SAMD21 USART Problem with Transmit

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

Hello, I am trying to use the USART module on the SAMD21. I put together a simple example leveraging code from an app note) where I receive data and then I echo it back out. I can setup it up to receive data, using the Atmel ICE debugger I see the data come in. But I cannot get it to transmit. Below is my code any help would be greatly appreciated.

 

<

#include <asf.h>
#define USART_BAUD_RATE 9600
#define USART_SAMPLE_NUM 16
#define SHIFT 32

 

/* function prototype */
void usart_clock_init(void);
void usart_pin_init(void);
void usart_init(void);
void ext_usart_clock_init(void);
void ext_usart_pin_init(void);
void ext_usart_init(void);
uint16_t calculate_baud_value(const uint32_t baudrate,const uint32_t peripheral_clock, uint8_t sample_num);

 

volatile uint8_t edbg_rx_data,ext_rx_data;

volatile bool nData = false;

 

int main (void)
{
    system_init();
    ext_usart_clock_init();
    ext_usart_pin_init();
    ext_usart_init();
    
    while(1) {
 
    }
}

 

/*ext_usart handler*/
void SERCOM5_Handler()
{
    if (SERCOM5->USART.INTFLAG.bit.RXC){
        ext_rx_data = SERCOM5->USART.DATA.reg;
        //if (SERCOM5->USART.INTFLAG.bit.DRE)
        //{
        while(!SERCOM5->USART.INTFLAG.bit.DRE);
        SERCOM5->USART.DATA.reg = (uint16_t)ext_rx_data;
        //}
    }
}

 

/*Assigning pin to the alternate peripheral function*/
static inline void pin_set_peripheral_function(uint32_t pinmux)
{
    uint8_t port = (uint8_t)((pinmux >> 16)/32);
    PORT->Group[port].PINCFG[((pinmux >> 16) - (port*32))].bit.PMUXEN = 1;
    PORT->Group[port].PMUX[((pinmux >> 16) - (port*32))/2].reg &= ~(0xF << (4 * ((pinmux >>
    16) & 0x01u)));
    PORT->Group[port].PMUX[((pinmux >> 16) - (port*32))/2].reg |= (uint8_t)((pinmux &
    0x0000FFFF) << (4 * ((pinmux >> 16) & 0x01u)));
}

 

/*
* internal Calculate 64 bit division, ref can be found in
* http://en.wikipedia.org/wiki/Div...
*/
static uint64_t long_division(uint64_t n, uint64_t d)
{
    int32_t i;
    uint64_t q = 0, r = 0, bit_shift;
    for (i = 63; i >= 0; i--) {
        bit_shift = (uint64_t)1 << i;
        r = r << 1;
        if (n & bit_shift) {
            r |= 0x01;
        }
        if (r >= d) {
            r = r - d;
            q |= bit_shift;
        }
    }
    return q;
}

 

/*
* \internal Calculate asynchronous baudrate value (UART)
*/
uint16_t calculate_baud_value(const uint32_t baudrate, const uint32_t peripheral_clock, uint8_t sample_num)
{
    /* Temporary variables */
    uint64_t ratio = 0;
    uint64_t scale = 0;
    uint64_t baud_calculated = 0;
    uint64_t temp1;
    /* Calculate the BAUD value */
    temp1 = ((sample_num * (uint64_t)baudrate) << SHIFT);
    ratio = long_division(temp1, peripheral_clock);
    scale = ((uint64_t)1 << SHIFT) - ratio;
    baud_calculated = (65536 * scale) >> SHIFT;
    return baud_calculated;
} /* UART(SERCOM0) bus and generic clock initialization */
void usart_clock_init(void)
{
    struct system_gclk_chan_config gclk_chan_conf;
    uint32_t gclk_index = SERCOM0_GCLK_ID_CORE;
    /* Turn on module in PM */
    system_apb_clock_set_mask(SYSTEM_CLOCK_APB_APBC, PM_APBCMASK_SERCOM0);
    /* Turn on Generic clock for USART */
    system_gclk_chan_get_config_defaults(&gclk_chan_conf);
    /*Default is generator 0. Other wise need to configure like below */
    /* gclk_chan_conf.source_generator = GCLK_GENERATOR_1; */
    system_gclk_chan_set_config(gclk_index, &gclk_chan_conf);
    system_gclk_chan_enable(gclk_index);
}

 

