STM32 Discovery Tutorials
Using the STM32 Discovery with Open Source Software
Tuesday, 28 September 2010
BOOT0
Just a quickie. Following a discussion on the ST Forum, I've decided to change the 220R for a 270R, just to bring the voltage down a little. It works fine on my Discovery board with 220R, but maybe just to be on the safe side ......
Saturday, 25 September 2010
Inside blinky.c
A short post explaining some of the things in blinky.c. This can be read in conjunction with the reference guide RM0041 and the Hitex document "Intro to Cortex-M3 programming". There is a lot to take in, this isn't a little 16C84 Processor.
After this I will step back a little and provide some simpler tutorials and exercises, so don't worry if you find this a bit incomprehensible.
I wanted the tutorials to be quite close to the metal. ST produce a library which abstracts a lot of the work. While this helps development, there are two disadvantages - one, the routines aren't particularly quick, but mainly if you are learning as I am you don't learn how the MCU works, just how the library works.
My personal POV is that if you know the hardware then understanding the library is easy as pie, but understanding the library gives you a much poorer handle on the hardware.
This file is a combination of two ST header files, type and map. It provides a set of 8, 16 and 32 bit types, along with References to the registers (which map to the register description in the documentation) - so for example "GPIOA->CRL" refers to register CRL in GPIOA
The ARM has a stack which works its way down through memory. This constant is the top of RAM - so data works up, and the stack works down. It is possible the two might meet in the middle, in which case .... all bets off.
This is actually wrong - this array is much bigger than this. It's an array of addresses used to set up the STM32 - in this case, the start address of the program, the initial value of the stack pointer, and the addresses of routines to handle Non Maskable Interrupts and Hardware Errors. There's actually many more of these vectors which we will see when we come to interrupts. Don't worry about this one for a while.
RCC->APB2ENR |= 0x10 | 0x04;
This completely threw me when I couldn't get Blinky to work. Unlike most other MCUs, you actually need to turn on the peripherals you are using, they just play dead otherwise. This command sets (using logical OR) bit 4 and bit 2 of APB2ENR - which enables GPIOA (bit 2) and GPIOC (bit 4) respectively. The binary constant 0x10|0x04 is equivalent to 10100 in binary.
Each GPIO port is 16 bits wide. CRH and CRL go together to make one big 64 bit control register for each port - each port having four control bits. Pins 0-7 are stored in CRL, Pins 8-15 in CRH.
In binary, what it is doing is setting Port8 and Port9 's control value to 0001 and Port0's to 0100 - these are the standard input and output values. There are all sorts of other things you can do - pull high, pull low, open collector circuitry, interrupt on change.
This reads the level on the button - GPIOA->IDR is the input register for GPIOA, and it is masked with 0000000000000001 binary to mask out the value on the button. The reason it is "checked equal to zero" is the button is normally logic '1' when not pressed - so this expression returns true when the button is pressed.
The STM32 has some nice facilities for bit work. Bits can be addressed individually - normally to turn a bit on, you would or a value into the Output Register. The STM32 allows you to address bits individually with the BSRR.
Each BSRR is 32 bits wide. The bottom half (0-15) turn bits on, and the top half (16-31) turn them off.
So to set PC8 to 'on', all you have to do is to write 1<<8 (or 00000001 00000000) into BSRR and it does the work for you. Similarly, writing 1 << 24 - the same thing in the 'top half' turns the bit off.
The STM32 also allows you to write to individual bits in data memory in the same way.
asm("nop");
The C compiler is quite smart. It is quite capable of looking at the delay() function and concluding that it actually doesn't do anything at all, and replacing it with a subroutine return. The asm("nop") assembles a no-operation in the middle of that, but at compile time the compiler doesn't know it's a nop - just that it is inline assembly - so it is unable to optimise away the delay loop because it might do something. (You can see this working if you remove this line, compile it and look at blinky.lst)
Of course, you shouldn't do delays this way - the STM32 has timers for this sort of thing.
Postscript : in other news, I've added a 5v -> 3.3v PSU to the veroboard (see earlier). This has the nice consequence that all the connections (5v, GND, PA10, PA9) are on the right side of the STM32 Discovery board which means the communications board can just be put over to the right - I'll usually wire things to the left side :)
This modification is optional, you can plug the serial chip into 3v3 directly - but it provides a little protection for the Serial Port circuit and allows you (for example) to put it in a box with a 9v battery if you so wish - reducing the connecting wires to PA9, PA10 and GND.
After this I will step back a little and provide some simpler tutorials and exercises, so don't worry if you find this a bit incomprehensible.
#include "stm32f10x.h"
I wanted the tutorials to be quite close to the metal. ST produce a library which abstracts a lot of the work. While this helps development, there are two disadvantages - one, the routines aren't particularly quick, but mainly if you are learning as I am you don't learn how the MCU works, just how the library works.
My personal POV is that if you know the hardware then understanding the library is easy as pie, but understanding the library gives you a much poorer handle on the hardware.
This file is a combination of two ST header files, type and map. It provides a set of 8, 16 and 32 bit types, along with References to the registers (which map to the register description in the documentation) - so for example "GPIOA->CRL" refers to register CRL in GPIOA
#define STACK_TOP 0x20002000
The ARM has a stack which works its way down through memory. This constant is the top of RAM - so data works up, and the stack works down. It is possible the two might meet in the middle, in which case .... all bets off.
unsigned int * myvectors[4] = { .. }
This is actually wrong - this array is much bigger than this. It's an array of addresses used to set up the STM32 - in this case, the start address of the program, the initial value of the stack pointer, and the addresses of routines to handle Non Maskable Interrupts and Hardware Errors. There's actually many more of these vectors which we will see when we come to interrupts. Don't worry about this one for a while.
RCC->APB2ENR |= 0x10 | 0x04;
This completely threw me when I couldn't get Blinky to work. Unlike most other MCUs, you actually need to turn on the peripherals you are using, they just play dead otherwise. This command sets (using logical OR) bit 4 and bit 2 of APB2ENR - which enables GPIOA (bit 2) and GPIOC (bit 4) respectively. The binary constant 0x10|0x04 is equivalent to 10100 in binary.
GPIOC->CRH = 0x11;
GPIOA->CRL = 0x04;
These two are very similar. The first sets pins 8 and 9 of GPIOC (the LEDs) to outputs, the second sets pin 0 of GPIOA (the button) to inputs.GPIOA->CRL = 0x04;
Each GPIO port is 16 bits wide. CRH and CRL go together to make one big 64 bit control register for each port - each port having four control bits. Pins 0-7 are stored in CRL, Pins 8-15 in CRH.
In binary, what it is doing is setting Port8 and Port9 's control value to 0001 and Port0's to 0100 - these are the standard input and output values. There are all sorts of other things you can do - pull high, pull low, open collector circuitry, interrupt on change.
button = ((GPIOA->IDR & 0x1) == 0)
This reads the level on the button - GPIOA->IDR is the input register for GPIOA, and it is masked with 0000000000000001 binary to mask out the value on the button. The reason it is "checked equal to zero" is the button is normally logic '1' when not pressed - so this expression returns true when the button is pressed.
GPIOC->BSRR = 1<<8 ;
GPIOC->BSRR = 1<<24;
GPIOC->BSRR = 1<<24;
The STM32 has some nice facilities for bit work. Bits can be addressed individually - normally to turn a bit on, you would or a value into the Output Register. The STM32 allows you to address bits individually with the BSRR.
Each BSRR is 32 bits wide. The bottom half (0-15) turn bits on, and the top half (16-31) turn them off.
So to set PC8 to 'on', all you have to do is to write 1<<8 (or 00000001 00000000) into BSRR and it does the work for you. Similarly, writing 1 << 24 - the same thing in the 'top half' turns the bit off.
The STM32 also allows you to write to individual bits in data memory in the same way.
The C compiler is quite smart. It is quite capable of looking at the delay() function and concluding that it actually doesn't do anything at all, and replacing it with a subroutine return. The asm("nop") assembles a no-operation in the middle of that, but at compile time the compiler doesn't know it's a nop - just that it is inline assembly - so it is unable to optimise away the delay loop because it might do something. (You can see this working if you remove this line, compile it and look at blinky.lst)
Of course, you shouldn't do delays this way - the STM32 has timers for this sort of thing.
Postscript : in other news, I've added a 5v -> 3.3v PSU to the veroboard (see earlier). This has the nice consequence that all the connections (5v, GND, PA10, PA9) are on the right side of the STM32 Discovery board which means the communications board can just be put over to the right - I'll usually wire things to the left side :)
This modification is optional, you can plug the serial chip into 3v3 directly - but it provides a little protection for the Serial Port circuit and allows you (for example) to put it in a box with a 9v battery if you so wish - reducing the connecting wires to PA9, PA10 and GND.
Friday, 24 September 2010
Blinky II
After having installed the GNU ARM Compiler, you need to change your path so it can access the executables. You can do this via :
for example (this assumes the executables are in /aux/arm-gcc/gin - it will vary depending on where you built them)
You now need to download the very simple sources for Blinky 2 at http://www.robsons.org.uk/blinky.zip - this is a very simple file which flashes the two LEDs and varying rates, stopping one flashing whenever the button is pressed.
To build it, just type
and to run it, reset the STM32 Discovery, type
which instructs the flash loader to write the binary, verify it, and run it - using /dev/ttyS0 as the interface. You should have flashing LEDs.
The link (mine) is still not 100% reliable. It seems to work best if you press the reset and immediately run the command.
In my next post I will take a look at what blinky.c is actually doing.
export PATH=$PATH:/aux/arm-gcc/bin
for example (this assumes the executables are in /aux/arm-gcc/gin - it will vary depending on where you built them)
You now need to download the very simple sources for Blinky 2 at http://www.robsons.org.uk/blinky.zip - this is a very simple file which flashes the two LEDs and varying rates, stopping one flashing whenever the button is pressed.
To build it, just type
make
and to run it, reset the STM32 Discovery, type
stm32flash -w blinky.bin -v /dev/ttyS0 -g 0x0
which instructs the flash loader to write the binary, verify it, and run it - using /dev/ttyS0 as the interface. You should have flashing LEDs.
The link (mine) is still not 100% reliable. It seems to work best if you press the reset and immediately run the command.
In my next post I will take a look at what blinky.c is actually doing.
Wednesday, 22 September 2010
Installing the GNU ARM Toolkit.
The instructions that seem to work for me best are the ones here http://lejos-osek.sourceforge.net/installation_linux.htm . You only need to install section 1 - install the Ubuntu components suggested, copy the script to a directory, run it and wait quite a while.
I've put the serial port interface on a bit of Veroboard. I've left half the board empty because I want to put a 3.3v regulator on there as well, and drive it from the 5v line.
In the next post, I will explain how to build and run "blinky" version 2.
I want to learn how the Microcontroller actually works. Because of this, I will keep things fairly close to the metal, rather than use the STM32 Peripheral Library.
I've put the serial port interface on a bit of Veroboard. I've left half the board empty because I want to put a 3.3v regulator on there as well, and drive it from the 5v line.
The Current State of the Development System |
I want to learn how the Microcontroller actually works. Because of this, I will keep things fairly close to the metal, rather than use the STM32 Peripheral Library.
Tuesday, 21 September 2010
Blinky for STM32VLDiscovery
As the title suggests, I have a new Blinky Application, all written, compiled and uploaded using open source software. This flashes the blue LED and the green LED at half the speed.
I will put up the full procedure on how to do this tomorrow, as I am a little short of time and it involves building the toolchain and so on.
Meanwhile, here is a video showing the program being uploaded to the board and running. Not the most exciting video ever :)
This took longer than expected partly, well mostly because I didn't realise you had to actually turn the MCU peripheral components on - unlike other MCUs I've worked with it doesn't start in a default state. The code I'd written for the LEDs was fine, but the port had never been enabled so it didn't work :(
I've also moved the serial converter out of the way - I'm going to move it to stripboard tomorrow I think :)
I will put up the full procedure on how to do this tomorrow, as I am a little short of time and it involves building the toolchain and so on.
Meanwhile, here is a video showing the program being uploaded to the board and running. Not the most exciting video ever :)
This took longer than expected partly, well mostly because I didn't realise you had to actually turn the MCU peripheral components on - unlike other MCUs I've worked with it doesn't start in a default state. The code I'd written for the LEDs was fine, but the port had never been enabled so it didn't work :(
I've also moved the serial converter out of the way - I'm going to move it to stripboard tomorrow I think :)
Sunday, 19 September 2010
Running the Discovery Demo
As a quick add on to the previous post, you can also run the built-in Discovery Demo (the flashing green light that changes rate when you press the User button).
stm32flash -g 0x0 /dev/ttyS0
.... and the green light will be happily flashing away :)
stm32flash -g 0x0 /dev/ttyS0
.... and the green light will be happily flashing away :)
A better program for the bootloader
As mentioned in the last post, I found an alternative program for the Python script for the bootloader written by geoff at spacevs.com. This seems to be much better (it can handle .hex files for example) and also more reliable. However, it is Linux only (at the moment), so anyone doing this on Windows will have to persevere with the Python script.
(It's possible the reason it's more reliable is I have rebuilt the MAX3232 serial interface to use shorter leads and be nearer the STM32VLDiscovery)
The web page is at http://code.google.com/p/stm32flash/
To build it, find a working directory and type :
You will need subversion and build-essential installed for this to work in Ubuntu - these commands install the stm32flash program in /usr/local/bin
You can then run the program (as before) by pressing reset and entering
which port you use depends on the way your system is set up, ttyS0 is the normal main serial port and will be the most common one. Hopefully this will display
You may get :
stm32flash - http://stm32flash.googlecode.com/
Serial Config: 57600 8E1
Failed to get init ACK from device
in which case press the STM32 reset switch and try again - if that doesn't work check the loop back tests.
(It's possible the reason it's more reliable is I have rebuilt the MAX3232 serial interface to use shorter leads and be nearer the STM32VLDiscovery)
The web page is at http://code.google.com/p/stm32flash/
To build it, find a working directory and type :
svn checkout http://stm32flash.googlecode.com/svn/trunk/ stm32flash-read-only
cd stm32-flash-read-only
sudo make install
You will need subversion and build-essential installed for this to work in Ubuntu - these commands install the stm32flash program in /usr/local/bin
You can then run the program (as before) by pressing reset and entering
stm32flash /dev/ttyS0
which port you use depends on the way your system is set up, ttyS0 is the normal main serial port and will be the most common one. Hopefully this will display
stm32flash - http://stm32flash.googlecode.com/
Serial Config: 57600 8E1
Version : 0x22
Option 1 : 0x00
Option 2 : 0x00
Device ID : 0x0420 (Medium-density VL)
RAM : 8KiB (512b reserved by bootloader)
Flash : 128KiB (sector size: 4x1024)
Option RAM : 15b
System RAM : 2KiB
Resetting device... done.
Serial Config: 57600 8E1
Version : 0x22
Option 1 : 0x00
Option 2 : 0x00
Device ID : 0x0420 (Medium-density VL)
RAM : 8KiB (512b reserved by bootloader)
Flash : 128KiB (sector size: 4x1024)
Option RAM : 15b
System RAM : 2KiB
Resetting device... done.
You may get :
stm32flash - http://stm32flash.googlecode.com/
Serial Config: 57600 8E1
Failed to get init ACK from device
in which case press the STM32 reset switch and try again - if that doesn't work check the loop back tests.
Subscribe to:
Posts (Atom)