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

Monday, January 24, 2011

STM32 Discovery: The Basics - Echo the serial port (USART)

This is a continuing of my first post.  In this post I will build on what we had in the first one and get the ARM STM32 to echo what we send over the terminal with serial.

The first step is to configure the usart.  Open STM32_Init.c with the configuration wizard.  I will write on how to do it in C when I cover getting started with GCC.  Enable your USART1 and set the parameters.  Also enable USAT1 interrupts on RXNE (receive) that way we don't need to poll the data and we will be notified when a byte has arrived.

Once every thing is configured to your liking, hit save.  Now we will be able to use the structure called USART1.  Here are a few notes on members that are used allot.
USART1->SR   this contains information about the interrupt that was generated
USART1->DR  this contains the byte that we received or that will will write
if you assign USART1->DR a value, it will send that value out the usart.  If you get the value form USART1->DR, if will read the value received from the usart.

Next, open you need to open main.c.  In this file we will add the function definition for void USART1_IRQHandler (void).  This function was declared STM32F10x.s and was all ready mapped to an interrupt vector. So all we need to do is enable the interrupt (which we all ready did in the configuration wizard) and override it.
My function will look a little bit like this.

void USART1_IRQHandler (void)
{
    volatile unsigned int vsr;
    int ByteSent;
    vsr= USART1->SR;
    if (vsr& USART_FLAG_RXNE)                   // did we interrupt on the read
    {
       // clear the interrupt since we are processing it
        USART1->SR &= ~(USART_FLAG_RXNE);  
        ByteSent = (USART1->DR & 0x1FF);
        SendByte(ByteSent);
     }
}

We will of course need to define SendByte.  The prototype will be void SendByte(int byte);
My definition will look something like this.
void SendByte (int byte) 
{
    //Wait for the uart to finish sending the byte.
     while (!(USART1->SR & USART_FLAG_TXE));
    USART1->DR = (byte & 0xFF);
}

Now you simply need to connect PA10 to RX and PA9 to TX on your hardware.  I used the FTDI chip on my arduino to accomplish this.  I simply connected PA10 to RX and PA9 to TX of my arduino and took the avr out.  After that what ever you send over to the terminal will echo back to you.  If you need a terminal program, I used Termite

You can download the project form my Code Project article

Wednesday, January 19, 2011

STM32 Discovery: The Basics - Creating a project

In this post I will be discussing how I got the stm32 discovery board working with the Keil IDE. This was my first time using an ARM processor, so I decided to go with a commercial grade IDE since they tend to be easier to use. As I switch over to GCC I will document that process as well.

For starters you need the STM32 discovery board
check it out at mouser
Also you will need the Keil IDE. You can download a free limited to 32kb program space version here

First off you need to create a new project and select the processor in the ST Micro section


It will then ask you if you want to Copy STM32 Start up Code to the Project Folder. Choose yes. I would then recommend you use the Keil STM32_init files. I found them in a example code. It can be found here
Once you have downloaded the files, unzip it. Copy over the following files to the same folder as the project file.
STM32_Init.c
STM32_Init.h
STM32_Reg.h
Now add STM32_Init.c to your project. Right click on the Source Group 1 and click add file to group. You can group them however you want, it doesn't change how any thing builds.

Also, to keep things clean we will create a Bin folder. So we make a new directory in the same folder as our project. Next, right click on the Target folder and click options for target.

Then click output and click Select Folder for Objects and go find our bin folder that we created.


Finally, create and add a file (lets call it main.c). In there, add a main function that will call the Init code and include the init file. You might also want to include the STM32 lib file.

#include <stm32f10x_lib.h>
#include "STM32_Init.h"

int main (void)
{

stm32_Init();
return 0;
}
Now we need to set up our debugging environment for the STM32 Discovery.  First we need to choose our debugger.  So right click on the project and click options for target and head to the debug tab.  Next, you don't want to be running a simulator so we will click the Use: radio button to the right half.  in the drop down we will choose the ST-Link Debugger.  Then you need to click setting and choose SWD.  finally I like to have run to main() check so that is stops at the main before running.


Next we need to define the flashing tool to upload your program to the STM32.  So head over to the Utilities tab and select the "Use Target Driver for Flash programming" radio button.  Then you can choose the ST-Link Debugger from the drop down.



Now you are all ready to debug.  In my next entry I will be making code to echo a terminal with The STM32 USART.

You can download the project form my Code Project article