Archive for the ‘microcontrollers’ Category

HAL designing, part 1

02-01-2008

Hardware Abstraction Layer is a part of software that (almost) allows you to forget about hardware you’re working with. In perfect case you can use the same software on different hardware just by changing the hardware layer.

Clean and well designed HAL hides hardware differences and separates software layer responsible for hardware managing from main application functionality.

There are some issues to consider before designing and coding HAL…

(more…)

ATMega88 basic board

26-12-2007

Small project in KiCad.
ATMega88 with power supply, isp and rs232 connectors on first schematic.
ATMega88 basic board
Here in png file.

Module with max232.
ATMega88 basic board
Here in png file.

It’s good idea to make separate, small module for rs232 communication – it may be useful in other projects. You should think about rs232 connector pinout (between board and module). In this case it is possible to plug P2 (RS232) inversely – this may burn up your rs232 module and even com port or supplier.

I haven’t got max232 for 3.3 V power supply so I usually put 5 V regulator on rs232 module. As far as I remember ATMega88 tolerates 5 V on its inputs even when it’s powered with 3.3 V.
To launch this board you’ll need also stk200 programmer, it’s very simple and easy to google.
On this basic board you may run uart example. Of course you need to configure clock speed (fuse bits + uart registers)…

ATMega88 basic board – KiCad project.
AVR ATMega88 – KiCad lib.

New lpc23xx errata

18-06-2007

NXP published new erratasheet for lpc23xx family (see previous post).
It’s available here.
To summarize – sometimes turning MAM fully enable may cause instability. Workaround – don’t (fully) enable MAM.
I’ve expected much more details, so I’m really dissapointed. Maybe they aren’t sure yet when and why exactly MAM fails…
Anyway I haven’t noticed new errata for lpc21xx family. Maybe they mismatched family name with lpc24xx, which of course is affected by this bug. “Of course” because lpc24xx is based on lpc23xx.
There is one more bug about code execution speed. If code is executed from flash memory frequency is limited to 60MHz. I’m not sure what it means. Is 60MHz maximum main clock frequency or maybe for clock faster then 60MHz code will be executed with same speed? In first case – peripherals and code work with max 60MHz. In second – code is executed as with 60MHz clock, but peripherals (like timers…) may work up to 72MHz.
Far for now – with 72MHz clock and MAM disabled I consider lpc23xx working stable.

New errata for lpc23xx?

14-06-2007

Is this good news for NXP lpc23/24xx users..?
lpc2000 mailing list – lpc speed problem
In short – there is some issue with MAM (Memory Acceleration Module) in LPC23/24xx. If microcontroller works with high frequency clock (max is 72MHz), the MAM is enabled and there is more then 32KB of code, it may work unstable. Of course when MAM is disabled everything works just perfect. Funny thing is that same code may work perfect on another lpc microcontroller or even on the same after reflash. Same thing with frequency – you may find some information about solving MAM problem with changing frequency below 60MHz. There are also some posts about MAM problems when code is bigger then 32KB, but I think problem is related with code location, not size.
Issue may be also connected with PLL problems in lpc23xx family.
Anyway – I’m quite surprised that NXP (if guy is really from NXP…) noticed this bug so late, but better late then never. It’s hard to belive that lpc210x family has same bug (has NXP been selling it for more then a year..?).

Workaround proposition sounds like some voodoo magic – insert some NOPs and limit frequency. I would add “pray” :-).

After small reprimand I have to say that their microcontrollers even without MAM are quite fast – 72MHz is very nice frequency in ARM7. The thing is that with acceleration enabled it works even 4-5 times faster.

It’s very good that NXP finally admitted that problem exist. I hope new errata, with more precisely explanation of this bug, will be available soon.

Here is some interesting posts about MAM problems in lpc23xx family:
Investigation of LPC23xx MAM Issues – lpc2000 mailing list discussion.

ISP quick tip

23-04-2007

Low frequency main clock…

