Pages

Friday, 27 September 2013

Introduction to Pure C Arduino Library - Timers & Delays

As long as blinking a led is a fairly simple task. Arduino Library is very handy and can really improve the speed of development of a new projects, making your idea real & tangible. Something similar in C would be useful. At this moment one may ask - why to create a new library, when there are already plenty of those available and ready to use ? Well, thinking like that, we may ask ourselves straight away why to even bother and play with an 8-bit machine when there is so powerful and cheap stuff available out there at the moment everywhere nearly ? The answers for both are short and straight forward:
  1. Because we can and it's fun
  2. Because we want to learn something
  3. Because we want to create some real, useful stuff
Another reason to create a library is to have some basic tool set which will be absolutely essential in most of any further developments. First thing which will need in this tool set is a proper (by proper I mean - timer/interrupt based) delay function. I have nothing against a "busy" delay from AVR libc but there is a small problem with that - the delay time cannot be passed as a parameter in the runtime since the delay is calculated during compilation, based upon the defined clock value (F_CPU). Now that's a real problem. We could write a similar function as well, which would spin in a loop for a defined number of time but this is more tricky than it seems - probably the optimizer would simply remove our code since it would detect that it has no functional meaning, the second thing is that it would be really hard to maintain any kind of usable accuracy. Since we have a proper hardware to do that (timers) we will use it.

At the time being I already created a simple library implementing most of the essential functionality, so this post will continue more or less as a supplement to the documentation on how to really use it. The library is hosted on GitHub:


I suggest cloning it to pca directory, since current repository name is my GitHub remote convention naming scheme, which isn't really convenient for every day use:

git clone git@github.com:dagon666/avr_Libpca pca

The documentation for the library, is a doxygen generated html page, available here:


But going back to the topic of timers. Let's discuss how the delay could be implemented. If we program the timer to overflow every 1 ms then automatically we have a 1 ms delay accuracy functionality implemented. It's really simple, here are the steps needed in a little bit more details:
  1. Program a timer in CTC mode, to overflow every 1 ms.
  2. Enable timer COMPA/COMPB interrupt
  3. Set global variable, let's call it "duration" to the number of milliseconds required
  4. With every timer overflow, decrement the "duration" variable in the interrupt handler
  5. Block until "duration" > 0
  6. Disable timer interrupt, since the required amount of time has passed by

First of all we need to program a timer in CTC mode, to be able to specify the exact time needed for it to overflow. Please have a look at the datasheet for more details about how timer behaves in that mode. Let's walk through the code bellow:


Starting from the main function. I setup PORTB as output and initiate it's value to 0x00; Further on I toggle all lines of PORTB with a 0.5 Hz frequency. Let's focus on the delay implementation itself. 

I strongly suggest to go through this code with datasheet opened - it will help to understand the setting and the register values a lot. First thing is to enable global interrupts and power to Timer0 - I'll use this timer for delay purposes. I use a macro from AVR libc to power on the timer - all it really does is writes zero to bit PRTIM0 in PRR register which controls the power reduction settings of the MCU, so we can easilly replace that with an explicit bit operation if we want:

PRR &= ~_BV(PRTIM0);

_BV is another nifty macro from avr-libc. It performs a bit shift, so in that example it's equivalent to:

PRR &= ~(0x01 << PRTIM0);

Next I setup the Timer0 registers. First in TCR0A I configure Timer0 in CTC mode (WGM01 bit set). I do not care about COM0A1/COM0A0 and COM0B1/COM0B0 settings since I do not plan to output anything on the MCUs OC0A/OC0B pin. Next thing is to configure the prescaler value in TCR0B to 64 (CS01 and CS00 bits are set). At that stage the timer is running. I then configure the value of OC0A to 0x7c (124), accordingly to the formula in the datasheet, the frequency in CTC mode for Timer0 with these settings will be:

f = 16 Mhz / [ 2 * 64 * (1 + 124)] = 1 kHz

and the period:

T = 1/f = 1 ms

Exactly what we need in order to have a 1 ms accurate delay. The timer now is running and overflows with a required frequency. In the next line I configure the duration variable to the requested amount of milliseconds. All that has to be done at that point is to simply enable the OCIE0A (output compare interrupt which happends always when the counter reaches value configured in OC0A) interrupt and block in a while loop until the "duration" variable becomes 0.

In the interrupt handler, the duration variable is decremented (if it has a positive value) each time the interrupt occurs. Once "duration" is equal to zero, I simply mask the OCIE0A interrupt and disable to clock to Timer0 by configuring prescaler to 0. The timer now has been stopped and no further interrupts will be generated.

Because interrupt decrements the "duration" variable every 1 ms. After 1000 ms it will become zero, and the tdelay_ms function will end it's execution. Simple as that :).

