Sunday, February 22, 2015

Useful Hardware Helper Functions

As microcontrollers continue to offer ever increasing performance and overwhelming arrays of sophisticated on-chip peripherals, the task of getting an unfamiliar mcu up and running may at first appear very daunting.

One approach is to use a small library of useful helper routines, which allow you to achieve the basics, and confirm that the hardware is indeed working.

Most microcontrollers, these days come with some form of in-circuit serial programming capability, generally incorporated into the IDE - which makes loading a hex file into flash, quick and easy.

Every microcontroller needs a minimum hardware support system, consisting of a power supply, a clock oscillator and reset circuit.  It's also a very good idea to make a serial communications (UART) port available - and the standard 6 pin "FTDI" USB cable connection, makes a very simple way of both powering and communicating with the fledgling target hardware.

For decades a program to print "Hello World" was normally the first program to be written for any new system, but for the microcontroller, turning on and off a LED connected to a digital output is often the best way of proving that there is indeed life in the target board.

This involves writing to two of the on-chip registers.  Usually one defines the direction of the port lines - whether they are configured as input or output - sometimes called the Data Direction Register. The second is the Port Register itself, from which the port data can be written to or read from.

Arduino effectively deals with the low level register interaction with the pinMode, digitalWrite and digitalRead functions - and the equivalent of these are needed in your armoury for whichever micro you are dealing with.

The ability to change the state of an output pin, when entering or leaving a block of code, provides a simple but effective debug method. I often use an oscilloscope to check for changes of pin state, but a LED or even a small speaker could provide an indication of pin activity.

With high clock rates, code execution speed can be very fast - even when writing in a high level language such as C.  Some means of introducing program delays is needed to slow things down to a more sensible speed.  The simplest delay is a for loop, and by executing a for loop multiple times, delays of some microseconds can be achieved.

Suitable nesting of the microsecond delay loop can be used to achieve millisecond delays, but it should be noted that these are blocking delays, and the micro cannot execute any other task whilst in the middle of a delay.  They are fine for initial debug, but generally should not be used in real code. As most microcontrollers have counter timer peripherals, these can be used to provide system tick or millisecond counting, which can be used later on for non-blocking delays and other task timing functions.

With a controllable delay and the means to change the state of an output pin, we are now in the position to flash an LED - and this is the classic "Blinky"  popularised by Arduino.  However, with time-controlled I/O operations it is possible to write functions to provide "bit-banged" serial communications, and this was often done where there was no on-chip UART provided. Bit-banging is a simple but powerful technique and can be used to communicate with shift registers or even SPI devices.

So with the means to provide serial output, we are close to sending characters and numerical output to a terminal program.

The simplest serial operation is to send a single ASCII character to a terminal - and in C this is generally called putchar.  Using putchar with characters from an array, allows operations such as memory dumps to be performed and even simple file transfer.  I often combine putchar into a function I call printnum, which provides the means to send an integer number to a debug terminal.

As most microcontrollers have an on-chip UART, it's fairly simple to write a version of putchar to send a character to the USART transmit register.  To avoid embarrassment, it's best to check the UART Tx status flag first, to ensure that the UART has finished sending the previous character, before the next is loaded.


The complementary function to putchar in C is getchar.  This reads the UART Rx register and returns any character that may be present in the Rx register. Once again the status flag should be read to wait for the character to be clocked in, before the Rx register is read.

The story so far....

We now have a small collection of 8 routines which will allow us the basis of input/output, timing and serial communications:

pinMode
digitalWrite
digitalRead
delayMicroseconds
delayMilliseconds
putchar
printnum
getchar

These routines can be considered the fundamental building blocks of any high level application as they are the ones that interact with the peripheral registers at the lowest level.

With these in place, others can rapidly be implemented to handle other peripheral functions that might be present such as ADC, Timers, SPI etc

analogRead
pwmWrite
spiRead
spiWrite

And a very useful millsecond counting function millis() will help immensely with programing time-keeping tasks and implementing non-blocking longer delays.



No comments: