The best time to learn microcontrollers

image
Admit how often you thought about mastering the basics of programming microcontrollers? Surely you have several ideas of potential projects in your head, but you never took to implement them. So: better time to start than now just can not find.

Why did I decide that this question is of interest to the Habr audience? It is enough to analyze the amount of adding some posts to favorites, and the conclusions suggest themselves.

On the other hand, there are a lot of programmers in my current environment, but there are almost no imbedders. When I talk with them about microcontrollers, I get the impression that many people have the same opinion about them 10 years ago.

Despite the fact that writing on asm for microcontrollers is easier than for x86 architecture, many are afraid of it and this serves as an obstacle for them on the way to embedded systems. Friends, in order to start the microcontroller now, it is not necessary, even, to thoroughly read the datasheets, not to mention to know its instructions. Of course, if this is your profession, then the level of immersion is much higher, but tell me how often you, regardless of what kind of professional you are, when trying to create products try not to violate the principle of encapsulation to the last and no no yes and look at the source libraries used? Now you will understand what I mean.

I vaguely remember those times when I did not program microcontrollers. I started writing on asm, not only because everyone did it, but also because there were practically no normal tools. I explain the popularity of 8-bit controllers from AVR by the fact that they created very easy-to-use libraries for them that allow you to create a new project, write a dozen lines of code and get a working program for yourself (the addresses of the peripheral device registers and interrupt vectors are kindly filled out by the library creators). I did not conduct research, this is from my personal memories - I am sure that more sensible libraries for other controllers existed even earlier, but then we did not know about it.

The first truly massive 32-bit microcontroller was created by the French STM office. It was at that moment that many lovers got acquainted with the architecture of Cortex-M3 and began to use it widely. I remember that at the same time 2 controllers fell into my hands - STM32F103 and LPC1768. I needed to make a prototype of the device on one of them as quickly as possible. Naturally, my choice fell on the first: the French released a peripheral library called the Standard Peripherals Library and all I had to do was launch FreeRTOS, connect the necessary peripherals and, based on the skeleton created, assemble the project already at the next level of abstraction, without being distracted anymore by working with registers. I also used the skeleton in the future, often bending and sticking the 32-bit Cortex to where the smallest ATtiny would have been enough, but most often the price would allow (and where it did not allow, or if lower power consumption was needed, it was possible to use cheap MSP430 and STM8, but this rarely happened).

Of course, I’m deceiving if I say that I didn’t have to fully learn the architecture of Cortex-M3 and smoke the F103 datasheet - of course, I had to be interested in the CMSIS library here tooand StdPeriph_Lib was more likely to prevent me than to help, but the speed of joining a new family was amazing for me, and even then I realized that the world of controllers is changing and is becoming both simpler and more complicated.

And so we gradually got to what I wanted to tell you about. The fact is that the popularity of all sorts of Arduino assemblies has long haunted the guys from Texas Instruments. They released MSP430-based launchers and sold them cheaper than cost and free shipping, they launched a community where they could upload their projects, they created Energia- fork Arduino, they released Stellaris launchers, and then renamed them Tiva C (although here we are talking about more global rebranding and adding some new functions, the essence has not changed). I want to talk about the latter.

You can buy the EK-TM4C123GXL launcher for $ 12.99 along with FedEx delivery (that is, you will receive it soon enough). The board is not replete with various electronics, such as the Discovery F4 (on board which are an accelerometer, sound sensor, DAC, a bunch of LEDs) - all that you will find on the Tiva C Launchpad is an RGB diode and 2 buttons, but its strength is not in additional devices on the board.

image

The power of the EK-TM4C123GXL in the libraries available for download from the TI website called TivaWare. The fact is that libraries now write everything for their controllers, but many of them, unfortunately, do not differ much in quality and are rather traditional examples than full-fledged libraries that are not ashamed to use in their projects (for the aforementioned LPC1768, NXP they wrote their library almost simultaneously with STM, but then it was not very different in quality). The library for Tiva C surprises with its standardization, documentation and variety.

A little later I will offer you to download TivaWare and, if you are not too lazy, then after installation you can watch the following directories:
  • Driverlib - here are directly the drivers for peripherals, such as adc, gpio and so on (including the header file with macros for calling functions from rom - more on that later)
  • Examples - well, here, of course, examples. They are divided into boards, peripherals and project. In the first, of course, projects for specific debug boards, in the second examples of the use of peripherals and in the third example of a clean project for various development environments (IAR, Keil, CCS) - the files are available under the BSD license.
  • Inc - various header files with macros, including the tm4c123gh6pm file, which is useful to us for creating a simple project
  • Docs - this is the hallmark of TI - simple and intuitive documentation. Inside there are several User Guide related to the components described here - DriverLib, Examples, Bootloader, IQmath and so on, as well as a user guide directly to the launcher we use.
  • Sensorlib - this is what really surprised me: there are drivers for various third-party sensors, such as sht21, lsm303d, MPU6050 and so on. I like to use the latter (this is such a MEMS assembly of accelerometers and gyroscopes on the same crystal) and before I always connected the lib torn from the Invensense examples, so I was very pleased with the neatly written sources from TI (besides, I found raw materials for work right there with quantions).
  • IQmath is a library of algorithms optimized for working with floating point numbers on Stellaris (Tiva C) devices.
  • Utils - frequently used utilities for working with the command line, serial port, scheduler and much more.
  • The remaining directories contain bootloader, raw third-party manufacturers (FreeRTOS, for example), a library for working with USB, drivers for Windows and so on.

In order to run any example on your launcher, just open the project from the examples / boards / ek-tm4c123gxl folder in your favorite IDE - everything is ready there (I use IAR, so I opened ek-tm4c123gxl.eww and it downloaded to me already configured workspace). But, you know, almost every microcontroller now has such tuned examples, and the real difficulties begin when we try to create something of our own.

Ok, let's give up not only examples but also a customized project skeleton - we will start everything from scratch (naturally using a file from libraries). Immediately disclaimer: I started working with the launcher only today, so I don’t know almost anything about it, nor about the source code with which I will work. This is the main leitmotif of the whole article - a person sees Tiva C for the first time and immediately tries to work with it.

I wanted to write some complicated and interesting application right away, but then I realized that it would take some time, and I had to publish the article urgently and so I decided to make a simple example, and then, if there are any, we will do something more interesting.

So, the first thing we need is to download and install the library (if you have not done so yet). In addition, you need to install an IDE and a flasher.

Where to download?
You can download it at this link . If the traffic allows - download the DK-TM4C123G Kit Full Installer - it contains the TivaWare library, documentation and IDE installers (about 3.5Gb).
The IDE and Flash Programmer are in the Tools folder.
If not, you can download separately TivaWare for Tiva C Series, LM Flash Programmer and IDE.


I will use the IAR as an IDE (hence the examples will be with it), however you can use any of the supported ones.

Who does not know, IAR has 2 options for free use - with a time limit and a code size limit. And, of course, there are other options if these 2 do not suit you (you yourself know which ones). I will not describe the procedure for installing and registering IAR - everything is simple there, but if you have any difficulties do not hesitate to ask questions in the comments.

So, first of all, create a new project. We’ll change some settings in the project properties.

Project settings
In fact, there are not so many settings. Open the project options and select the right stone. On the General Options -> Target tab.

image

In C / C ++ Compiler, on the Preprocessor tab, specify the path to the TivaWare folder. On the same tab, a little later we will add some constants.

image

In Debugger, select TI Stellaris.

image

More detailed settings (if necessary) can be seen in the examples (for example, another linker configuration file is used there, not the one proposed by IAR).


Now we need to set up the project structure. I suggest sticking to the structure suggested by TI (as in the examples), but with some differences.

In the folder (actually “in the group”, but the folders are somehow more familiar) Src we have our source codes. In the examples, the source files of library files are added there, but I believe that this will only confuse the project.

The Library folder contains files from DriverLib. TI adds the already compiled file there (in the case of IAR, this is the driverlib / ewarm / Exe / driverlib.a file), you can do the same, but I would suggest adding the sources instead, and only if necessary - it’s easier to remember where what located, and looking at the source code is useful. If you plan to add files from other libraries (Utils, for example) to the same folder, then it is better to create another hierarchy level.

I missed the examples, and I didn’t do it either, but if you write your header files, create an Inc. folder

The main thing is not to forget that these folders are just for the convenience of the user, they have nothing to do with the placement of files on the disk and in no way affect the compilation.

So, in the Src folder, create the main.c file

Add startup_ewarm.c to the Library folder - it is needed for proper initialization of the interrupt vector. You can take it from project_0 (this is in examples) of the project, for example.

Let's start our program with the main function. Since the RGB LED is connected to port F of our launcher, we blink it.