If you use simple ISP programmer (like stk200) and your AVR microcontroller stops responding after changing clock frequency to very low – don’t panic.

I’ve got similar problem with avrdude – it just can’t detect atmega88 after I change clock speed to about 100kHz. Because I’m using the power save mode (those with timer2 clock enabled) changing the main clock prescaler gives me about 100-200 uA less current consumption. What I tried to do was to change system prescaler before the sleep mode (I’ve changed timer2 prescaler so timer worked with same speed in normal and sleep mode).

Avrdude can’t detect device because it’s to inpatient :-). All you have to do is talk to your AVR a bit slower. I’m afraid it can’t be done with avrdude (at least you probably may put some delays into avrdude code to make it work slower, avrdude is an open source utility, so use the source luke :-) ). Theoretically AtmelISP had some options to change frequency of programming avr with stk200, but I could’nt find any working with atmega88 and stk200 aplication on Atmel site.

Use uisp!

Uisp is an isp programmer, like avrdude. I’m not sure if uisp supports newer avr microcontrollers (I’m not so sure if “new” is the right word here) like atmega88, but I was able to erase flash memory with atmega8 parameter. After that avrdude starts detecting my atmega.

AVR, UART C++ example…

02-03-2007

Some people came here from Google, looking for “avr example”. I’m playing with Atmega88 for a few days, because I’m thinking about simple motorcycle alarm.

Normally when I get new microcontroller I’m programming UART to get some readable debug output. It (probably) won’t be needed in final version of device – I don’t want MAX232 to consume power and I may have not enough memory to append extra debug code. (situation with not enough memory would be a nightmare, but it’s still possible – UART and Debug classes aren’t very big, but const strings with debug output may consume a lot) Anyway it’s good idea to get UART working at the very beginning.

Of course you know that you may set your house on fire or brake your leg because of my ideas or software I developed. I’ve got both legs straight and they seem to be all right, but it doesn’t prove anything. I’ve heard that probability of train appearing over your head (3..2..1..now) doesn’t equal zero. So, you’ve been warned.

I’ve written a post about avr and interrupts in c++ about three weeks ago. There was an example of defining interrupt routine as a friend of class. I’ve implemented C_UART class methods and added C_Debug class.

You can get sources here.

Directories and files:

  • Devs
    • debug.h, debug.cpp – debug device, defines operator <<
    • devs.h, devs.cpp – devices namespace
  • Periphs
    • uart.h, uart.cpp – uart peripheral class and interrupt routines
    • periphs.h, periphs.cpp – peripherals namespace

After including files with namespaces in main.cpp:
Debug<<"Hello World!\n"<<"uiTest = "<<123<<"\n";

Remember that there is no memory copying, so there is no hidden buffers – when you’re using this debug output microcontroller waits until all data is sent.
You have to change UBRR0H/L definitions in uart.h. They’re correct for baud rate 9600 when clock is ~8.8MHz. You may find proper values in ATmega88 datasheet.

Makefile is based on some example from AVRFreaks, I’ve just modified it to compile C++ code, added some dependencies and run statement. You may compile this project using WinAVR under Windows or anyhow under Linux.

After “$ make all” and “$ make run” you should get something like this (terminal – 9600/8/1):

Hello World!
uiTest = 123

That’s all folks :-).

Thanks to Patrys for hosting my files.

IAR, Extended Embedded C++ and templates support

20-02-2007

I’m not sure what’s going on – wordpress stats shows that some people saw this post when it was a draft. I thought it’s not possible, but… I’m a little sleepy so maybe I’ve done something wrong (or better – not 100% correct :-) ).

Second thing is about avatar – I’ve uploaded one, but it’s not visible on “about” page and in my posts. If you have any idea – please let me know… I’m just a programmer, you know :-).

Now, let’s get to the point.

IAR templates support

On IAR site you may read that their Extended Embedded C++ supports templates. It does. Mainly. But there are (of course) some funny issues.

Let’s start with something simple, there shouldn’t be any problem:


