Tuesday, April 8, 2014

Porting FreeRTOS to Atmega328p Arduino UNO R3

/******************************************************************************
 * Header file inclusions.
 ******************************************************************************/

#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
#include <avr/io.h>
#include <avr/interrupt.h>
#include "portmacro.h"
#include <stdio.h>

/******************************************************************************
 * Private macro definitions.
 ******************************************************************************/

#define mainLED_TASK_PRIORITY   (tskIDLE_PRIORITY)

/******************************************************************************
 * Private function prototypes.
 ******************************************************************************/

static void vBlinkLed(void* pvParameters);

/******************************************************************************
 * Public function definitions.
 ******************************************************************************/

void * xSerialPortInitMinimal( unsigned long ulWantedBaud, unsigned portBASE_TYPE uxQueueLength )
{
unsigned long ulBaudRateCounter;
unsigned char ucByte;

portENTER_CRITICAL();
{
/* Calculate the baud rate register value from the equation in the
data sheet. */
ulBaudRateCounter = ( configCPU_CLOCK_HZ / ( 16 * ulWantedBaud ) ) - ( unsigned long ) 1;

/* Set the baud rate. */
ucByte = ( unsigned char ) ( ulBaudRateCounter & ( unsigned long ) 0xff );
UBRR0L = ucByte;

ulBaudRateCounter >>= ( unsigned long ) 8;
ucByte = ( unsigned char ) ( ulBaudRateCounter & ( unsigned long ) 0xff );
UBRR0H = ucByte;

/* Enable the Rx interrupt.  The Tx interrupt will get enabled
later. Also enable the Rx and Tx. */
UCSR0B |= (1 << RXCIE0) | (1 << RXEN0) | (1 << TXEN0);

/* Set the data bits to 8. */
UCSR0C |= (1 << UCSZ01) | (1 << UCSZ00);
}
portEXIT_CRITICAL();

/* Unlike other ports, this serial code does not allow for more than one
com port.  We therefore don't return a pointer to a port structure and can
instead just return NULL. */
return NULL;
}
/*-----------------------------------------------------------*/


void uart_putchar(char c, FILE *stream) {
    if (c == '\n') {
        uart_putchar('\r', stream);
    }
    loop_until_bit_is_set(UCSR0A, UDRE0);
    UDR0 = c;
}
char uart_getchar(FILE *stream) {
    loop_until_bit_is_set(UCSR0A, RXC0); /* Wait until data exists. */
    return UDR0;
}

void uart_init(void)
{
xSerialPortInitMinimal( 9600, NULL );

FILE uart_output = FDEV_SETUP_STREAM(uart_putchar, NULL, _FDEV_SETUP_WRITE);
FILE uart_input = FDEV_SETUP_STREAM(NULL, uart_getchar, _FDEV_SETUP_READ);
FILE uart_io = FDEV_SETUP_STREAM(uart_putchar, uart_getchar, _FDEV_SETUP_RW);

stdout = &uart_output;
stdin = &uart_input;
}

int flag = 0;

// Define constants and variables for buffering incoming serial data.  We're
// using a ring buffer (I think), in which head is the index of the location
// to which to write the next incoming character and tail is the index of the
// location from which to read.
#if (RAMEND < 1000)
  #define SERIAL_BUFFER_SIZE 16
#else
  #define SERIAL_BUFFER_SIZE 64
#endif

typedef struct ring_buffer
{
  unsigned char buffer[SERIAL_BUFFER_SIZE];
  volatile unsigned int head;
  volatile unsigned int tail;
}ring_buffer;

ring_buffer rx_buffer  =  { { 0 }, 0, 0 };
ring_buffer tx_buffer  =  { { 0 }, 0, 0 };


inline void store_char(unsigned char c, ring_buffer *buffer)
{
  int i = (unsigned int)(buffer->head + 1) % SERIAL_BUFFER_SIZE;

  // if we should be storing the received character into the location
  // just before the tail (meaning that the head would advance to the
  // current location of the tail), we're about to overflow the buffer
  // and so we don't write the character or advance the head.
  if (i != buffer->tail) {
    buffer->buffer[buffer->head] = c;
    buffer->head = i;

if ( (c == '\n') || (c == '\r'))
{
// Notification flag
flag = 1;
}
  }
}



static void vUSART(void* pvParameters)
{
char input;
int i;

(void *)pvParameters;

    for ( ;; )
    {
    // TODO:
    portENTER_CRITICAL();
    // Recieve the USART command
    if (flag)
    {
    // Parse the command
    printf("Oh sir, you wrote: %s\n", rx_buffer.buffer);

// reset the flag
flag = 0;

memset(rx_buffer.buffer, '\0', SERIAL_BUFFER_SIZE);
rx_buffer.head = rx_buffer.tail = 0;
    }
portEXIT_CRITICAL();
}
}


// TODO: fixme
// ISR_BLOCK
// ISR_NOBLOCK
// ISR_NAKED

ISR(USART_RX_vect, ISR_BLOCK)
{
if (bit_is_clear(UCSR0A, UPE0)) {
 unsigned char c = UDR0;
 store_char(c, &rx_buffer);
} else {
 unsigned char c = UDR0;
};
  }



/**************************************************************************//**
 * \fn int main(void)
 *
 * \brief Main function.
 *
 * \return
 ******************************************************************************/
int main(void)
{
// USART task
xSerialPortInitMinimal( 9600, NULL );

// Redirecting STDIN and STDOUT to UART
FILE uart_output = FDEV_SETUP_STREAM(uart_putchar, NULL, _FDEV_SETUP_WRITE);
FILE uart_input = FDEV_SETUP_STREAM(NULL, uart_getchar, _FDEV_SETUP_READ);
FILE uart_io = FDEV_SETUP_STREAM(uart_putchar, uart_getchar, _FDEV_SETUP_RW);

stdout = &uart_output;
stdin = &uart_input;

    // Create task.
    xTaskHandle blink_handle;
    xTaskCreate
    (
        vBlinkLed,
        (signed char*)"blink",
        configMINIMAL_STACK_SIZE,
        NULL,
        mainLED_TASK_PRIORITY + 1,
        &blink_handle
    );

#if 1
// USART task
xTaskHandle usart_handle;
xTaskCreate
    (
        vUSART,
        (signed char*)"USART",
        configMINIMAL_STACK_SIZE,
        NULL,
        mainLED_TASK_PRIORITY,
        &usart_handle
    );
#endif

    // Start scheduler.
    vTaskStartScheduler();

    return 0;
}

/**************************************************************************//**
 * \fn static vApplicationIdleHook(void)
 *
 * \brief
 ******************************************************************************/
void vApplicationIdleHook(void)
{

}

/******************************************************************************
 * Private function definitions.
 ******************************************************************************/

/**************************************************************************//**
 * \fn static void vBlinkLed(void* pvParameters)
 *
 * \brief
 *
 * \param[in]   pvParameters
 ******************************************************************************/
static void vBlinkLed(void* pvParameters)
{
    DDRB |= _BV(PB5);

    for ( ;; )
    {
        PORTB ^= _BV(PB5);

if (bit_is_set(PORTB, PB5))
printf("LED on\n");
else
printf("LED off\n");

        vTaskDelay(1000);
    }
}

No comments:

Post a Comment