void main(void)
{
    volatile uint32_t ui32Counter;
    //Инициализация периферии
    while(1)
    {
        //Тут код для переключения пинов
        for(ui32Counter = 0; ui32Counter < 1000000; ui32Counter++)
        {
        }
        //Тут код для переключения пинов
        for(ui32Counter = 0; ui32Counter < 1000000; ui32Counter++)
        {
        }
    }
}


I think everything is clear: using types like uint32_t is a good habit, it helps to solve the ambiguity with the sizes of variables on different controllers (in addition, it complies with MISRA-C standards); volatile - tells the compiler that this variable should not be optimized (because we will use it for a generally useless operation). Next is the endless cycle (as students are taught, the program on microcontrollers should never end) and 2 counters for delays.
To compile this code, add to the beginning of the file.

#include 


Now we will proceed directly to the flashing LEDs.

Download the Tiva C Series TM4C123G LaunchPad Evaluation Kit User's Manual from the launcher page and read in the User Switches and RGB User LED section that the diode is connected to pins PF1 (red), PF2 (blue) and PF3 (green).
Now open SW-TM4C-DRL-UG (in the TivaWare docs folder) and look at the GPIO section. From the introduction, we understand that first the pins must be configured (of course, there are many configurations) to the output. Here we read that some of the most useful functions are GPIOPinRead () and GPIOPinWrite (). What they do is understandable, it remains to look at their description to clarify the list of parameters. Immediately we find that the function GPIOPinTypeGPIOOutput () is used to register pin output. So, we change the comments in our code to:

GPIOPinTypeGPIOOutput(GPIO_PORTF_BASE, GPIO_PIN_1|GPIO_PIN_2);  //для инициализации 
//и
GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_1, 0xFF);
GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_2, 0);
//и
GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_1, 0);
GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_2, 0xFF);


To turn on and off the diodes.

Naturally, do not forget to add the driverlib / gpio.c file to the Library folder, as well as

#include "driverlib/gpio.h" 

in the headlines.

In addition, during the compilation process, we notice that it is necessary to add 2 more header files:
#include  // Для поддержки типа bool, который используется в gpio
#include "inc/hw_memmap.h" //Для поддержки деклараций пинов.


Now our program looks like this:
#include 
#include 
#include "driverlib/gpio.h"
#include "inc/hw_memmap.h"
void main(void)
{
    volatile uint32_t ui32Counter;
    GPIOPinTypeGPIOOutput(GPIO_PORTF_BASE, GPIO_PIN_1);
    while(1)
    {
        GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_1, 0xFF);
        GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_2, 0);
        for(ui32Counter = 0; ui32Counter < 2000000; ui32Counter++)
        {
        }
        GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_1, 0);
        GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_2, 0xFF);
        for(ui32Counter = 0; ui32Counter < 2000000; ui32Counter++)
        {
        }
    }
}


And, if you compile and run it, you will be able to observe the alternating color change of the diode.

But blinking the LED is too easy for us. Let's go a little further and add I / O port support.
Actions are the same. We find which ports UART is connected to, read about the configuration of the module in UserGuide, configure it, use the functions to write to and read from uart.

My uart initialization function turned out to be similar to the function from the example, but with one interesting difference. Here is the initialization from the example:

void ConfigureUART(void)
{
    //
    // Enable the GPIO Peripheral used by the UART.
    //
    ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);
    //
    // Enable UART0
    //
    ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_UART0);
    //
    // Configure GPIO Pins for UART mode.
    //
    ROM_GPIOPinConfigure(GPIO_PA0_U0RX);
    ROM_GPIOPinConfigure(GPIO_PA1_U0TX);
    ROM_GPIOPinTypeUART(GPIO_PORTA_BASE, GPIO_PIN_0 | GPIO_PIN_1);
    //
    // Use the internal 16MHz oscillator as the UART clock source.
    //
    UARTClockSourceSet(UART0_BASE, UART_CLOCK_PIOSC);
    //
    // Initialize the UART for console I/O.
    //
    UARTStdioConfig(0, 115200, 16000000);
}


As you can see, strange functions with the ROM_ prefix are used here - these are special functions that are already stored in the ROM of the launcher microcontroller. You can read about them in the same UserGuide for DRL. They were created in order to reduce the size of the code in Flash memory. Whether you need it or not - you decide, I liked the idea (since I still use the Peripheral Driver Library). By the way, if you don’t know whether the code will be used on the device with pieces of the library in ROM or not, you can use Mapped ROM Calls. Then the code from ROM will be used if there is one and compiled if it is not.

