Monday, January 31, 2011

STM32 Discovery: The Basics - Buffering the USART and Error Handling

So this part is mostly coding a linked list. probably not the most efficient linked list either but it servers its purpose does not have much over head too.  The code also does not do checks if pointer is null and such and assumes you will be able to add that.  The code has room for improvement but this is to give a basic idea.

so I created 2 files urat.h and uart.c. I will not describe adding the function signatures in the header and assume you will do that.

we will first need to declare out struct for the linked list.

#define READ_BUFF_SIZE 1024
//structs
typedef struct ReadWriteBufferStruct
{
int size;
int readAt;  //the next byte to read
int writeAt; //the next byte to write
int* buffer;
}ReadWriteBuffer ;



typedef struct LinkedReadWriteBufferStruct
{
struct LinkedReadWriteBufferStruct* next;
ReadWriteBuffer buffer;
}LinkedReadWriteBuffer ;

We also nee a couple global variables
//a pointer to the buffer we are currently reading from
extern LinkedReadWriteBuffer* receiveReadBuffer;
//the pointer to the buffer we are writing to
extern LinkedReadWriteBuffer* receiveWriteBuffer;


We will define these variables in uart.c

now in our main we will need to instantiate those variables

receiveReadBuffer = (LinkedReadWriteBuffer*) malloc(sizeof(LinkedReadWriteBuffer) ) ;
receiveWriteBuffer = receiveReadBuffer;
receiveReadBuffer->buffer.size = READ_BUFF_SIZE;
initRWBuff(&(receiveReadBuffer->buffer));


now we are ready to tackle uart.c
The first function we need to define is initRWBuff()  this function will initialize a buffer to its default values.
here is what mine looks like

void initRWBuff(ReadWriteBuffer * tmpBuff)
{
    tmpBuff->buffer = (int*)malloc( sizeof(int) * tmpBuff->size);
    if(!tmpBuff->buffer)
    {
        HardFault_Handler();
    }
    tmpBuff->writeAt = 0 ;
    tmpBuff->readAt = 0 ;
}

So now we need to write the the buffer every time we receive a byte from our interrupt routine.  Basicalyy we will read the char we are receiving and insert it into the buffer.  we will increment our counter of where the last byte was written.  If the buffer if full, we will create a new buffer to write in the next time.  It would probably be more efficent to have it create the buffer only one we need to use it.

Here is what my routine looks like
void USART1_IRQHandler (void)
{
    volatile unsigned int IIR;

    IIR = USART1->SR;
    if (IIR & USART_FLAG_RXNE)                   // read interrupt
    {
        USART1->SR &= ~USART_FLAG_RXNE;              // clear interrupt
        receiveWriteBuffer->buffer.buffer[receiveWriteBuffer->buffer.writeAt] = (USART1->DR & 0x1FF);
        receiveWriteBuffer->buffer.writeAt++;

        if(receiveWriteBuffer->buffer.writeAt == receiveWriteBuffer->buffer.size)
        {
            LinkedReadWriteBuffer* tmpBuff;
            tmpBuff = (LinkedReadWriteBuffer*) malloc(sizeof(LinkedReadWriteBuffer) ) ;
            if(!tmpBuff)
            {
                HardFault_Handler();
            }
            tmpBuff->buffer.size = READ_BUFF_SIZE;
            if(!tmpBuff->buffer.size)
            {
                HardFault_Handler();   
            }
            tmpBuff->next = 0 ;
            initRWBuff(&(tmpBuff->buffer));
            receiveWriteBuffer->next = tmpBuff;
            receiveWriteBuffer = tmpBuff;
        }
    }
}
now we need to create a function that will read the buffer and skip to the next one when we get to the end.  I will call mine my_recv()  because I will use this function else where for socket connection. 
here is what it looks like:
int jm_recv(void* uart, unsigned char * buff, int size)
{
    int i=0;
    for(;i<size && receiveReadBuffer->buffer.readAt < receiveReadBuffer->buffer.writeAt;i++)
    {
        buff[i] = (char) receiveReadBuffer->buffer.buffer[receiveReadBuffer->buffer.readAt];
        receiveReadBuffer->buffer.readAt++;
        if(receiveReadBuffer->buffer.readAt == receiveReadBuffer->buffer.size)
        {
            if(receiveReadBuffer->next)
            {
                LinkedReadWriteBuffer* p = receiveReadBuffer;
                receiveReadBuffer = receiveReadBuffer->next;
                free(p->buffer.buffer);
                free(p);
            }
        }    
    }
    return i;        
}

if you want o wrap SendByte with a similar signature. here what I did.
int jm_send(void * param, unsigned char * buff, int size)
{
    int i;
    for(i=0;i<size;i++)
    {
        while (!(USART1->SR & USART_FLAG_TXE));
        USART1->DR = ((buff[i]) & 0xFF);
    }
     return size;
}
I warped these this way because I will be using them with polarssl
now for simple error handling we just need to override the error functions we want to handle.  similar to our IRQ. I simply Added this under the main.
void HardFault_Handler(void)
{
    int error = 0;
    while(1);
}

Eventually I will make it reboot the device. a few more error functions you can override are
DCD     HardFault_Handler         ; Hard Fault Handler
DCD     MemManage_Handler         ; MPU Fault Handler
DCD     BusFault_Handler          ; Bus Fault Handler
DCD     UsageFault_Handler        ; Usage Fault Handler

You can see the list in STM32F10x.s
Finlay you might want a larger stack then the default.  the stm32 Discovery has 92kb of ram.  I set my stack to half of that.  Open up STM32F10x.s and click the Configuration Wizard at the bottom.  open the stack Configuration and increase the Stack size.  I set mine to 0x14000.
The next post will cover using the usart to connect to a pc that will then connect to the internet.  I will also suggest other ways to connect to the internet with out the PC

3 comments:

  1. I'm using USART2. Transmission from STM32 board to PC is fine. I'm writing 5 bytes to COM port in PC, but I'm receiving only first 2 bytes of the 5 bytes. The initialization looks fine http://harinadha.wordpress.com/2012/04/17/stm32_usart2/. I use same IRQ handler routine available over the web.

    ReplyDelete
  2. Hi Harinathc,
    I will look into this later this week and get back to you. Feel free to email me any time as well.

    ReplyDelete
  3. what must we do when ovr happening and program hanging.
    I used to code to re initialize usart completely but the data transmission after resetting uart are not working proper.

    ReplyDelete