What is the best method to send data via uart

Thread Starter

Mjd Kassem

Joined Sep 9, 2016
15
hi every one ...feel free to deletd this post if it is not logically !!!
i have 60 bytes data frame(generated inside atmega128), i have to send them as a frame every 10 ms vi uart with 115200 Baud and 11.095200 MHz external crystal
i did this mission by using timer1 compare interrupt (ctc) mode to enable volatile flag and in the main loop i checked that flag and according to its state i started sending the 60 byte using usual for loop.i will be able to fed up you with the code but if my implementation is not good then no matter that code is .
when i simulated with Proteus using hyper terminal the frames sent correctly until the 9th frame,in 9th frame only some bytes was sent (about 10 bytes of 60) and suddenly moved to start sending 10th frame
i am new in micro controller, i do not know if my implementation is the best method. there is another problem also that is the timer compare interrupt not exactly 10 ms it is 10.06 ms according to atmel studio7 watchdog, note that i use 1024 prescale of 11.095200 which result in 107 value for
OCR1A register. can i get the exact delay value by another method ?
is it a good idea to use (_delay()) function instead of timer delay?
also i used the ring buffer library in atmel studio to implement uart function with buffer size equal to 60 (frame size)

should i do the sending operation in Timer1 ISR?
any document, simple example, and you experience will help me.
thank you so much
 

JohnInTX

Joined Jun 26, 2012
4,787
Welcome To AAC!
Without the code it is hard to tell exactly but a few things come to mind..
Are you checking that your buffer is empty before loading it with the next frame? 60 char at 115.2Kbaus is about 5.2msec but that doesn't count overhead. It sounds like the buffer may be getting written before the previous packet is fully sent. It is probably close in time which is why it takes several characters to show up.

To find out, double the send interval as a test. If it works, you are getting some creep.

Your timer implementation is a good one and much better than a delay. Keep in mind that as main does more it may take a little more time to get around to the flag and that may cause some delay in loading the buffer - its not the problem here but something to keep in mind.

It sounds like you have a linear buffer instead of a circular FIFO one?

Sorry about the rough reply. I'm putting a new SSD into my computer and get to reboot for drivers and stuff as I type..

Good luck!
 
Last edited:

Thread Starter

Mjd Kassem

Joined Sep 9, 2016
15
Welcome To AAC!
Without the code it is hard to tell exactly but a few things come to mind..
Are you checking that your buffer is empty before loading it with the next frame? 60 char at 115.2Kbaus is about 5.2msec but that doesn't count overhead. It sounds like the buffer may be getting written before the previous packet is fully sent. It is probably close in time which is why it takes several characters to show up.

To find out, double the send interval as a test. If it works, you are getting some creep.

Your timer implementation is a good one and much better than a delay. Keep in mind that as main does more it may take a little more time to get around to the flag and that may cause some delay in loading the buffer - its not the problem here but something to keep in mind.

It sounds like you have a linear buffer instead of a circular FIFO one?

Sorry about the rough reply. I'm putting a new SSD into my computer and get to reboot for drivers and stuff as I type..

Good luck!
Thank you for your interaction.... my solution in atmel studio is multiple file structure , i am writing it as single file to be easy in posting and discussion, I will be back as soon as i finish, but there is some thing to tell about your suggestion (To find out, double the send interval as a test. If it works) i do that and as you expected the 9th frame sent completely, the same thing occur when i also increase the buffer size but the problem appear in later frames
 

djsfantasi

Joined Apr 11, 2010
9,163
You increase the buffer size and the problem then appears in a later frame. Is this correct?

Without seeing the code, I would suspect there is a variable that is not being reset or cleared after processing each frame. This could cause the buffer to creep towards its end, until it overflows. Seen that many times.

See if his helps.
 

Thread Starter

Mjd Kassem

Joined Sep 9, 2016
15
You increase the buffer size and the problem then appears in a later frame. Is this correct?

