SAM4S Xplained Pro UART and USART (examples with Interrupts)

Recently I was in need to get two separate UARTS from the SAM4S Xpro board. It took me a while, but I finally figured out how to use the USART1 with interrupts; and since I already had working code for UART1, I decided to post examples for both.

 

UART1

UART1 is exposed in pins 13 and 14 in EXT3, and also in the Debug USB port. It requires the UART – Univ. Async Rec/Trans (driver) ASF module. For this example I’m using the code from here, without any modification.

 

USART1

USART1 is exposed in pins 13 and 14 in EXT1 and EXT2. It requires the USART – Univ. Synch Async Rec/Trans (driver) ASF module. Other modules that may be using it must be removed, or else you get a USART1_Handler redefined error. Most of the code for this example is from the ASF documentation, but it was missing  a configuration step of USART1 pins. Also it had what it seemed to be a mistake; in the call to usart_init_rs232, I replaced sysclk_get_main_hz() for sysclk_get_peripheral_hz(), and that fixed it. The working code is in the downloads.

 

Demo

 

Downloads

UART1 Example

Download

USART1 Example

Download
By |2016-09-12T00:12:07+00:00June 18th, 2016|Prototyping, SAM4S Xpro|10 Comments

10 Comments

  1. […] Pro, you could use the pins labeled Rx, Tx, Gnd, and VTG in the IO1 board (Not sure why? See here or check the SAM4s Xpro User […]

  2. shivam keshri May 24, 2018 at 7:07 am - Reply

    thanks it helpful for beginners

    • Rafael Roman Otero June 4, 2018 at 3:52 am - Reply

      Welcome!

      • Raphael September 25, 2018 at 3:38 pm - Reply

        Hi, I’ve set my IDE and put the USART code into my main.c file. I also modified it for it to work on USART0, because that’s the routed USART on my board. It compiles but doesn’t not do what is shown on your video… If you want you cant show what I’ve done on the StackOverFlow forum :
        https://stackoverflow.com/questions/52501455/cant-send-and-receive-data-from-my-own-usart-sam4sd16c

        • Rafael Roman Otero September 26, 2018 at 3:19 am - Reply

          I’ve never really tried working with RS485, sorry. That being said, if I had to make the example work for RS485. I’d check on the datasheet more details about the RS485 and I’d adjust these values:

          #define PINS_USART1_PIO PIOA
          #define PINS_USART1_ID ID_USART1
          #define PINS_USART1_TYPE PIO_PERIPH_A
          #define PINS_USART1_ATTR PIO_DEFAULT
          #define PINS_USART1_MASK (PIO_PA21A_RXD1| PIO_PA22A_TXD1 )

          They’re device specific. I’m sure different serial devices have different PIO, ID, TYPE, ATTR, and MASK.

          Then I would also remove

          while(US_CSR_TXRDY != 0 );

          Just to see what happens.

          Good Luck

          Rafael

  3. eder October 15, 2018 at 6:19 pm - Reply

    hello I’m trying to use your second example of port usart but it does not work, on pins 13 and 14 I enter the signal of a small gps but in terminal windows I can not visualize anything, I hope you can support me, thanks.
    I am using the following code:

    #include

    #define USART_SERIAL USART1
    #define USART_SERIAL_ID ID_USART1
    #define USART_SERIAL_BAUDRATE 115200
    #define USART_SERIAL_CHAR_LENGTH US_MR_CHRL_8_BIT
    #define USART_SERIAL_PARITY US_MR_PAR_NO
    #define USART_SERIAL_STOP_BIT US_MR_NBSTOP_1_BIT

    #define PINS_USART1_PIO PIOA
    #define PINS_USART1_ID ID_USART1
    #define PINS_USART1_TYPE PIO_PERIPH_A
    #define PINS_USART1_ATTR PIO_DEFAULT
    #define PINS_USART1_MASK (PIO_PA21A_RXD1| PIO_PA22A_TXD1 )

    uint32_t received_byte;

    void main(void){

    sysclk_init();
    board_init();

    pio_configure(PINS_USART1_PIO, PINS_USART1_TYPE, PINS_USART1_MASK, PINS_USART1_ATTR);
    pmc_enable_periph_clk(ID_USART1);

    const sam_usart_opt_t usart_console_settings = {
    USART_SERIAL_BAUDRATE,
    USART_SERIAL_CHAR_LENGTH,
    USART_SERIAL_PARITY,
    USART_SERIAL_STOP_BIT,
    US_MR_CHMODE_NORMAL
    };

    sysclk_enable_peripheral_clock(USART_SERIAL_ID);

    usart_init_rs232(USART_SERIAL, &usart_console_settings, sysclk_get_peripheral_hz());
    usart_enable_tx(USART_SERIAL);
    usart_enable_rx(USART_SERIAL);
    usart_enable_interrupt(USART_SERIAL, US_IER_RXRDY);
    NVIC_EnableIRQ(USART1_IRQn);

    //usart_write(USART_SERIAL, 1);

    while(1){

    USART1_Handler();
    }
    }

    void USART1_Handler(void){

    uint32_t dw_status = usart_get_status(USART1);
    if (dw_status & US_CSR_RXRDY) {
    uint8_t received_byte;
    usart_read(USART1, &received_byte);
    usart_write(USART1, received_byte+1);
    }
    }

    • Rafael Roman Otero October 16, 2018 at 6:00 am - Reply

      Hi Eder, I can’t tell for sure without debugging, but from a quick look at your code I see two problem:

      while(1){
      USART1_Handler();
      }

      USART1_Handler is a handler exception, so you don’t need to call it like a function. USART1_Handler will run when a new character is received on USART1.

      The second problem that I see is that in USART1_Handler you’re calling:

      usart_write(USART1, received_byte+1);

      that line is from the example. You probably don’t want to do that. I assume you’ll only be receiving data from the GPS, so you probably only need usart_read.

      Lastly, if your GPS works like most other IO devices, you’ll need to “send” some configuation to the GPS before you start receiving data from it (maybe not, I can’t tell).

      Anyway, Good luck

      Rafael

  4. francisco November 1, 2018 at 2:14 am - Reply

    hello good day, I am programming the port to use for a gps, but since I can separate each character that I receive through the usart port of a gps, try in the while loop but only the first character always guaranties me, the signal I am receiving it to 9600 baud, also try to put a delay of 1140 us, which represent 8 bits of the data plus a start bit and plus a stop bit (10 bits), in the spec sheet of the microcontroller indicates 104 us that it takes a single bit to be transmitted,
    in the lcd I am showing hour (h: m: s), but the seconds are not saved in a correct way sometimes some jumps are noticed is not continuous.

    #include
    #include “stdio_serial.h”
    #include “asf.h”
    #include “stdio_serial.h”
    #include “conf_board.h”
    #include “conf_clock.h”
    #include “conf_uart_serial.h”

    #define USART_SERIAL USART1
    #define USART_SERIAL_ID ID_USART1
    #define USART_SERIAL_BAUDRATE 9600
    #define USART_SERIAL_CHAR_LENGTH US_MR_CHRL_8_BIT
    #define USART_SERIAL_PARITY US_MR_PAR_NO
    #define USART_SERIAL_STOP_BIT US_MR_NBSTOP_1_BIT

    #define PINS_USART1_PIO PIOA
    #define PINS_USART1_ID ID_USART1
    #define PINS_USART1_TYPE PIO_PERIPH_A
    #define PINS_USART1_ATTR PIO_DEFAULT
    #define PINS_USART1_MASK (PIO_PA21A_RXD1| PIO_PA22A_TXD1 )

    char letra(uint8_t entrada);

    char dia[2];
    char mes[2];
    char anio[4];
    char hr[2];
    char minuto[2];
    char seg[2];

    char text[30];
    uint8_t rx[50];
    uint8_t received_byte;

    int i=0;

    void main(void){

    sysclk_init();
    board_init();
    ssd1306_init();
    ssd1306_clear();

    uint32_t seconds;
    uint32_t minutes;
    uint32_t hours;

    pio_configure(PINS_USART1_PIO, PINS_USART1_TYPE, PINS_USART1_MASK, PINS_USART1_ATTR);
    pmc_enable_periph_clk(ID_USART1);

    const sam_usart_opt_t usart_console_settings = {
    USART_SERIAL_BAUDRATE,
    USART_SERIAL_CHAR_LENGTH,
    USART_SERIAL_PARITY,
    USART_SERIAL_STOP_BIT,
    US_MR_CHMODE_NORMAL
    };

    sysclk_enable_peripheral_clock(USART_SERIAL_ID);

    usart_init_rs232(USART_SERIAL, &usart_console_settings, sysclk_get_peripheral_hz());
    usart_enable_tx(USART_SERIAL);
    usart_enable_rx(USART_SERIAL);
    usart_enable_interrupt(USART_SERIAL, US_IER_RXRDY);
    NVIC_EnableIRQ(USART1_IRQn);

    while(1){

    for(i=0;i<30;i++)
    {
    rx[i]=received_byte;
    //delay_us(10000);
    delay_us(1040);
    //delay_ms();
    }

    ssd1306_set_page_address(0);
    ssd1306_set_column_address(0);

    for (i=0;i> %02d:%02d:%02d”,hhh, mmm, sss);
    ssd1306_write_text(text);

    }
    }

    }

    }

    void USART1_Handler(void)
    {

    uint32_t dw_status = usart_get_status(USART_SERIAL);

    // if (dw_status & US_CSR_RXRDY) {
    //

    usart_getchar(USART_SERIAL, &received_byte);

    //usart_write(USART_SERIAL, received_byte);

    //}

    }

  5. francisco November 1, 2018 at 2:16 am - Reply

    Sorry, the code was not copied well.

    #include
    #include “stdio_serial.h”
    #include “asf.h”
    #include “stdio_serial.h”
    #include “conf_board.h”
    #include “conf_clock.h”
    #include “conf_uart_serial.h”

    #define USART_SERIAL USART1
    #define USART_SERIAL_ID ID_USART1
    #define USART_SERIAL_BAUDRATE 9600
    #define USART_SERIAL_CHAR_LENGTH US_MR_CHRL_8_BIT
    #define USART_SERIAL_PARITY US_MR_PAR_NO
    #define USART_SERIAL_STOP_BIT US_MR_NBSTOP_1_BIT

    #define PINS_USART1_PIO PIOA
    #define PINS_USART1_ID ID_USART1
    #define PINS_USART1_TYPE PIO_PERIPH_A
    #define PINS_USART1_ATTR PIO_DEFAULT
    #define PINS_USART1_MASK (PIO_PA21A_RXD1| PIO_PA22A_TXD1 )

    char letra(uint8_t entrada);

    char dia[2];
    char mes[2];
    char anio[4];
    char hr[2];
    char minuto[2];
    char seg[2];

    char text[30];
    uint8_t rx[50];
    uint8_t received_byte;

    int i=0;

    void main(void){

    sysclk_init();
    board_init();
    ssd1306_init();
    ssd1306_clear();

    uint32_t seconds;
    uint32_t minutes;
    uint32_t hours;

    pio_configure(PINS_USART1_PIO, PINS_USART1_TYPE, PINS_USART1_MASK, PINS_USART1_ATTR);
    pmc_enable_periph_clk(ID_USART1);

    const sam_usart_opt_t usart_console_settings = {
    USART_SERIAL_BAUDRATE,
    USART_SERIAL_CHAR_LENGTH,
    USART_SERIAL_PARITY,
    USART_SERIAL_STOP_BIT,
    US_MR_CHMODE_NORMAL
    };

    sysclk_enable_peripheral_clock(USART_SERIAL_ID);

    usart_init_rs232(USART_SERIAL, &usart_console_settings, sysclk_get_peripheral_hz());
    usart_enable_tx(USART_SERIAL);
    usart_enable_rx(USART_SERIAL);
    usart_enable_interrupt(USART_SERIAL, US_IER_RXRDY);
    NVIC_EnableIRQ(USART1_IRQn);

    while(1){

    for(i=0;i<30;i++)
    {
    rx[i]=received_byte;
    //delay_us(10000);
    delay_us(1040);
    //delay_ms();
    }

    ssd1306_set_page_address(0);
    ssd1306_set_column_address(0);

    for (i=0;i> %02d:%02d:%02d”,hhh, mmm, sss);
    ssd1306_write_text(text);

    }
    }

    }

    }

    void USART1_Handler(void)
    {

    uint32_t dw_status = usart_get_status(USART_SERIAL);

    // if (dw_status & US_CSR_RXRDY) {
    //

    usart_getchar(USART_SERIAL, &received_byte);

    //usart_write(USART_SERIAL, received_byte);

    //}

    }

    • Rafael Roman Otero November 1, 2018 at 3:09 am - Reply

      Hi Francisco,

      I see a few problems. First, this line is a mixed of a for loop with an sprintf (I’m not even sure that compiles):

      for (i = 0; i > % 02 d: % 02 d: % 02 d”, hhh, mmm, sss);

      Second, you need to be careful what you send to print in this line:

      ssd1306_write_text(text);

      I’d need to check but I think ssd1306_write_text(text) will print eveything in text up to the null character ‘/0’. So make sure you null-terminate text.

      Third, exception Handlers and main run asynchronously (i.e. each it’s doing its own thing at their own pace), so you have to take that into consideration when writing your main. In particular, if possible try to avoid assuming a particular timing.

      I was thinking something like this:

      main(){
      while(true){
      if(signal){
      signal=false;
      print(rx)
      }
      }
      }

      global rx;
      global i;

      handler(){
      read_usart(&c)
      rx[i++] = c;

      if( i >= 30){ //I’m assuming you only want to print after receiving 30 characters
      signal = true;
      i = 0;
      }
      }

      If you prefer, there’s a more general approach to processing data coming from exception handlers. Namely with a queue:
      (I prefer this method because it decouples the producer of the data, i.e. the exception handler, from the consumer of the data, i.e. main…
      data will get process as it becomes available)

      main(){
      while(true){
      if( queue_size() > 0 ){
      new_item = queue_read()
      process(new_item); //here’s where you don whatever you want to do with the new item
      }
      }
      }

      handler(){
      data = read_from_usart():
      queue_put(data) //send data to
      }

      Hope it helps. Good luck!

      Regards,
      Rafael

Leave A Comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.