Having tinkered with the Arduino and it's clones for a few years, the opportunity arose to move up to a much more powerful 32-bit ARM Cortex M4 device, which is now available cheaply.
The ARM is a somewhat more complex device than the humble 8-bit Atmel AVR so it took a little while to get things up and running to the point where I could do useful development work with it. I hope that this blog post will be a help to anyone else considering such a move.
If you read some of the historical documents describing the development of computer languages in the 1960s and early 1970s, there is a common underlying theme - the desire of the computer pioneers to make things quicker and easier and create a more comfortable programming environment.
Ken Thompson, who wrote 'B', the precursor of C had a very limited DEC PDP-7 at his disposal, and according to Dennis Ritchie in the 2003 C History paper "Thompson wanted to create a comfortable computing environment constructed according to his own design, using whatever means were available."
Similarly, Charles Moore, creator of the Forth programming language, describes in his Forth history, how he continually strove to make things simpler, so he could focus on the application and not get bogged down in the primitive tool set.
So, in true tradition, when encountering a 32-bit ARM microcontroller for the first time, I wanted to get things quickly up and running and get it within my comfort zone, and treat it like any 8 bit or 16 bit mcu, such as the AVR.
ST Microelectronics have licensed ARM cores for several years, and have encouraged newcomers to their product by way of very low cost development boards. The STM32F4 Discovery board, which is a target for the ARM Cortex M4 microcontroller is available for as little as £10, or $15 in the US.
If you have come from an Arduino background, here is a low cost board, bristling with 80 I/O lines, an accelerometer, an audio codec and a built-in programmer/debugger which runs at 168MHz. Compared to the Arduino it runs at 10.5 times the speed, has 32 times the Flash and 98 times the SRAM, all for less than the cost of a Uno.
All those I/O lines take a little getting used to, as many of them are shared between the various on-chip peripherals, and you need to do a little bit of configuration work to make sure you have access to the mix of peripheral functions needed by your application.
One approach is to arrange the I/O and peripherals into a familiar format - and it is not unsurprising that the peripherals are a good match to the Arduino resources. In one configuration we can get:
4 USART Serial ports
3 SPI interfaces
12 ADC Inputs
2 DAC Outputs
2 I2C interfaces
12 PWM channels
2 Quadrature encoder channels
Numerous digital I/O
So in terms of I/O resources, the Discovery is a good approximation to the Arduino Mega, or Due but with a good speed and memory advantage.
The downside for newcomers, is that it does not come with the Arduino IDE, but this is not altogether a bad thing, because it encourages you to broaden your horizons and finally cut the Arduino apron strings.
All of the tools needed to program and debug the Discovery board are available open source, and very quickly you can be programming your application code. However, it's always good to take a few old friends along on any voyage of discovery, so here's how to get the basics up and running for the newcomer.
First you should install the IDE from CooCox. You can download their CoIDE from here
Additionally you will need to install the GCC toolchain - which is accessible from the CoIDE page.
The Discovery board has it's own on-board programmer/debugger known as the STLink. You will also need to download the driver for this - again available from the CoIDE page.
There is now a rapid increasing number of user examples of Discovery code. A quick search will bring up several good resources e.g.
Lastly, ST Microelectronics have released a standard peripherals library, and a good range of examples and application notes to support their dev kit. You might want to look through their examples here
The standard procedure for getting any microcontroller up and running, is to initialise a UART, and as a bare minimum provide the means to get serial input and output. Once this is achieved, debugging becomes a whole lot easier, and as likely as not, the final application will need serial communications - so it's not wasted effort.
The STM32F407 on the Discovery board is provided with up to six UARTS of which 4 are USARTS - meaning that they can handle both synchronous (clocked) and unsynchronous serial comms. Whichever USART is chosen, there is a certain amount of initialisation code to be executed first, and then some relatively simple code to handle character input and output.
Once the UART is up and running, you have the means to send numerical debug information to a serial terminal, and to control programs using simple serial commands.
One method I have used many times is a simple serial command interpreter based on a switch/case statement. It uses an alpha command and a numerical argument. For example, in a motor drive application, the serial command F100 could be entered to make the motor run forwards at 100rpm, and R100 would reverse it at 100rpm. These simple serial commands are easy to implement and a quick way of proving that your hardware and the various driver routines are working. Each new project I have worked on for the last few years has had some variant of this serial command interpreter programmed in as a prerequisite.
The other on chip peripherals are initialised using a similar set of functions. Most importantly is to remember to enable the clock to both the GPIO port you are using AND the peripheral you wish to use. Failure to do this is a common cause for non working peripherals.
The main.c routine posted up to Github Gist enables a number of peripherals:
USART1 and USART 2 for serial communication with a host computer.
ADC1, six 12 bit ADC channels enabled
Timer 2 and Timer 5 for 32 bit pulse counting (quadrature encoder) applications
Timer 1 for three complementary PWM channels for motor drive etc
Timer 3 is used to generate three independent PWM signals
Timer 4 is set up as a milliseconds tick timer
GPIO D is set up to have four general purpose outputs, used to drive the on board LEDs.
Further initialisation routines will follow to allow the SPI and I2C interfaces to be accessed, for SDcard and EEPROM devices. This will be covered in a later post.