Saturday 29 July 2017

Wirtting code in C++ for small MCUs

When you think about C++ what's in your mind? I thought about those fancy complicated powerful GUI programs on PC like you until one day when I was looking at the IAR MSP430 IDE and realized it has been suported C++ for a long time.

If you look around you'll find that many compilers for MCU has the ability to support C++, for example the IAR, Keil, and the GCC. Wild ranges of MCUs can be developed in C++, like TI's MSP430, Atmel's AVR, ARM series from any manufacture, and even the MCS-51 if you choose the right compiler.

First of all, C++ doesn't mean big code size. Programs with GUI on PC becomes large because they use a lot of libraries, C++ itself is as efficient as C, if not better than. I had done a commercial project with MSP430F2312, which has only 8KB of FLASH. I wrote the entire code in C++ and it turns out to be one of the most efficient code I have ever done. Until now I still couldn't believe I had packed so many functionalities in such a small chip.

C++ has 3 major benefits over C, inheritance, polymorphism, and templates. Unfortunately, many C++ compilers for MCUs do not support templates, but polymorphism alone is a thing good enough for you to consider using it. Imagining you wrote a software I2C interface, and you can easily change the configuration to assign which I/O port to assign it, or even changing the mapping I/O on the fly!

Here I'll give an easy example with STM32F103 using Keil's SDK. The code is very simple, it just blink a LED on an I/O pin. Not using any RTOS, not using any timer, interrupt, or any library.

First there is the plain C version:
#include <stm32f10x.h>

#define LED1        0x2000      // PC13

void RCC_Init(void)
{
    RCC->APB2ENR |= RCC_APB2ENR_IOPCEN;
}

void blink()
{
    unsigned long i;
    while(1)
    {
        GPIOC->ODR ^= LED1;
        for (i=0; i<0x400000; i++);
    }
}    

int main(void)
{
    RCC_Init();
    GPIOC->CRH = 0x44244444;
    blink();
    return 0;
}

The C++ version is a little bit longer than the C code, because there need to be the definitions of the class:
file gpio.h:
#ifndef GPIO_H
#define GPIO_H

class GPIO
{
    public:
    enum Mode
    {
        FLOAT_INPUT = 0x04,
        PUSH_PULL_50M = 0x03,
        PUSH_PULL_2M = 0x02,
        PUSH_PULL_10M = 0x01,
        ANALOG_INPUT = 0x00,
        ALT_PUSH_PULL_50M = 0x0B,
        ALT_PUSH_PULL_2M = 0x0A,
        ALT_PUSH_PULL_10M = 0x09,
        PULL_UP_DOWN_INPUT = 0x08
    };
    GPIO() {}
    virtual ~GPIO() {}
    virtual void Set1() = 0;
    virtual void Set0() = 0;
    virtual void Toggle() = 0;
};

#endif

File main.cpp:
#include "stm32f10x.h"
#include "gpio.h"

class PortCPin : public GPIO
{
    private:
    uint16_t pin;
    public:
    PortCPin( unsigned char pin_number, GPIO::Mode mode = FLOAT_INPUT)
    {
        pin = (uint16_t)1<<pin_number;
        if (pin_number >= 8)
        {
            pin_number -= 8;
            GPIOC->CRH = (GPIOC->CRH & (~((uint32_t)0x0F << (pin_number*4)))) | ((uint32_t)mode << (pin_number*4));
        }
        else
        {
            GPIOC->CRL = (GPIOC->CRL & (~((uint32_t)0x0F << (pin_number*4)))) | ((uint32_t)mode << (pin_number*4));
        }
    }
    ~PortCPin()
    {
    }
    void Set1()
    {
        GPIOC->BSRR = pin;
    }
    void Set0()
    {
        GPIOC->BRR = pin;
    }
    void Toggle()
    {
        GPIOC->ODR ^= pin;
    }
};

void RCC_Init(void)
{
    RCC->APB2ENR |= RCC_APB2ENR_IOPCEN;
}

void blink(GPIO& pin)
{
    while(1)
    {
        pin.Toggle();
        for (unsigned long i=0; i<0x400000; ++i);
    }
}

int main()
{
    RCC_Init();
    PortCPin    PC13(13, GPIO::PUSH_PULL_2M);
    blink(PC13);
    return 0;
}