template <typename TypeA>
class ExampleClass
{
    TypeA W;
};

and somewhere in code...
ExampleClass <int> Instance;

Here you go, first template. Working, how sweet. Let’s try something a little bit complicated.


template < typename TypeA >
class BaseClass
{
    /*code*/
};

class DerivedClass : public BaseClass < DerivedClass* >
{
    /*code*/
};

DerivedClass inherits from the BaseClass template. The template parameter is a pointer to DerivedClass.
This example will compile under IAR and gcc. Anyway, try to use our DerivedClass.


///somewhere
DerivedClass Instance;

Such code crashes IAR. Updating compiler, linker, even downloading whole newest workbench doesn’t fix the problem. There were “internal tool error”, “fatal tool error” and crash without any message (IAR just disappeared).
Same code working after compiling with gcc without any problems.

Workaround…
Because there can’t be pointer to derived class in template parameter, pointer to void could be used. This solution should work, but it’s ugly. So there is nice one:


template < typename TypeA >
class BaseClass
{
    /*code*/
};

class DerivedClass;

class DerivedClassWA : public BaseClass < DerivedClass* >
{
};

class DerivedClass : public DerivedClassWA
{
    /*code*/
};

///somewhere
DerivedClass Instance;

This code is compiling and working under IAR because there is no pointer to derived class as template parameter. It should be correct for any C++ compiler.

AVR interrupts in C++

07-02-2007

AVR interrupts in C…
Defining interrupt handler function under gcc is quite simple. All you have to do is write your own function and name it with macro ISR(vector_name), enable interrupts and allow interrupt generation for selected peripheral. For example ISR for uart transmitter should look like this:


ISR(USART_TX_vect)
{
    Code sending next byte...
}

Such handler works in C and C++, it even might be sufficient. Anyway it’s not very friendly for object – oriented programming.

Interrupts and object-oriented programming…
Interrupt itself is kind of dysfunction in program processing. There are some methods to predict jump condition but processor can’t predict when will an interrupt occur. Every time interrupt occurs processor has to flush pipeline and jump to interrupt routine.
In C++ you can describe peripheral as a class, here is simple example for uart public interface:


class C_UART
{
public:
    /// Turning uart on, setting registers (baudrate...)
    void Init(void);
    /// Sending uiSize bytes of pBuffer.
    bool Send(char* pBuffer, unsigned int uiSize);
    /// Receiving uiSize bytes to pBuffer.
    bool Receive(char* pBuffer, unsigned int uiSize);
    /// Checking if uiSize of pBuffer is sent/received.
    bool IsTxReady(void)
    bool IsRxReady(void)
};

Such interface should be enough to send and receive sequence of bytes. In fact, because uart sends data byte after byte there has to be some data counters and local copies of pointers. They should be kept in private or protected area:


private:
    char* pTxBuffer;
    char* pRxBuffer;
    volatile unsigned int uiTxCounter;
    volatile unsigned int uiTxSize;
    volatile unsigned int uiRxCounter;
    volatile unsigned int uiRxSize;

Now it’s possible to check if uiTxCounter++ is equal to uiTxSize. If not – send next byte from pTxBuffer.
It’s what ISR should do, but it can operate on global/public variables only, it doesn’t have access to private members of objects.
First of all – I’m working with ATMega88, it has only one uart peripheral so I’ve added one static pointer to C_USART:


private:
    static C_UART* pUart;

Of course it’s possible to add static Create() method and use pUart as singleton, in this simple example it should be initiated in constructor of C_UART class (with this).
Also it could be an array of static pointers if there’s more then one instance of C_UART class (more then one uart peripheral so more interrupt sources also).
Because pUart is a static pointer so our uart object is now reachable, but it’s still inaccessible.
The definition of ISR(x) for USART_TX_vect macro looks like:


extern "C" void USART_TX_vect(void) __attribute__ ((signal));
void USART_RX_vect(void)

