AVR, UART C++ example…

02-03-2007 by waterproofman

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 by waterproofman

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 by waterproofman

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 by waterproofman

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…