The idea behind the code is, the GPIO is a base class of all the independent I/O pins, it provides a common interface for all the I/O operations (here I only included Set1(), Set0(), Toggle() 3 operations, there should be more like read() change_mode() etc). A specific I/O pin should be an instance of a derived class of GPIO. All the functions in the code should use these common interface to operate I/Os, then by power of polymorphism, once these functions are written, they can be used on any I/O pins.

One thing should be of caution is, the definition of PC13 must be behind the RCC_Init() code, it can not be declared as a global, because then the constructor will be executed before the main() then before the RCC is initialized.

If you are curious about the code efficiency, the plain C code is 744 bytes long (mainly because of the system initialization code not listed here), while the C++ version is 788 bytes.

Saturday 22 July 2017

Connect ESP8266 in Ubuntu

I received my ESP-launcher board a few days ago, 2 ESP8266 module and a ESP32 dev kit have also been ordered but I decide to leave them for later use, would stick to the launcher board at this stage.

The SDK for ESP8266 is based on linux, the user manual suggest you to install a virtual machine in Windows and do your job under windows. I don't know why they do this, probably because their download tool is for Windows only ? For me that doesn't make sense. I won't waste my hard drive space to install a virtual machine while I already have a Ubuntu installed as a dual boot.

The simplest way to play with a ESP8266 is to use the AT command, you just need a terminal and a USB port. There is already a USB-UART chip FT-232 on the ESP-launcher board, and the good news is Ubuntu has built-in driver for it.


You don't need to turn on the launcher to check the FT-232's status. Connect the USB cable and go to the terminal in Ubuntu, use this command to check if the USB-UART chip has been recognized:
lsusb
See the second one from the last : Future Technology Devives International, Ltd FT232 USB-Serial (UART) IC

When it's correctly driven, you will get a new TTY device and that is the AT terminal to use. Use "ls /dev" command to check the devices and search for "ttyUSBn", on my computer, it's ttyUSB0.





Unfortunately, Ubuntu doesn't come with a proper terminal software to communicate via these serial ports, you have to download the "minicom" software. It's easy just use "sudo apt-get install minicom" form the terminal.

run minicom in the terminal, you have to use "sudo minicom" otherwise it will not run. For the first time, use "sudo minicom -s" to enter setup and set the serial port to the USB, be sure to set it to 115200, 8N1, like this:





When everything is set, turn the ESP-Launcher on, ta-da! you see the "ready!" from the ESP8266!

Now let's try some AT commands: AT+GMR displays the version information the ESP8266 chip, and AT+CWLAP displays the wifi hotspots arround:

Remember, you have to use Ctrl-m + Ctrl-j at the end of AT command, or use
ENTRE+Ctrl-j , seems the ESP8266 needs a Windows like end-of-line mark.

Connect to the WiFi :
That's it! You can't do much with just a terminal and ESP8266, to have more fun you have to do some programming, either program the ESP8266 itself or connect an external MCU, I'll try it later and write a post then.

Thursday 13 July 2017

USB HID demo with STM32 and emWin and FreeRTOS





This is a demonstration of the HID communication. The computer program reads the LED status via the USB and shows it on screen with 3 big indicators. In the mean while the scroll bar on the computer is used to control the flashing speed of the LED on board.



The board is using a STM32F103 MCU which has a USB 2.0 device full speed port. I didn't use the ST peripheral library or the ST's USB stack, all the USB code was built from scratch and is completely interrupt driven. So the code is compact and efficient, the USB core code is less than 400 lines.



FreeRTOS is used as the operating system to provide support of the GUI and multi-tasking. 3 software timers were used to control the LED flashing speed, the GUI refreshing, and the USB idle time. The benefit of using the software timer of the RTOS is there is no additional hardware and software cost to the system.



The whole tool chain I used is free except the Keil compiler. It is possible to use a free GNU compiler, anyway I bought the Keil several years ago and I can't see any reason not using it by now. The emWin is free to use if you are using the STM32 chips thanks for a deal made between ST and Segger. FreeRTOS is free of charge, even for commercial purpose. The compiler for the Windows program is Embarcadero's C++ builder, which is free to build Win32 applications now, for both personal and commercial use.

I would like to provide the source codes for this demo, but haven't found a way to upload files in Blogger, which is this site based on, I'll update this blog when the download is available. Before that, maybe you can contact me to send you an email.