Archive

Archive for June, 2011

Automatic Hardware Configuration for Embedded Systems

June 18, 2011 Leave a comment

Most of the time required in embedded systems development (atleast in case of hobby level projects) is in the configuration of the on chip peripherals of the microcontroller. The traditional approach is to look up in datasheets and then set associated register values for the desired functionality. This is very tiedious and time consuming. A better option is to define some of the frequently used configurations using some name indicative of functionality, and OR in different such values to generate the value for a single register. This is the option provided by common compilers like gcc.

A better way is to code small pieces of code, that will automatically configure the peripherals for a subset of the functionalities offered (believe me, it is difficult to programme for all the functionalities provided by the hardware using such a program). This piece of configuration code will be executed at the beginning only, so it will not impact the performance of the system other than consuming some extra flash code memory. Quite often startup time or flash memory is not a limitation, compared to RAM or CPU.

The process of creating such a code is very labour intensive. But once such an auto config code is created, most often, you can reuse the code as such, and sometimes with slight modifications, to incorporate extra functionality. This makes the development much faster. Code generators producing the configuration code, based on specifications are available for some of the platfroms like AVR. But such tools are not available for all existing and yet to be marketed hardware.

Examples

The following illustrate the three methods for configuring the Timer0 of Atmega32 to CTC operation at a frequency of 5kHz, when the IO clock is 8MHz. The compiler used is avr-gcc, which is available in the repositories of Ubuntu 11.04.

Crude Method

TIMSK|=0x03;    //Enable overfolw, and compare match interrupts
TCCR0=0x8a;    //Prescaler is divide by 8; timer mode....
OCR0=200;

Need to go through a datasheet to code and understand.

Formal Method

TIMSK|=(1<<OCIE0)|(1<<TOIE0);
TCCR0=(1<<FOC0)|(1<<WGM01)|0x01;
OCR0=200;

Still need to go through a datasheet to understand or code. But easier to understand than crude method

Proposed Method

initTimer0(5000,8000000,T0_TIMER,T0INT_COMP,0.5);

Only need to specify the requirements-Easy to understand, modify etc. Not as easy to code, as the real thing is behind the function call, as given below.

The function is defined in another file or library as,

//Timer modes
#define T0_PWM  0x68
//Fast_PWM mode, clear OC0 on compare match (up count)
#define T0_SYMPWM 0x60
//Phase correct PWM, clear OC0 on compare match during up count, and set during down count
#define T0_TIMER 0x88
//OC0 disconnected, CTC mode

//Timer interrupts
#define T0INT_ALL   0x03
#define T0INT_COMP  0x02
#define T0INT_OVRF  0x01
#define T0INT_NONE  0x00

void initTimer0(unsigned long frequency,unsigned long clkIO,unsigned char mode,unsigned char interrupt,float dutyCycle)
{
    unsigned char config, count;

    TIMSK=TIMSK|interrupt;

    if(frequency>=clkIO/256){
        config=mode|0x01;   //Prescaler divide by 1
        count=(unsigned char)(clkIO/frequency);
    }
    else if(frequency>=clkIO/(8*256)){
        config=mode|0x02;
        count=(unsigned char)(clkIO/(8*frequency));
    }
    else if(frequency>=clkIO/(64*256)){
        config=mode|0x03;
        count=(unsigned char)(clkIO/(64*frequency));
    }
    else if(frequency>=clkIO/((long)256*256)){
        config=mode|0x04;
        count=(unsigned char)(clkIO/(256*frequency));
    }
    else{
        config=mode|0x05;
        count=(unsigned char)(clkIO/(1024*frequency));
    }
    TCCR0=config;
    if(mode==T0_TIMER)
        OCR0=count;
    else
        OCR0=(unsigned char)(dutyCycle*255);
}