SAMD20E18A UART (No ASF)

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

Hi all,

 

I am working on a project which requires UART. One of my problems is the following: For some reason, th e handler seems to hold up the rest of the code (main while loop) and not let it do anything. My code is the following:

 

//Code for smart driver module
//Objective: To communicate module over radio to control dimming
#include <samd20.h>

#define PORTA   0
#define PORTB   1

#define true    1
#define false   0

#define N   3 //PM tx buffer
#define I   3

//Function initialization
void CLK_Setup(void);
void DAC_Setup(void);
void UART_Setup_SERCOM3(void);
void UART_Setup_SERCOM0(void);
//*******************************************************************************************

void Sys_Init(void){
    CLK_Setup();
    DAC_Setup();
    UART_Setup_SERCOM3();
    UART_Setup_SERCOM0();
}
//Global variable declaration

volatile uint8_t Rx_buff[I];
int i =0;
int i2=0;
int packet_ok = false;
uint32_t timeout = 0;
volatile uint8_t Tx_Data[N];
uint8_t Rx_Data[I] = {10,2,4};
int data_ready = true;

void SERCOM3_Handler(void){
    if(SERCOM3->USART.INTFLAG.reg =  SERCOM_USART_INTFLAG_RXC){
        Rx_Data[i] = SERCOM3->USART.DATA.reg;
        i++;
        if(i >= 20) {
            packet_ok=true;
            i=0;
            
        }
    }
}
int receive_bgn=0;

void SERCOM0_Handler(void){
    
    
    
}
// Main code write
int main(void)
{
    //Interrupt startup
    NVIC_EnableIRQ( SERCOM0_IRQn );
    NVIC_EnableIRQ( SERCOM3_IRQn );

    //Local variables
    uint8_t Data_MSB, Data_LSB;
    uint8_t DAC_Out;

    SystemInit(); // Initialize the SAM system
    Sys_Init(); //Peripheral initializatiob

    Tx_Data[0] = 0xFE;
    Tx_Data[1] = 0b11001001;
    Tx_Data[2] = 0b01001001;

        
    while(1){
        
        DAC->DATABUF.reg = 0x3ff&(0x3ff);

        
     }   

        
}

 

//Peripheral initialization
void CLK_Setup(void){
    NVMCTRL->CTRLB.bit.RWS = NVMCTRL_CTRLB_RWS_HALF_Val; // 1 wait state for operating at 2.7-3.3V at 48MHz
    PM->APBAMASK.bit.GCLK_ = true;
    GCLK->CTRL.bit.SWRST = true;
    while (GCLK->CTRL.bit.SWRST && GCLK->STATUS.bit.SYNCBUSY) {};
    // 2. Make sure the OCM8M keeps running.)

    SYSCTRL->OSC8M.bit.ONDEMAND = 0;
    GCLK->GENDIV.reg =
    GCLK_GENDIV_ID(3) | // Select generator 3
    GCLK_GENDIV_DIV(64); // Set the division factor to 64
    GCLK->GENCTRL.reg =
        GCLK_GENCTRL_ID(3) | // Select generator 3
        GCLK_GENCTRL_SRC_OSC8M | // Select source OSC8M
        GCLK_GENCTRL_GENEN; // Enable this generic clock generator
    while (GCLK->STATUS.bit.SYNCBUSY) {}; // Wait for synchronization
    // 5. Configure DFLL with the
    GCLK->CLKCTRL.reg =
        GCLK_CLKCTRL_ID_DFLL48M | // Target is DFLL48M
        GCLK_CLKCTRL_GEN(3) | // Select generator 3 as source.
        GCLK_CLKCTRL_CLKEN; // Enable the DFLL48M
    while (GCLK->STATUS.bit.SYNCBUSY) {}; // Wait for synchronization
    // 6. Workaround to be able to configure the DFLL.
    SYSCTRL->DFLLCTRL.bit.ONDEMAND = false;
    while (!SYSCTRL->PCLKSR.bit.DFLLRDY) {}; // Wait for synchronization.
    // 7. Change the multiplication factor.
    SYSCTRL->DFLLMUL.bit.MUL = 3072; // 48MHz / (1MHz / 64)
    SYSCTRL->DFLLMUL.bit.CSTEP = 1; // Coarse step = 1
    SYSCTRL->DFLLMUL.bit.FSTEP = 1; // Fine step = 1
    while (!SYSCTRL->PCLKSR.bit.DFLLRDY) {}; // Wait for synchronization.
    SYSCTRL->DFLLCTRL.reg |=
        SYSCTRL_DFLLCTRL_MODE | // 1 = Closed loop mode.
        SYSCTRL_DFLLCTRL_QLDIS; // 1 = Disable quick lock.
    while (!SYSCTRL->PCLKSR.bit.DFLLRDY) {}; // Wait for synchronization.
    SYSCTRL->INTFLAG.bit.DFLLLCKC = 1;
    SYSCTRL->INTFLAG.bit.DFLLLCKF = 1;
    SYSCTRL->INTFLAG.bit.DFLLRDY = 1;
    // 10. Enable the DFLL
    SYSCTRL->DFLLCTRL.bit.ENABLE = true;
    while (!SYSCTRL->PCLKSR.bit.DFLLRDY) {}; // Wait for synchronization.
    // 11. Wait for the fine and coarse locks.
    while (!SYSCTRL->INTFLAG.bit.DFLLLCKC && !SYSCTRL->INTFLAG.bit.DFLLLCKF) {};
    // 12. Wait until the DFLL is ready.
    while (!SYSCTRL->INTFLAG.bit.DFLLRDY) {};
    GCLK->GENDIV.reg =
        GCLK_GENDIV_ID(0) | // Select generator 0
        GCLK_GENDIV_DIV(0);
    while (GCLK->STATUS.bit.SYNCBUSY) {}; // Wait for synchronization       
    // 2. Switch generic clock 0 to the DFLL
    GCLK->GENCTRL.reg =
        GCLK_GENCTRL_ID(0) | // Select generator 0
        GCLK_GENCTRL_SRC_DFLL48M | // Select source DFLL
        GCLK_GENCTRL_IDC | // Set improved duty cycle 50/50
        GCLK_GENCTRL_GENEN; // Enable this generic clock generator
    while (GCLK->STATUS.bit.SYNCBUSY) {}; // Wait for synchronization

}