/* (SERCOM5) UART bus and generic clock initialization */
void ext_usart_clock_init(void)
{
    struct system_gclk_chan_config gclk_chan_conf;
    uint32_t gclk_index = SERCOM5_GCLK_ID_CORE;
    /* Turn on module in PM */
    system_apb_clock_set_mask(SYSTEM_CLOCK_APB_APBC, PM_APBCMASK_SERCOM5);
    /* Turn on Generic clock for USART */
    system_gclk_chan_get_config_defaults(&gclk_chan_conf);
    //Default is generator 0. Other wise need to configure like below
    /* gclk_chan_conf.source_generator = GCLK_GENERATOR_1; */
    system_gclk_chan_set_config(gclk_index, &gclk_chan_conf);
    system_gclk_chan_enable(gclk_index);
}

 

/*(SERCOM5) pin initialization */
void ext_usart_pin_init(void)
{
    pin_set_peripheral_function(PINMUX_PB22D_SERCOM5_PAD2);     

    pin_set_peripheral_function(PINMUX_PB23D_SERCOM5_PAD3);
}

 

/*(SERCOM5) UART initialization */
void ext_usart_init(void)
{
    uint16_t baud_value;
    baud_value = calculate_baud_value(USART_BAUD_RATE,system_gclk_chan_get_hz(SERCOM5_GCLK_ID_CORE),
    USART_SAMPLE_NUM);
    
    SERCOM5->USART.CTRLA.reg = SERCOM_USART_CTRLA_DORD |
    SERCOM_USART_CTRLA_RXPO(0x3) |
    SERCOM_USART_CTRLA_TXPO(0x2) |
    SERCOM_USART_CTRLA_SAMPR(0x0)|
    SERCOM_USART_CTRLA_RUNSTDBY |
    SERCOM_USART_CTRLA_MODE_USART_INT_CLK ;
    /* baud register value corresponds to the device communication baud rate */
    SERCOM5->USART.BAUD.reg = baud_value;
    /* 8-bits size is selected as character size by setting the bit CHSIZE as 0,
    TXEN bit and RXEN bits are set to enable the Transmitter and receiver*/
    SERCOM5->USART.CTRLB.reg = SERCOM_USART_CTRLB_CHSIZE(0x0) |
    SERCOM_USART_CTRLB_TXEN |
    SERCOM_USART_CTRLB_RXEN ;
    /* synchronization busy */
    while(SERCOM5->USART.SYNCBUSY.bit.CTRLB);
    /* SERCOM2 handler enabled */
    system_interrupt_enable(SERCOM5_IRQn);
    /* receive complete interrupt set */
    SERCOM5->USART.INTENSET.reg = SERCOM_USART_INTFLAG_RXC;
    /* SERCOM2 peripheral enabled */
    SERCOM5->USART.CTRLA.reg |= SERCOM_USART_CTRLA_ENABLE;
    /* synchronization busy */
    while(SERCOM5->USART.SYNCBUSY.reg & SERCOM_USART_SYNCBUSY_ENABLE);
}>

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
SERCOM_USART_CTRLA_TXPO(0x2)

This gives you TX on PAD0, the value should be 1 for TX on PAD2.

/Lars

 

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

I had an issue with muxing a SERCOM on the D5x/E5x parts, and it turns out you can ONLY put TX on PAD0 of an IOSET (for that MCU family)

 

I don't know if this is applicable to the D2x family... I would be curious what you find out.

 

Related thread:  https://community.atmel.com/forum/same51-problems-muxing-sercom

murph

Debugging - Being a detective in a crime movie where you are also the murderer.

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

Thank you Lars

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

I don't have answer for you, but I am going to review how the pads work because obviously I did not understand them correctly based on Lars's correction. Will let you know if I learn anything.