The implementation in libpca is exactly the same as the example above, it's a little bit more complex only to provide more flexibility and not to duplicate the code inside of the library, but in general the principle stays the same. How to use timer delays with libpca then ? It's even simpler than our reference code above. Let's start by cloning the library and creating directory for our "test project":

git clone git@github.com:dagon666/avr_Libpca pca
mkdir delay_tests
cd delay_tests

Once inside of our project directory. Let's create two files main.c for our code and Makefile for compilation:

The code is really simple. The first difference is that there are two functions tdelay_init() and the tdelay_ms() function itself. The reason is that we need to configure the timer only once, after that all that needs to be done is to configure the "interrupt variable" and re-enable interrupts. This save some time when tdelay_ms() is called in a very busy loop. The second difference is that you must specify the timer explicitly for every function by using the timer enumeration (E_TIMER0 - E_TIMER2) The library tries to be as much flexible as it is possible. We can use any Timer we want, not only Timer0. One thing needs to be mentioned. In order for the timer delay implementation to work a timer interrupt implementation must be enabled for adequate timer in the library configuration (include/config.h), in case of the example above this should be:

#define TDELAY_IMPLEMENT_T0_INT 1

A complete example can be downloaded here.


I hope that this short introduction has been helpful. Going further there is not much that has to be changed to our existing reference code in order to implement the Arduino Library tone() function - I'll try to cover that next time.



Wednesday, 25 September 2013

Libraries, what they really are


This post is more of an introduction to what I plan to cover further on in the future.

Let's start with the basics, for those who are not very familiar with C compilation details. How to create a library, what kind of libraries can we create, what are the advantages/disadvantages ? First of all, there are two types of libraries, static (*.a files) and dynamic libraries (*.so files). The first ones are just a bunch of object files glued together to form a single file (object archive). The second ones are loaded during runtime by operating systems (like Linux (*.so files) /Windows (*.dll files)) whenever applications need them. Both have their pros & cons.

The advantage of dynamic libraries, short summary:
  • The library code is NOT included in every application using the library, the resulting executables are smaller
  • The library is loaded to memory by operating system (dynamic library loader) once an application requests it, and removed when no longer needed.
  • The library is shared across many applications - only one copy exists in the memory
  • When making changes to the library there is no need to recompile once again every application using it (as long as the interface stays compatible)

Disadvantages:
  • A true multi - process capable operating system is needed