Without seeing the code, I would suspect there is a variable that is not being reset or cleared after processing each frame. This could cause the buffer to creep towards its end, until it overflows. Seen that many times.

See if his helps.
 

Thread Starter

Mjd Kassem

Joined Sep 9, 2016
15
Thanks for quoting me, but did you want to say anything?
Thank you very much this is my code and some terminal output
Code:
#include <avr/io.h>
#include <avr/interrupt.h>
#include <stdbool.h>
#include <stdint.h>
#include <stddef.h>
#include <stdlib.h>

#if defined(_ASSERT_ENABLE_)
#  if defined(TEST_SUITE_DEFINE_ASSERT_MACRO)
// Assert() is defined in unit_test/suite.h
#    include "unit_test/suite.h"
#  else
#    define Assert(expr) \
{\
    if (!(expr)) while (true);\
}
#  endif
#else
#  define Assert(expr) ((void) 0)
#endif

#define BitSet(ADDRESS, BIT) (ADDRESS |= (1<<BIT))

#define F_CPU 11059200
#define USART_BAUDRATE 115200
#define MYUBRR F_CPU / (16L * USART_BAUDRATE) -1
#define TIMER_COMPARE_VALUE 107
#define MAXBYTES 60
#define BUFFER_SIZE 60

struct ring_buffer {
    volatile uint8_t write_offset;
    volatile uint8_t read_offset;
    uint8_t size;
    uint8_t *buffer;
};
//general variable
struct ring_buffer ring_buffer_out;
struct ring_buffer ring_buffer_in;
uint8_t out_buffer[BUFFER_SIZE];
uint8_t in_buffer[BUFFER_SIZE];
uint8_t calibFrame[MAXBYTES];
volatile uint16_t byteCount = 0;
volatile bool timePassed = false;
volatile uint8_t framNumber = 0;

// ring buffer functions implementation
static inline uint8_t get_next(uint8_t cur_offset, uint8_t size)
{
    return (cur_offset == (size - 1) ? 0 : cur_offset + 1);
}
static inline uint8_t ring_buffer_get_next_write(const struct ring_buffer *ring)
{
    return get_next(ring->write_offset, ring->size);
}
static inline uint8_t ring_buffer_get_next_read(const struct ring_buffer *ring)
{
    return get_next(ring->read_offset, ring->size);
}
static inline bool ring_buffer_is_full(const struct ring_buffer *ring)
{
    return (ring->read_offset == ring_buffer_get_next_write(ring));
}
static inline bool ring_buffer_is_empty(const struct ring_buffer *ring)
{
    return (ring->read_offset == ring->write_offset);
}
static inline struct ring_buffer ring_buffer_init(uint8_t *buffer, uint8_t size)
{
    struct ring_buffer ring;
    ring.write_offset = 0;
    ring.read_offset = 0;
    ring.size = size;
    ring.buffer = buffer;
    return ring;
}
static inline uint8_t ring_buffer_get(struct ring_buffer *ring)
{
    Assert(!ring_buffer_is_empty(ring));
    uint8_t data = ring->buffer[ring->read_offset];
    ring->read_offset = ring_buffer_get_next_read(ring);
    return data;
}
static inline void ring_buffer_put(struct ring_buffer *ring, uint8_t data)
{
    Assert(!ring_buffer_is_full(ring));
    ring->buffer[ring->write_offset] = data;
    ring->write_offset = ring_buffer_get_next_write(ring);
}

