Those of you who wish to learn about ARM microcontrollers may consider a nice little board from Mikroelektronika. The MINI-M4 for STM32 is a small board implemented as a DIP40 and features a STM32F415RG microcontroller http://www.mikroe.com/mini/stm32/ and at $29 US it is very affordable. The mikroC compiler for ARM will set you back $299, however. I recommend the USB Dongle License that can be easily moved from one computer to another. However, you can learn a lot about this architecture with just the board and the Examples provided in this tutorial. The only other piece of equipment required is a USB cable with a Type-A connector on one end and a Mini-B connector on the other end which also supplies power to the board. The microcontroller comes with a bootloader already programmed into the chip so that a programmer is not required.
The board contains very few auxiliary components. There are 2 programmable LEDs, one yellow and one red. The green LED is connected to the 3.3 volt power rail. A 16 MHz crystal supplies the clock to the microcontroller that can be boosted by the PLL up to 168 MHz. A 32.768 KHz crystal supplies the oscillator for the Real Time Clock (RTC). Due to the lack of space, the battery backup pin for the RTC is simply wired to the 3.3 volt rail. Which means that the RTC looses its time setting when power is removed from the board. There is a Reset pushbutton and 36 I/O pins neatly brought out to the edge of the board. Most importantly, the board includes a USB socket already wired to the appropriate pins of the microcontroller. This interface will be used for program load and for communicating with the microcontroller. On the website mentioned above, you will find the MINI-M4 for STM32 User Manual which includes the schematic of the board. The manual also walks you through the process of loading code into the microcontroller using mikroBootloader USB HID.exe.
An incredible number of peripherals are fully integrated inside the microcontroller chip. These are accessible through memory mapped registers. It takes a little bit of programming to make use of these peripherals. It’s best to start with the simplest one and keep adding software modules as the need arises. If you have the compiler, Mikroelektronika has supplied a Library of useful function calls that can make life easier for beginners. However, I like to use as little as possible of those libraries and program the control registers directly. That way, I can be more intimate with the hardware and learn what each bit in a register does. I also dislike that the code is not published and I don’t know exactly what it does. Reading through the Reference Manual and the Datasheet is essential. Don’t be dismayed by the fact that the Reference Manual for the microcontroller alone has 1422 pages.
On the same website URL mentioned above, you will find a zip file with the bootloader already programmed in the microcontroller chip and also the application mikroBootloader USB HID.exe. This bootloader software will be used to program the user area of the microcontroller. After loading some code into the microcontroller flash memory, you will need a software application to communicate with the board. Mikroelektronika includes a HID Terminal program with the microC PRO for ARM compiler ( http://www.mikroe.com/arm/compilers/ ). Download the compiler to get a feel for the IDE and the HID Terminal program should be installed with it. Otherwise, you can use a small program I have written for the same purpose called UsbUtility.exe.
If you unzip the Example1.zip file, you will find a bunch of files. The only files that are pertinent are the .c and .h files. The rest are created by the compiler. The USB_Driver.c file uses the Mikroelektronika library that implements USB communications and puts a wrapper around it. For convenience to the user, outgoing messages on the USB interface can be queued for sending by placing a pointer to the message into a recirculating buffer. This is done automatically by a call to USB_PutQueue(char *msg). For example, if you have some text you want to send to the PC application, you just call the function directly: USB_PutQueue(“Hello world”); If you have some variables that require formatting, you have to create a buffer in RAM using the sprintf function. For example: sprintf(MyBuffer,”Variable value: %d”,MyVariable); followed by USB_PutQueue(MyBuffer); You will get the hang of it once you read some of the code provided. I have included a module that defines a bunch of buffers that can be used for this purpose. Define a variable char *BufNum; and in your code call BufNum = GetBuffer(); This will get you a pointer to the next free buffer and you can use it for all sorts of things. You will see code in many places like this:
BufNum = GetBuffer(); // Get a free buffer
Example1 doesn’t do very much. If you load it into the microcontroller, you can use HID Terminal or UsbUtiity to send an “a” command to it and it should respond with “Command a received”.
Example2 adds a file called LED.c. In USB_Driver.c we now add 4 more commands:
b – sets the yellow LED
c – clears the yellow LED
d – sets the red LED
e – clears the red LED
Still very primitive but handy to have as a diagnostic tool. If my code gets hung up for some reason, I surround the suspect code with LED_SetRed(); and LED_Clr_Red(); and if my code hangs between these two lines (the red LED will be shining bright), I have an approximate idea where the problem is.
This example adds a file for the Real Time Clock. USB_Driver.c now includes 4 more commands:
f – sets the RTC to the date and time which follows the command. For example – f,14,04,01,02,18,44,36 sets the date to Year=14, Day of week= 4 (Thursday), Month=01 (January), Day=02, Hour=18, minute=44, and Second=36
g – displays the current RTC date and time. You should see the seconds increasing as you repeatedly send this command.
h – writes some data to RTC backup registers. If there was a battery attached to the microcontroller Vbat pin, data in these registers would be preserved even when main power was removed.
i – displays the Initialization and Status Register.
This example adds support for the 2 DACs that are onboard. DAC1 in particular will be used to generate a Sine wave at 60 Hz. To do that I will use a Sine lookup table and assign 1000 data points to one cycle of the Sine wave. In order to provide a time base for DAC1 I have to introduce some timer resources. These will be in Timers.c file. Timer6 will drive DAC1 loading. Upon timeout of timer6, it will generate an interrupt where the next DAC1 value will be obtained from the Sine table. Before it is loaded into the DAC, it will be multiplied by an amplitude value (0 to 255) and divided by 255. This has an attenuating effect on the value in the Sine table. When the amplitude value is 255 (at maximum) then the attenuating value is 1 (255/255) and the DAC is loaded with the value from the Sine table. When the amplitude is 127 (mid point) the attenuating value will be 127/255 = 0.498 or approximately ½. When the amplitude is 0 then the output should be a flat line. The output of DAC1 is available on I/O pin PA4 for scoping.
The Sine table only holds ¼ of the data points since the 4 quadrants of a Sine wave can reuse the data. The address where the data is fetched from the Sine table starts at 0 and is incremented after each interrupt. The address is checked after each access and when the code detects that the address is at 250 (251st element of the table), the direction is switched so that each subsequent interrupt decrements the address. The address then decrements until the code detects address 0. At that point the address is incremented again and so on.
A simple calculation will show that 60 Hz and 1000 data points results in 60,000 interrupts per second with a multiply and divide for each one. This a pretty high rate and I wouldn’t use it like this in an application but I wanted to see if it would keep up. I have included a spreadsheet that can calculate a smaller Sine table.
There are 3 more commands in USB_Driver.c. They are:
j – initialize DAC1 and Timer6
k – raise the amplitude of the Sine wave
l – lower the amplitude of the Sine wave
These 4 examples only scratch the surface of what is possible with this little board. I may publish additional drivers for some of the other peripherals that are on-board. They could be:
General Purpose Input Output (GPIO)
Direct Memory Access (DMA)
Analog to Digital Converter (ADC)
Many more Timers (TIM1 to TIM14)
Independent Watchdog Timer (IWDG)
Random Number Generator (RNG)
Controller Area Network (CAN)
Inter-integrated Circuit (I2C)
Universal Synchronous Asynchronous Receiver Transmitter (USART)
Serial Peripheral Interface (SPI)
It all depends on the response I get for this article.
Examples for STM32
Examples to get you started with MikroElektronika MINI-M4 for STM32 development board.