In contrast to the dynamic libraries static libraries are simply compiled into the executable itself for every application using the library. The only advantage we really gain, is that once the library is compiled, we do not have to compile it anymore (if it doesn't change), we just compile the code of our app and link against the library.

The advantages of static libraries, short summary:
  • User results with a single opaque object archive file (.a) which he needs to link his application against
  • The library is an easily decoupled logical entity, containing some universal code
  • No sophisticated runtime loading mechanisms are required since the library code is included in the application itself

Disadvantages:
  • Every application must link library code into itself (larger executables)
  • Every application using the library must be recompiled if we incorporate a new change to the library

Although dynamic libraries seems to be far more superior, we can only benefit from creating static libraries for embedded systems like Arduino though. Now why is that ? The answer is simple: No operating system ! On our little 8 bit machine there are no resources to run an operating system capable of managing dynamic libraries and real multiprocess environment, thus the only option available are static libraries.

Just as an exercise let's create a dummy library. We'll need two files dummy.c and dummy.h
and the code:
We can't go any simpler. To create a library out of this code, all we need to do is compile it as an object:

avr-gcc -mmcu=atmega328p -I. -c dummy.c

In fact this single object file is already a static library. The (.a) file only aggregates them into a single file nothing else.

avr-ar rcsv libdummy.a dummy.o

... and there we go, our first lib. It can be used in a program the following way:

avr-gcc -mmcu=atmega328p main.c -ldummy -L. -I.

Additionally, we can have a look what symbols are inside:

avr-nm libdummy.a

dummy.o:
0000003e a __SP_H__
0000003d a __SP_L__
0000003f a __SREG__
00000000 a __tmp_reg__
00000001 a __zero_reg__
00000000 T portb_high

Our function starts from address 0x00, we can have a look at the assembler output:

In archive libdummy.a:

dummy.o:     file format elf32-avr


Disassembly of section .text:

00000000 <portb_high>:
   0: cf 93       push r28
   2: df 93       push r29
   4: cd b7       in r28, 0x3d ; 61
   6: de b7       in r29, 0x3e ; 62
   8: 85 e2       ldi r24, 0x25 ; 37
   a: 90 e0       ldi r25, 0x00 ; 0
   c: 2f ef       ldi r18, 0xFF ; 255
   e: fc 01       movw r30, r24
  10: 20 83       st Z, r18
  12: df 91       pop r29
  14: cf 91       pop r28
  16: 08 95       ret


What can be seen here ? First, registers r28,r29 (register Y) are preserved on the stack (address 0 and 2). Then, r28,r29 is configured to the current stack pointer top. That's a standard gcc behavior. Next two instructions load registers r24,r25 with the memory address of PORTB (0x25). The instruction at address 0x0c loads our argument 0xff to register r18. Next two instructions copy the register pair r24,r25 to r30,r31 (register Z) in order to store the value in r18 (0xff) in the memory (0x0025 - PORTB). Next the stack is restored and we exit the function. Quite a lot of stuff as for such a simple code :). This code is compiled of course without any optimizations enabled. If we compile it once again with -Os (size optimization), the output looks a lot less clobbered:

In archive libdummy.a:

dummy.o:     file format elf32-avr


Disassembly of section .text:

00000000 <portb_high>:
   0: 8f ef       ldi r24, 0xFF ; 255
   2: 85 b9       out 0x05, r24 ; 5
   4: 08 95       ret

The code is pretty obvious and doesn't require further explanations from my point of view. At this time I'm sure that most of the library technical specific aspects have been covered and we are ready to create some more useful stuff. In the next post, I'll try to explain the details regarding the Atmega's Timers and introduce you to a real library with more useful code.

Sunday, 22 September 2013

Arduino in pure C

Arduino is a great, simple development platform and it's simple enough that even less advanced users can start and be creative straight out of the box. I have nothing against the C++ Arduino Libraries but relying only on those separates you a little bit from the machine itself. Arduino is simple enough to use it with Pure C. Doing so, you will not only learn a lot more, but will have an ultimate control over your software and will better understand what really is going on. I dedicate this blog to everyone who is starting with Arduino as well as to those of you who already have a lot of experience with it but were never really brave enough to abandon the Arduino Libraries and IDE itself.

In order to start we need a couple of tools.
  • toolchain & cross compiler: avr-gcc, avr-binutils
  • C library: avr-libc
  • Programmer: avrdude
Some other useful stuff which can be installed:
  • debugger: avr-gdb
  • simulator: simavr/simulavr
On most of the modern system those packages can be installed automatically (through a package manager). If that's not the case, you will have to download them compile and install manually. On ARCH linux you can install arduino package using yaourt, which will automatically install avr-gcc + avrdude, unfortunately those are not placed in the PATH directories so one needs to specify the paths explicitly. I'm not going to focus on those matters as in my understanding they're a little out of scope.

To start the work first of all, we need to prepare a Makefile which will ease up the development and compilation process. The avrdude configuration paths, serial port or the target mcu should be adjusted accordingly to the configuration of your board and system. TARGET denotes the name of the ELF file which will be generated by the compiler and SOURCES variable should contain a list of all source files which must be compiled. For the purpose of this simple example there is only one blink.c which we'll create later on. The basic Makefile which I will use and extend further on looks the following way:



Using C with AVR MCU requires some knowledge of the avr-libc library. So this site:

http://www.nongnu.org/avr-libc/

will be your best friend for now on. Not mentioning the detailed datasheet of the MCU itself. For Atmega's installed on Arduino UNO this one is located here:

http://atmel.com/Images/Atmel-8271-8-bit-AVR-Microcontroller-ATmega48A-48PA-88A-88PA-168A-168PA-328-328P_datasheet.pdf

The Arduino Schematics also comes very handy:

(Rev 3): http://arduino.cc/en/uploads/Main/Arduino_Uno_Rev3-schematic.pdf

For the moment we need to know three things.
  1. In order to configure a pin as output we need to configure it in the DDR(B,C,D) register.
  2. In order to raise the pin high or low we need to set an appropriate bin in the PORT(B,C,D) register.
  3. The avr-libc implements the simplest, so called, busy delay (which in general is a bunch of loops) which can be used for our purposes.

Let's put this together:


A short walk through this example. Line 6, writing 0x01 will configure pin 0 of port B as output, on the next line I'm setting port B to zeros. On Line 10 I'm XOR'ing current value of PORTB with 0x01, this will cause a value of the first bit to toggle since

0 xor 0 = 0;
0 xor 1 = 1;
1 xor 1 = 0;
1 xor 0 = 1;

On the next line I'm calling a avr-libc delay function, so our LED won't blink with full clock speed. If we have a look at the schematics, then we can see that PORTB0 is connected to pin 8 on the arduino. This is where the LED should be attached.

All that needs to be done is as simple as:
make
make install

... and our blinking led C "project" should run now on Arduino. Complete code can be found here:

https://googledrive.com/host/0ByE_WFvvg-guTzE4TmFwMDhaZTA/blink.tar.gz