It’s not possible to make it class member, even static. But it’s possible to declare such function as a friend of C_UART class. Interrupt handler would be able to access static pUart and modify any of private members C_UART.
Here is my c_uart.h listing:


#ifndef _C_UART_H_
#define _C_UART_H_

extern "C" void USART_TX_vect(void) __attribute__ ((signal));
extern "C" void USART_RX_vect(void) __attribute__ ((signal));

class C_UART
{
private:
    char* pTxBuffer;
    char* pRxBuffer;
    volatile unsigned int uiTxCounter;
    volatile unsigned int uiTxSize;
    volatile unsigned int uiRxCounter;
    volatile unsigned int uiRxSize;
    static C_UART* pUart;
public:
    void Init(void);
    bool Send(char* pBuffer, unsigned int uiSize);
    bool Receive(char* pBuffer, unsigned int uiSize);
    bool IsTxReady(void);
    bool IsRxReady(void);
    C_UART();
    friend void USART_TX_vect(void);
    friend void USART_RX_vect(void);
};
#endif

Few facts about CC1000 chip

20-04-2006

Description

The CC1000 is a single chip UHF transceiver manufacturing by Chipcon. It works in wide frequency range from 300MHz to 1GHz and offers data rate up to 76.8 kbit/s (in Manchester mode 38.4 kbit/s only). CC1000 is designed for low power applications and (according to datasheet) it will consume 0.2 uA in powerdown mode, ~10mA working as receiver and up to 15mA when transmitting data in normal mode (0 dBm).

First and most important thing about transmitting data with CC1000 is that it just provides digital transmission. Nothing more. With properly set CC1000 chip you can think about ones and zeros, but you can't think about packets. Everything above – checksum like CRC32 or any protocol are not provided. On one hand – it's good, you are totally free to implement (almost) any protocol, but on the other – you have to do everything yourself.

Interfacing

Chipcon sells CC1000 chips in minimodules called CC1000PP (Plug&Play) – small modules with chip and few passive elements onboard, designed for 433 or 868MHz. Difficulties begin when you want to connect CC1000PP to 5V microcontroller. CC1000 is low voltage chip, supply voltage should be 3V. You'll find some tips about voltage level conversion on Chipcon's webpage. They suggest to use 74LV245 buffer or just make this conversion with some transistors. I chose the first way. Indeed I used 74HC245 because I could'nt get LV. It's not a good idea and it should'nt be done with HC but… it works.

Second problem are bidirectional lines in CC1000PP. If you have 5V microcontroller you'll probably can't use one microcontroller pin to control bidirectional pins like PDATA or DIO. You'll have to split those lines. It's quite simple with multiplexer. I used 74HC4052 from Motorola.

Third and last thing is stable 3V supply voltage. I decided to use LP2950. It's a voltage regulator for 3.3V. It's small and I have'nt noticed any heat when it was working.

If you have small board which provides supply, voltage level conversion and divides bidirectional lines you can almost begin transmission… almost.

Configuration

CC1000 is programmed by 3-wire interface. This interface is used for reading or writing 28 registers. First step is to get this interface working. It can be done with "bit bangling" method or SPI interface. First method is simple but, in my opinion, it's quite dirty. You can find this method in Chipcon's example on their website. They provide an application note with library for AVR microcontrollers, nice for beginners.

Second thing is to calibrate CC1000. Chipcon's SmartRF Studio provides registers value. It can be downloaded from their webpage for free. You have to set few options like transmission mode or speed and SmartRF will generate properly values.

Calibration procedures are well described in CC1000 datasheet, examples can by also find in Chipcon's application notes. All procedures are in fact only series of reads, writes and delays.

Transmission

Last step is data transmission. CC1000 offers three modes of transmission – uart, NRZ and Manchester. In last two CC1000 provides the data clock at DCLK pin. It can be used to cause interrupt or it can be polled. If you'll get to this point you'll be able to send and receive bits.

I met some people who told me, that CC1000 is too difficult for them, but there were also some who said it's very easy. As usual – if you know something well – it's easy…