void Timer1__CTC_Init()
{
    TCCR1B |= (1 << WGM12)|(1 << CS10)|(1 << CS12);
    OCR1A = TIMER_COMPARE_VALUE;
    TCNT1 = 0x00;// initialize counter
    BitSet(TIMSK,OCIE1A);
    sei();
}
void USART_Init(uint8_t ubrr)
{
    UBRR1H = (uint8_t)(ubrr>>8);
    UBRR1L = (uint8_t)ubrr;
    UCSR1B = (1 << RXEN1) | (1 << TXEN1) | (1 << RXCIE1);
    UCSR1C = (1<<UCSZ0)|(1<<UCSZ1);
    ring_buffer_out = ring_buffer_init(out_buffer, BUFFER_SIZE);
    ring_buffer_in = ring_buffer_init(in_buffer, BUFFER_SIZE);
}
void IntilizeDefaultFrame(uint8_t tempArray[])
{
    uint8_t localIndex;
    tempArray[0] = 0xEB;
    tempArray[1] = 0x90;
    tempArray[MAXBYTES - 1] = 0x00;
    for(localIndex = 2 ; localIndex < MAXBYTES -1; localIndex ++)
    {
        tempArray[localIndex] = 0x00;
    }
}
void uart_putchar(uint8_t data)
{
    cli();
    if (ring_buffer_is_empty(&ring_buffer_out))
    {
        UCSR1B |=  (1 << UDRIE1);
    }
    ring_buffer_put(&ring_buffer_out, data);
    sei();
}
//main loop
int main(void)
{
    uint8_t cnt;
    cli();
    Timer1__CTC_Init();
    USART_Init(MYUBRR);
    IntilizeDefaultFrame(calibFrame);
    sei();
    while (1)
    {
        if(timePassed)
        {
            timePassed = false;
            for (cnt = 0; cnt < MAXBYTES; cnt++)
            {
                uart_putchar(calibFrame[cnt]);
            }
            framNumber++;
            if(framNumber == 10) break;
        }
    }
}
//ISRs implementation
ISR(TIMER1_COMPA_vect)
{
    timePassed = true;

}
ISR(USART1_UDRE_vect)
{
    if (!ring_buffer_is_empty(&ring_buffer_out))
     {
        UDR1 = ring_buffer_get(&ring_buffer_out);
        //byteCount++;
     }
     else
     {
         UCSR1B &= ~(1 << UDRIE1);
     }
}
ISR(USART1_RX_vect)
{
    ring_buffer_put(&ring_buffer_in, UDR1);
}
 

Attachments

Last edited:

djsfantasi

Joined Apr 11, 2010
9,163
Thank you very much this is my code and some terminal output
Code:
#include <avr/io.h>
#include <avr/interrupt.h>
#include <stdbool.h>
#include <stdint.h>
#include <stddef.h>
#include <stdlib.h>

#if defined(_ASSERT_ENABLE_)
#  if defined(TEST_SUITE_DEFINE_ASSERT_MACRO)
// Assert() is defined in unit_test/suite.h
#    include "unit_test/suite.h"
#  else
#    define Assert(expr) \
{\
    if (!(expr)) while (true);\
}
#  endif
#else
#  define Assert(expr) ((void) 0)
#endif

#define BitSet(ADDRESS, BIT) (ADDRESS |= (1<<BIT))

#define F_CPU 11059200
#define USART_BAUDRATE 115200
#define MYUBRR F_CPU / (16L * USART_BAUDRATE) -1
#define TIMER_COMPARE_VALUE 107
#define MAXBYTES 60
#define BUFFER_SIZE 60

struct ring_buffer {
    volatile uint8_t write_offset;
    volatile uint8_t read_offset;
    uint8_t size;
    uint8_t *buffer;
};
//general variable
struct ring_buffer ring_buffer_out;
struct ring_buffer ring_buffer_in;
uint8_t out_buffer[BUFFER_SIZE];
uint8_t in_buffer[BUFFER_SIZE];
uint8_t calibFrame[MAXBYTES];
volatile uint16_t byteCount = 0;
volatile bool timePassed = false;
volatile uint8_t framNumber = 0;

// ring buffer functions implementation
static inline uint8_t get_next(uint8_t cur_offset, uint8_t size)
{
    return (cur_offset == (size - 1) ? 0 : cur_offset + 1);
}
static inline uint8_t ring_buffer_get_next_write(const struct ring_buffer *ring)
{
    return get_next(ring->write_offset, ring->size);
}
static inline uint8_t ring_buffer_get_next_read(const struct ring_buffer *ring)
{
    return get_next(ring->read_offset, ring->size);
}
static inline bool ring_buffer_is_full(const struct ring_buffer *ring)
{
    return (ring->read_offset == ring_buffer_get_next_write(ring));
}
static inline bool ring_buffer_is_empty(const struct ring_buffer *ring)
{
    return (ring->read_offset == ring->write_offset);
}
static inline struct ring_buffer ring_buffer_init(uint8_t *buffer, uint8_t size)
{
    struct ring_buffer ring;
    ring.write_offset = 0;
    ring.read_offset = 0;
    ring.size = size;
    ring.buffer = buffer;
    return ring;
}
static inline uint8_t ring_buffer_get(struct ring_buffer *ring)
{
    Assert(!ring_buffer_is_empty(ring));
    uint8_t data = ring->buffer[ring->read_offset];
    ring->read_offset = ring_buffer_get_next_read(ring);
    return data;
}
static inline void ring_buffer_put(struct ring_buffer *ring, uint8_t data)
{
    Assert(!ring_buffer_is_full(ring));
    ring->buffer[ring->write_offset] = data;
    ring->write_offset = ring_buffer_get_next_write(ring);
}

void Timer1__CTC_Init()
{
    TCCR1B |= (1 << WGM12)|(1 << CS10)|(1 << CS12);
    OCR1A = TIMER_COMPARE_VALUE;
    TCNT1 = 0x00;// initialize counter
    BitSet(TIMSK,OCIE1A);
    sei();
}
void USART_Init(uint8_t ubrr)
{
    UBRR1H = (uint8_t)(ubrr>>8);
    UBRR1L = (uint8_t)ubrr;
    UCSR1B = (1 << RXEN1) | (1 << TXEN1) | (1 << RXCIE1);
    UCSR1C = (1<<UCSZ0)|(1<<UCSZ1);
    ring_buffer_out = ring_buffer_init(out_buffer, BUFFER_SIZE);
    ring_buffer_in = ring_buffer_init(in_buffer, BUFFER_SIZE);
}
void IntilizeDefaultFrame(uint8_t tempArray[])
{
    uint8_t localIndex;
    tempArray[0] = 0xEB;
    tempArray[1] = 0x90;
    tempArray[MAXBYTES - 1] = 0x00;
    for(localIndex = 2 ; localIndex < MAXBYTES -1; localIndex ++)
    {
        tempArray[localIndex] = 0x00;
    }
}
void uart_putchar(uint8_t data)
{
    cli();
    if (ring_buffer_is_empty(&ring_buffer_out))
    {
        UCSR1B |=  (1 << UDRIE1);
    }
    ring_buffer_put(&ring_buffer_out, data);
    sei();
}
//main loop
int main(void)
{
    uint8_t cnt;
    cli();
    Timer1__CTC_Init();
    USART_Init(MYUBRR);
    IntilizeDefaultFrame(calibFrame);
    sei();
    while (1)
    {
        if(timePassed)
        {
            timePassed = false;
            for (cnt = 0; cnt < MAXBYTES; cnt++)
            {
                uart_putchar(calibFrame[cnt]);
            }
            framNumber++;
            if(framNumber == 10) break;
        }
    }
}
//ISRs implementation
ISR(TIMER1_COMPA_vect)
{
    timePassed = true;

}
ISR(USART1_UDRE_vect)
{
    if (!ring_buffer_is_empty(&ring_buffer_out))
     {
        UDR1 = ring_buffer_get(&ring_buffer_out);
        //byteCount++;
     }
     else
     {
         UCSR1B &= ~(1 << UDRIE1);
     }
}
ISR(USART1_RX_vect)
{
    ring_buffer_put(&ring_buffer_in, UDR1);
}
Need to get to a laptop to read the code. On iPhone now
 
Top