#define F_CPU 48000000   // 48MHz source clock
                         // Baud rate depends on source clock frequency

void UART_Setup_SERCOM3(void){

    uint32_t baud = 9600;
    
    // FBAUD = ( fREF/ S) (1 – BAUD/65,536)
    // FBAUD = baud frequency
    // fref – SERCOM generic clock frequency
    // S – Number of samples per bit
    // BAUD – BAUD register value
    uint64_t br = (uint64_t)65536 * (F_CPU - 16 * baud) / F_CPU;    // Variable for baud rate

    PORT->Group[PORTA].DIRSET.reg = (1 << 22);                          // Set TX Pin direction to output
    PORT->Group[PORTA].PINCFG[22].reg |= PORT_PINCFG_INEN;              // Set TX Pin config for input enable (required for usart)
    PORT->Group[PORTA].PINCFG[22].reg |= PORT_PINCFG_PMUXEN;            // enable PMUX
    PORT->Group[PORTA].PMUX[22>>1].bit.PMUXE = PORT_PMUX_PMUXE_C_Val;   // Set the PMUX bit (if pin is even, PMUXE, if odd, PMUXO)
    
    PORT->Group[PORTA].DIRCLR.reg = (1 << 23);                          // Set RX Pin direction to input
    PORT->Group[PORTA].PINCFG[23].reg |= PORT_PINCFG_INEN;              // Set RX Pin config for input enable
    PORT->Group[PORTA].PINCFG[23].reg &= ~PORT_PINCFG_PULLEN;           // enable pullup/down resistor
    PORT->Group[PORTA].PINCFG[23].reg |= PORT_PINCFG_PMUXEN;            // enable PMUX
    PORT->Group[PORTA].PMUX[23>>1].bit.PMUXO = PORT_PMUX_PMUXE_C_Val;   // Set the PMUX bit (if pin is even, PMUXE, if odd, PMUXO)
    
    PM->APBCMASK.reg |= PM_APBCMASK_SERCOM3;                        // Set the PMUX for SERCOM3 and turn on module in PM

    
    GCLK->CLKCTRL.reg = GCLK_CLKCTRL_ID(SERCOM3_GCLK_ID_CORE) | GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN(0);
    while ( GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY); //Wait for synchronization to complete

    
    SERCOM3->USART.CTRLA.reg = SERCOM_USART_CTRLA_MODE_USART_INT_CLK /*Internal clock mode*/| SERCOM_USART_CTRLA_RXPO_PAD1 | SERCOM_USART_CTRLA_TXPO_PAD0;
    
    SERCOM3->USART.CTRLB.reg = SERCOM_USART_CTRLB_RXEN | SERCOM_USART_CTRLB_TXEN | SERCOM_USART_CTRLB_CHSIZE(0/*8 bits*/);
    
    SERCOM3->USART.BAUD.reg = SERCOM_USART_BAUD_BAUD((uint16_t)br);

    SERCOM3->USART.CTRLA.reg |= SERCOM_USART_CTRLA_ENABLE;

    SERCOM3->USART.INTENSET.reg |= SERCOM_USART_INTENSET_RXC;

    SERCOM3->USART.INTENSET.reg |= SERCOM_USART_INTENSET_DRE;

 

    

}
//USART Interrupt Handler