To work with ROM, you need to configure several constants: in the project options, in C / C ++ Compiler, on the Preprocessor tab, add the constant TARGET_IS_BLIZZARD_RB1 to the Defined Symbols field. Add PART_TM4C123GH6PM and ewarm right there - they are needed to successfully compile library files.

Screen
image


In addition, you need to add the missing files to the project tree:

image

So, all that remains for us is to output something to the port (you can use any terminal emulator for reading. For example, for Windows I used Real Term). Then, I propose to read the letter from the port, check whether it belongs to one of the colors (r, g, b) and change the state of the corresponding pin.

You already have a function for initializing UART. We change the initialization of the ports to add a third pin (earlier we configured only 2 to output). You can output a string to the terminal using the UARTprintf () function; from the utils / uartstdio.c library (naturally, you need to add this to the project and include the header file).

We read the character with the UARTCharGet () function. It enters the loop until a symbol arrives in Wart. After that, we perform actions on the pins and return to the beginning of the cycle.

#include 
#include 
#include "inc/hw_memmap.h"
#include "inc/hw_types.h"
#include "driverlib/gpio.h"
#include "driverlib/rom.h"
#include "driverlib/sysctl.h"
#include "driverlib/uart.h"
#include "driverlib/pin_map.h"
#include "utils/uartstdio.h"
void ConfigureUART(void)
{
    ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);
    ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_UART0);
    ROM_GPIOPinConfigure(GPIO_PA0_U0RX);
    ROM_GPIOPinConfigure(GPIO_PA1_U0TX);
    ROM_GPIOPinTypeUART(GPIO_PORTA_BASE, GPIO_PIN_0 | GPIO_PIN_1);
    UARTClockSourceSet(UART0_BASE, UART_CLOCK_PIOSC);
    UARTStdioConfig(0, 115200, 16000000);
}
void main(void)
{
    volatile uint32_t ui32Loop;
    uint32_t ui32Color;
    uint8_t ui8Red = 0xFF;
    uint8_t ui8Green = 0xFF;
    uint8_t ui8Blue = 0xFF;
    GPIOPinTypeGPIOOutput(GPIO_PORTF_BASE, GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3);
    ConfigureUART();
    UARTprintf("Hello HabraHabr!\n");
    while (1) 
    {
    UARTprintf("Please, enter color(r,g,b) \n");
    ui32Color = UARTCharGet(UART0_BASE);
    switch (ui32Color)
        {
        case 'r': 
            GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_1, ui8Red);
            ui8Red = ~ui8Red;
            break;
        case 'b': 
            GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_2, ui8Blue);
            ui8Blue = ~ui8Blue;
            break;
        case 'g': 
            GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_3, ui8Green);
            ui8Green = ~ui8Green;
            break;
        default:
            UARTprintf("Incorrect color! \n");
            break;
        }
    }
}


In TivaWare I found an interesting lib - utils / cmdline. It allows you to create and process commands entered from the command line. I wanted to make an interesting project using it and some other interesting libraries, but time is running out, so I can write about it later if there is interest (as well as interruptions that are not even mentioned here about FreeRTOS).
Well, now about why I wrote several times about the fact that time is running out and why, of all the favorable times for starting controller studies, the most favorable is now: on January 22, Embedded Systems - Shape The World courses will start on edX .



Registration is free, but if you want to receive a certificate, you must pay a fee (at least $ 50). Personally, I paid $ 50 - not because of the certificate, but simply out of love for such courses and in their support.

To participate, you need to buy a Tiva C launcher and various loose powder. You can buy the latter on any radio market, but you have to hurry up with the launcher: TI is usually sent via FedEx, but this can take up to 10 days, while there is a week left before the start of the course.

But you shouldn’t worry: I don’t think that in the first lesson you will immediately need to work with hardware, maybe you can simulate your program.

So, a few conclusions. Using such libraries is a double-edged sword. On the one hand, it simplifies development, lowers the entry threshold, and on the other hand, creates an abstraction level that complicates the understanding of the basics (there is not a single reference to the datasheet in the whole article, and this is wrong: you must always look at the datasheet and this is a prerequisite in a professional). But such libraries, unlike arduino (by the way, Energia supports the described launcher), there is one advantage: they do not create a false understanding of reality. If you use the library, you understand that the abstraction is a very real device and the parallels between functions and real registers are not at all difficult to trace.

I hope that this material will encourage you to buy and study (albeit so superficial) this wonderful device. If you have ideas for projects that you could implement on the TM4C123G, but there are difficulties in the implementation, do not hesitate to write about it in the comments: we will sort it out together.

Also popular now: