Tuesday, 28 September 2010


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.

#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.

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;    

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 :

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


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.
The Current State of the Development System
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.

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 :)

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 :)

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 :

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.

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.

Saturday, 18 September 2010

Life on Planet STM.

This step is relatively simple after the last one - you connect the Serial converter built in the last post to the STM32. There are two wires - one runs from PA10 (actually USART1/Rx) on the STM to pin 12 of the MAX3232, the second one runs from PA9 (actually USART1/Tx) on the STM to pin11 of the MAX3232.

You can see the wires (the two green ones) here.

The completed programming circuit for the STM32 Discovery
The software I used to check it was working I got from this page STM32 ARM Cortext bootloader. It is a python app called "stm32loader" and the link is about half way down the main text.  It requires python and pyserial to work.

If you download this file, reset the STM32 board using the black button, then run the program with the following :-

python stm32loader.py -p /dev/ttyS0

with a bit of luck it will echo back at you :

Bootloader version 22
Chip id `['0x4', '0x20']'

You may have to try a few times. It seems a little unreliable on my machine, not related to the baud rate either. The thing that seems to help is having a short gap between the reset press and running the python application.

It will sometimes echo "Can't init. Ensure that BOOT0 is enabled and reset device" back instead. I'm not sure if this is the application or the hardware.

Various possible causes spring to mind - the STM programmer interfering, the buggy USB key interfering, the circuitry being wrong.

I have found a C program which claims to do the same thing, and will experiment with that.

Getting the voltages right

One of the problems with the serial port is that it is rather high voltage - up to 15v. The STM operates at 3.3v - so we cannot directly connect it. To make this work properly we use a MAX3232 IC, which converts from one level to another - allowing us to talk to the STM32 board.

For this section, you will need 5 x 0.1uf capacitors (I used polyester ones which are cheap) and a MAX3232 IC (which is a couple of dollars).

On the breadboard :

1) Plug in the IC in a sensible spot, notch up.
2) Connect 3v3 to pin 16 and GND to pin 15. (these pins are on the top left of the STM board)
3) Put capacitors across - pins 1 and 3, pins 4 and 5, pins 6 and 15, pins 16 and 15, and pins 2 and 16.
4) Connect the cable you made in the last step so that :-
- RxD (pin 2 on the socket) is connected to pin 14
- TxD (pin 3 on the socket) is connected to pin 13
- GND (pin 5 on the socket) is connected to pin 15

Now put the short back in between pins 12 and 11 - this is the 'loopback' test again.
The completed serial interface, with the "loopback" short in place.

If you do this and it is working, as before the characters should echo back as you type them in to GTKTerm or whatever terminal program you use - you have connected the in and out together again, but at "the other side" of the chip where the voltages are okay for the STM32.

Now take the loop-back out. Here is the circuit. (Apologies for the text positioning, there are some bugs here)
Serial Interface Circuit

The next time we will start talking to the Microcontroller.

Constructing the Serial Cable

The first part of the serial connection is to get a working serial cable. If, like me, you have a box full of cables, you can probably find one to cut up to make a cable. If not, you can make one out of a 9 pin D Socket, a piece of cable (with at least three wires), and if you like neatness, a plastic cover.

You need to make a connection to pins 2 (RxD) 3 (TxD) and 5 (Ground). The pins are normally engraved on the plastic near the socket hole, so it's not hard to find the right one.

On the left - the PC plug - on the right - the socket

As I'm a test-as-you-go person, one quick and not-too-unreliable test is to connect the "txd" and "rxd" wires together - this sends the signal back into the PC. If you run a terminal program like GTKTerm this will mean the screen will 'echo' the characters as you type them in.

Size doesn't matter.

The Discovery board is quite a chunky thing, and I've ended up having to splash out on a new breadboard to fit it. Even then, there's only about a pin and a half visible on the left and half a pin on the right.

The other thing I've had to do is cut off pins PB10-PB15 (the six at the bottom). They are odd pins for counters and so on, but nothing too important. If I do need them I can always plug on the top of the board.

My Breadboard
This shows where I am now. Not much to see - the 220R resistor is visible on the top right of the board (this is the one that pulls the boot line to logic '1'). At the far top left you can see my serial connector which is currently on a "loop back" test. (the bit of wire connects Rx and Tx).

The next part involves building a serial interface. Unfortunately, RS232 (the PC serial port) and the STM board don't like each other, so I have to build a little bit of circuitry to convert the voltage levels.

Friday, 17 September 2010

Converting the STM32 to Boot Mode.

As with the ST8 Discovery board we have super hardware and lousy software support. Things are better now in that the demos actually work, but the software choices are annoying (silly screens) or limited (only 32k of code). The bug that was in the ST8 Discovery board (half working USB memory interface) isn't fixed either.

So, we have to access the hardware differently. In this case, we will use the GNU Compiler, and the STM32's inbuilt bootloader.

(Some lessons have been learnt from the ST8 Discovery - the STM32 is much easier to prototype, as you can plug it straight into a breadboard - except for the bottom rows (PB0-PB15). I struggle to believe that particular piece of design, but I can get round it by hanging it off the bottom of the breadboard)

The first thing we have to do is to set up the board so when it resets it goes into "BOOTLOADER" mode.

Table 1 of the Bootloader Document (AN2606) tells us this :

BOOT1 BOOT0 Boot Mode
X     0     User Flash memory    User Flash memory is selected as the boot space
0     1     System memory        System memory is selected as the boot space
1     1     Embedded SRAM        Embedded SRAM is selected as the boot space

So to get it to work we need to get BOOT1 to Logic 0 and BOOT0 to Logic 1

Returning to the STM32 Discovery guide, we see that these are set by solder bridges.

Bridge SB2 (BOOT1) is currently set to Ground (Logic 0) via a pull down resistor, which is correct. However, Bridge SB16 (BOOT0) is also connected to Ground (Logic 0) via a pull down resistor so that "User Flash Memory" is selected.

Moving on to Figure 11 (the schematic) we can see that removing SB16 will indeed push BOOT0 to Logic 1.

Not a good solution though, really. My "fix" for this is to put a 220R resistor between "Boot" (actually Boot0) and 5v on the top Right Hand side of the board.  Thus mangling the potential divider.

Changing the circuitry to enable boot mode
The dotted line and associated resistor has been added.  We can more or less ignore the minimal current passing through the 10k resistor, and as a potential divider the voltage on BOOT0 is 510 / (510+220) * 5 v, which is 3.49v, slightly above Vcc, but within tolerances - and that pin is 5v tolerant anyway, according to the specification.

On my board it actually reads slightly less than this, but near enough.

You can this works by putting the 220R* resistor between lines "5V" and "Boot". If you now press reset the demo program the STM32 comes with (flashing the green led and the blue one if you press the button) doesn't start up. If you remove the resistor, then it works again.

There's a fair amount of current coming down here (6ma) that isn't necessary, but as the board is powered by the USB port, it doesn't matter - I think.

I am rather making this up as I go along. (There's a chance this might never work at all), so all suggestions or criticism are welcome.  Nothing is put on the blog until it is actually tried for real though.

NOTE: Following some discussions I reckon a 270R resistor may be better than a 220R. While it works fine on my board, the voltage is may be a little high ?