void UART_Setup_SERCOM0(void){

    uint32_t baud_2 = 9600;
    
    // FBAUD = ( fREF/ S) (1 – BAUD/65,536)
    // FBAUD = baud frequency
    // fref – SERCOM generic clock frequency
    // S – Number of samples per bit
    // BAUD – BAUD register value
    uint64_t br_2 = (uint64_t)65536 * (F_CPU - 16 * baud_2) / F_CPU;    // Variable for baud rate

    PORT->Group[PORTA].DIRSET.reg = (1 << 4);                          // Set TX Pin direction to output
    PORT->Group[PORTA].PINCFG[4].reg |= PORT_PINCFG_INEN;              // Set TX Pin config for input enable (required for usart)
    PORT->Group[PORTA].PINCFG[4].reg |= PORT_PINCFG_PMUXEN;            // enable PMUX
    PORT->Group[PORTA].PMUX[4>>1].bit.PMUXE = PORT_PMUX_PMUXE_D_Val;   // Set the PMUX bit (if pin is even, PMUXE, if odd, PMUXO)
    
    PORT->Group[PORTA].DIRCLR.reg = (1 << 5);                          // Set RX Pin direction to input
    PORT->Group[PORTA].PINCFG[5].reg |= PORT_PINCFG_INEN;              // Set RX Pin config for input enable
    PORT->Group[PORTA].PINCFG[5].reg &= ~PORT_PINCFG_PULLEN;           // enable pullup/down resistor
    PORT->Group[PORTA].PINCFG[5].reg |= PORT_PINCFG_PMUXEN;            // enable PMUX
    PORT->Group[PORTA].PMUX[5>>1].bit.PMUXO = PORT_PMUX_PMUXE_D_Val;   // Set the PMUX bit (if pin is even, PMUXE, if odd, PMUXO)
    
    PM->APBCMASK.reg |= PM_APBCMASK_SERCOM0;                        // Set the PMUX for SERCOM3 and turn on module in PM

 
    GCLK->CLKCTRL.reg = GCLK_CLKCTRL_ID(SERCOM0_GCLK_ID_CORE) | GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN(0); //48 MHz clock from Gen 0 (Main CPU clock sharing)
    while ( GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY); //Wait for synchronization to complete

    SERCOM0->USART.CTRLA.reg = SERCOM_USART_CTRLA_MODE_USART_INT_CLK /*Internal clock mode*/| SERCOM_USART_CTRLA_RXPO_PAD1 | SERCOM_USART_CTRLA_TXPO_PAD0;
    
    SERCOM0->USART.CTRLB.reg = SERCOM_USART_CTRLB_RXEN | SERCOM_USART_CTRLB_TXEN | SERCOM_USART_CTRLB_CHSIZE(0/*8 bits*/);
    
    // baud register value corresponds to the device communication baud rate
    SERCOM0->USART.BAUD.reg = (uint16_t)br_2;

    // SERCOM0 peripheral enabled
    SERCOM0->USART.CTRLA.reg |= SERCOM_USART_CTRLA_ENABLE;

    SERCOM0->USART.INTENSET.reg |= SERCOM_USART_INTENSET_RXC;

    SERCOM0->USART.INTENSET.reg |= SERCOM_USART_INTENSET_DRE;
    SERCOM0->USART.INTENSET.reg |=SERCOM_USART_INTENSET_TXC;

}

 

void DAC_Setup(void){

    PORT -> Group[PORTA].DIRSET.reg |= (uint32_t)(1 << 2);
   
    //Enable PORT Multiplexing

    PORT->Group[PORTA].PINCFG[2].reg |= PORT_PINCFG_PMUXEN;
    PORT->Group[PORTA].PMUX[2 >> 1].reg |= PORT_PMUX_PMUXE_B;
    //PM
    PM -> APBCMASK.reg = PM_APBCMASK_DAC ; //Enable DAC clock
    //CLK
    GCLK->CLKCTRL.reg = GCLK_CLKCTRL_ID (DAC_GCLK_ID) | // DAC share same GCLK
    GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN (0);
    //DAC Setup
    while ( GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY); //Wait for synchronization to complete
    
    DAC->CTRLB.reg = DAC_CTRLB_EOEN | DAC_CTRLB_REFSEL_VREFP; //Enable the DAC output on Vout pin. Enable VDDANAL REF.
    DAC->CTRLA.reg = DAC_CTRLA_ENABLE;
    while(DAC->STATUS.bit.SYNCBUSY==1);

}

 

 

 

My second problem is that the receiver does not seem to be working. Any suggestions?

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
    if(SERCOM3->USART.INTFLAG.reg =  SERCOM_USART_INTFLAG_RXC){

You have an assignment and not a compare operation here. Also this needs to check the bit ( & operator) because other bits can also be set in the register (i.e., you can't compare with just a == ).

#define I   3
uint8_t Rx_Data[I] = {10,2,4};
        Rx_Data[i] = SERCOM3->USART.DATA.reg;
        i++;
        if(i >= 20) {

The buffer has space for 3 chars and you intend to store up to 20 in it, not ok.

 

BTW, Use the code button when you post code (looks like <>).

/Lars

 

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

Got it, totally overlooked those two things. I was wondering, say I have two interrupts enabled for the USART, do both interrupts get handled on the same handler?

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

On the SAMD20; yes. The SERCOM units only have one NVIC line each.

If you enable more than one interrupt for the SERCOM, you need to check the INTFLAG register to see winch interrupt got triggered.