SAMD20 USART read callback issue

Go To Last Post
4 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi,

I need to interface my SAMD20 with another module through UART.

My approach is to call usart_read_job() in the main loop, so that anytime a new byte is received, the usart_read_callback() is invoked (I'm using this because I don't know how many bytes I could receive at a time, so the callback could not always be triggered).

Within such callback, I just append the received byte to a buffer and call usart_read_job() again to catch new bytes.

 

To test correct functioning, I'm transmitting 5 bytes from a serial terminal (Docklight) to the SAMD20, and reading them back once the 5th byte is received.

Everything is ok when I insert the 5 bytes manually (one by one): when the SAMD20 receives the 8th byte, it sends back the content of the buffer, with correct values.

However, when I transmit a predefined 5 bytes packet at a time (which is more likely what the external module would do (e.g. when it sends 'ERROR' after a command), the only correct byte is the first one, while others are messed up.

 

I was suspecting that the callback execution could cause delays in UART bytes parsing, but I've tried to slow down the baud rate from 9600 to even 110, and the result is exactly the same.

 

Any idea? Thank you in advance!

Last Edited: Fri. Mar 20, 2020 - 05:37 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Couple of examples (where TX is what I send from PC terminal, and RX is what I get back from SAMD20):
 

[TX]: 0x31 0x32 0x33 0x34 0x35

[RX]: 0x31 0xA6 0xA2 0x35

 

or

 

[TX]: 0x31 0x00 0x32 0x00 0x33

[RX]: 0x31 0x32 0x33

 

The rx values are not random (they always correspond to the same tx sequence) and do not change regardless of the baud rate.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The approach you outline has worked for me. Maybe you need to show the code. Anyway here is an example reading line by line and it keeps up when sending a text file from a PC terminal program at 115200 baud. For testing I put a break point at the 

            n_lines = 0;

i.e., when 100 lines are read.

/Lars

 

#include <asf.h>
#include <stdio.h>
#include <ctype.h>
#include <string.h>

bool get_line(char* buffer, size_t buf_size, size_t timeout_ms);
void usart_read_callback(struct usart_module *const usart_module);
void configure_usart(void);
void configure_usart_callbacks(void);

struct usart_module usart_instance;
char line_buffer[120];
char done_buffer[120];
char rx_buffer;
volatile bool line_buffered = false;

void usart_read_callback(struct usart_module *const usart_module)
{
    static size_t line_idx = 0;
    if (line_idx > 0 || !isspace(rx_buffer)) {
        if (rx_buffer == '\r' || rx_buffer == '\n') {
            memcpy(done_buffer, line_buffer, line_idx);
            done_buffer[line_idx] = '\0';
            line_buffered = true;
            line_idx = 0;
        }
        else if (line_idx < sizeof(line_buffer) - 1) {
            line_buffer[line_idx++] = rx_buffer;
        }
    }
    usart_read_buffer_job(&usart_instance, (uint8_t*)&rx_buffer, 1);
}

bool get_line(char* buffer, size_t buf_size, size_t timeout_ms)
{
    while(!line_buffered) {
        if (timeout_ms == 0) {
            return false;
        }
        delay_ms(1);
        timeout_ms--;
    }	
    line_buffered = false;
    strncpy(buffer, done_buffer, buf_size);
    return true;
}

void configure_usart(void)
{
    struct usart_config config_usart;
    usart_get_config_defaults(&config_usart);

    config_usart.baudrate    = 115200;
    config_usart.mux_setting = EDBG_CDC_SERCOM_MUX_SETTING;
    config_usart.pinmux_pad0 = EDBG_CDC_SERCOM_PINMUX_PAD0;
    config_usart.pinmux_pad1 = EDBG_CDC_SERCOM_PINMUX_PAD1;
    config_usart.pinmux_pad2 = EDBG_CDC_SERCOM_PINMUX_PAD2;
    config_usart.pinmux_pad3 = EDBG_CDC_SERCOM_PINMUX_PAD3;
    while (usart_init(&usart_instance, EDBG_CDC_MODULE, &config_usart) != STATUS_OK) {
    }
    usart_enable(&usart_instance);
}

void configure_usart_callbacks(void)
{
    usart_register_callback(&usart_instance,
            usart_read_callback, USART_CALLBACK_BUFFER_RECEIVED);
    usart_enable_callback(&usart_instance, USART_CALLBACK_BUFFER_RECEIVED);
}

char test_lines[100][80];
int main(void)
{
    system_init();
    delay_init();
    
    configure_usart();
    configure_usart_callbacks();
    system_interrupt_enable_global();
    usart_read_buffer_job(&usart_instance, (uint8_t*)&rx_buffer, 1);

    size_t n_lines = 0;
    while (true) {
        if (n_lines < 100) {
            if (get_line(test_lines[n_lines], sizeof(test_lines[n_lines]), 0)) {
                n_lines++;
            }
        }
        else {
            n_lines = 0;
        }
    }
}

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thank you for sharing your code Lars. Before trying it, I've started a brand new project, and my same code now works fine. I guess in the previous project I've changed something I forgot to put back at its place.

However, thanks again for your support!

 

Best regards

Lorenzo