SERCOM UART and Rx PULL-UP

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

hello,

 

i am using SAMC20 MCU with keil uvision 5.23 IDE and PE-micro flash programmer abd debugger.

 

i set the Rx pin of the UART to be pulled up on the GPIO pinmux and pincfg.  (checked and worked ok)

 

but when i start transmitting through the SERCOM UART, the Rx pin goes to low (idle low, i can see that the pincfg for the port is still set to pull up settings).

the Tx pin stays (or goes to ) high.

 

i have tried it both on my own code and with the ATMEL START program, and they both acted the same.

it also didnt matter if i set the port before the uart or after, and even whan ports i used for Rx and Tx. 

 

do i miss anything?

how do i make the Rx stay idle high?

 

 

i am adding my code

 

void USART_init()
{
 //config SERCOM to USART
   // Enable Bus clock for SERCOM0
   REG_MCLK_APBCMASK = MCLK_APBCMASK_TCC0 | MCLK_APBCMASK_SERCOM0;
  
 REG_GCLK_PCHCTRL19 = GCLK_PCHCTRL_GEN_GCLK0 | GCLK_PCHCTRL_CHEN;
 
 SERCOM0->USART.CTRLA.bit.ENABLE = 0; // disable USART
 
 SERCOM0->USART.CTRLA.bit.MODE = 1; // set clock mode to internal clock
 SERCOM0->USART.CTRLA.bit.CMODE = 0; // set clock to be asynchronous with bus clk
 //SERCOM0->USART.CTRLA.bit.CPOL = 1;
 SERCOM0->USART.CTRLA.bit.TXPO = 0; // select Tx pin to be PAD[2] (PA08)
  SERCOM0->USART.CTRLA.bit.RXPO = 2; // select Rx pin to be PAD[0] (PA10)
 SERCOM0->USART.CTRLA.bit.DORD = 1; // set data order (LSB first)
 REG_SERCOM0_USART_BAUD = USART_baud_reg_calc(BAUD_RATE); //SERCOM_USART_BAUD_USARTFP_BAUD(207); // by baud rate equation in datasheet (p.520), fref = 8.064Mhz. synchronous arithmetic mode
 SERCOM0->USART.CTRLB.bit.RXEN = 1; // enable Receiver
 //SERCOM0->USART.INTENSET.bit.RXC = 1;
  
 SERCOM0->USART.CTRLB.bit.TXEN = 1; // enable transmitter
  
 SERCOM0->USART.CTRLA.bit.ENABLE = 1; // enable USART module
 //NVIC_EnableIRQ(SERCOM0_IRQn);
 while (SERCOM0->USART.SYNCBUSY.bit.ENABLE == 1); // wait for USART to be enabled
 
}

 

void GPIO_init()
{
  
 // set pins for SERCOM0 - USART
 //set PA10 to output and PA09 to input (Rx PAD[0], Tx PAD[2])
 PORT->Group[0].PINCFG[8].bit.PMUXEN = 1;
 PORT->Group[0].PINCFG[10].bit.PMUXEN = 1;
 PORT->Group[0].PMUX[4].bit.PMUXE = 2;
 PORT->Group[0].PMUX[5].bit.PMUXE = 2;
 
 // PULL UP for RX (PA10)
 PORT->Group[0].PINCFG[10].bit.PULLEN = 1;
 PORT->Group[0].PINCFG[10].bit.INEN = 1;
 PORT->Group[0].OUT.reg = 1<<10;
  
 
 // debug port
 PORT->Group[0].PINCFG[14].bit.PMUXEN = 1; // enable pin muxing for peripheral pick
 PORT->Group[0].DIR.reg |= PORT_PA14 | PORT_PA08;
 PORT->Group[0].PMUX[7].reg = 0x11; // set pin mux output to correct peripheral
 
}

p.s

i tried to upload the atmel start projects as well but it didnt let me.

 

thank you,

omer

omer

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

I have the same problem on the SAMD51 range. have you been able to solve this problem?

 

in the datasheet I see them mentioning something about the strdrv(strong drive) feature of the pin config. But I tried it out and nothing. It seems as soon as you enable the sercom pin mux that the sercom takes full control of that pin.

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

Are you sure you have the TX and RX pins around the correct way. I dont know the SAMC20, but with the SERCOM on the other devices, it looks as you may have your transmit and receive pads back to front

 

Your code is as follows: 

SERCOM0->USART.CTRLA.bit.TXPO = 0; // select Tx pin to be PAD[2] (PA08)
SERCOM0->USART.CTRLA.bit.RXPO = 2; // select Rx pin to be PAD[0] (PA10)

Normally when TXPO = 0, this sets PAD[0] to TX

Normally when RXPO = 2, this sets PAD[2] to Rx

 

However, the SAMC20 may be reversed compared with other devices.

 

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

lachlan, you are correct with that. 

 

However, do you have experience with the ARM range of Atmel? I'm having the same issue where I want the RX pin to have pull-up internally. The uart in question is using as terminal and it is working but with an external pull-up the way my circuit is configured. So I also want to know if it is possible to keep that pin high when the uart is in an idle state?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
	PORT->Group[0].PINCFG[8].bit.PULLEN = true;	// enable pull up/down on PA08
	PORT->Group[0].OUTSET.reg |= 1 << 8;		// pull up (OUTCLR for pulldown)

 

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

I explored this issue extensively with Microchip support and it appears (at least on the SAMD21) that it is only possible to enable a pulldown on the UART receive line. If you attempt to enable a pullup using the above code, it will only enable a pulldown. They indicate this is because the pin state is in control of the UART whereas the enabling of the pull functionality still functions. Since the UART RX pin state default is low, it pulls low. Seems a design fault to me, but that's how they explained it.

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

This is not exactly the same model of uC you are using, but this is how I configured my SERCOM3 UART ( 9600 baud at 48Mhz of CPU clock ) in a Adafruit ATSAMD51 Metro M4 board ( I removed the Circuit Python machine form the board and program it in C ). I also tried to set pull up in the Rx line only for test, but It didn't seem to do anything. Only pull down seems to be available. Anyway that is not a problem for my project. Corrections or apreciations for the code are welcome:

 

// USART config:
// ATSMAD51  AdaFruitMetro4 labels
//  PA22        *Tx>(1)
//  PA23        *Rx<(0)
// #define P0_USART_TX_MASK        0x00400000 // PORTA-0: PA22 -*Tx>(1)- USART TX PIN
// #define P0_USART_RX_MASK        0x00800000 // PORTA-0: PA23 -*Rx<(0)- USART RX PIN
// CPU CLCK is 48Mhz in Generic Clock Generator 0

// Configure GPIO lines to use them with SERCOM3:
// configure direction of I/O pins used for the USART Tx/Rx ( DIR bit = 1 OUTPUT , DIR bit = 0 INPUT )
PORT->Group[0].DIRSET.reg = P0_USART_TX_MASK;// TX PINA22 set to output
PORT->Group[0].DIRCLR.reg = P0_USART_RX_MASK;// RX PINA23 set to input
// enable multiplexer in both pins
PORT->Group[0].PINCFG[22].bit.PMUXEN  = 1; // enable p.multiplexing on PINA22
PORT->Group[0].PINCFG[23].bit.PMUXEN  = 1; // enable p.multiplexing on PINA23
PORT->Group[0].PINCFG[23].bit.PULLEN  = 1; // enable pull in the Rx in
PORT->Group[0].OUTCLR.reg = P0_USART_RX_MASK;// select pull down in RX pin
// select SERCOM3 function in the multiplexer
PORT->Group[0].PMUX[11].bit.PMUXE = 2; // 22 is even, so use PMUXE to set p.multiplexing to function (22/2=11),     function C = SERCOM3/ PAD[0] so set 0x2 ( peripheral C function selected )
PORT->Group[0].PMUX[11].bit.PMUXO = 2; // 23 is odd, so use PMUXO to set p.multiplexing to function (23/2=11.5=11), function C = SERCOM3/ PAD[1] so set 0x2 ( peripheral C function selected )

// Configure clocks for SERCOM3:
// CLK_SERCOM3_APB: Peripheral Clock Masking
MCLK->APBBMASK.bit.SERCOM3_=1;
// GCLK_SERCOM3_CORE: PCHCTRLm Mapping Index 24: 24 GCLK_SERCOM3_CORE SERCOM3 Core
GCLK->PCHCTRL[24].bit.GEN = 0;  //0 = Generic Clock Generator 0, 1 = Generic Clock Generator 1, 2 Generic Clock Generator 2 ...
GCLK->PCHCTRL[24].bit.CHEN = 1; //1 = clock CHANNEL ENABLE

// Configure the SERCOM3 - USART registers:
SERCOM3->USART.CTRLA.bit.ENABLE = 0;// 0 = Disable before configuring
SERCOM3->USART.CTRLA.bit.MODE = 1;// 1 = Use internal clock
SERCOM3->USART.CTRLA.bit.CMODE= 0;// 0 = Asynchronous mode clock
SERCOM3->USART.CTRLA.bit.RXPO = 1;// 0x1 = PAD[1] SERCOM PAD[1] is used for data reception
SERCOM3->USART.CTRLA.bit.TXPO = 0;// 0x0 = SERCOM PAD[0] SERCOM PAD[1] N/A N/A
SERCOM3->USART.CTRLB.bit.CHSIZE = 0;// 0x0 = 8 bits
SERCOM3->USART.CTRLA.bit.DORD = 1;// 0 = MSB is transmitted first, 1 = LSB is transmitted first
SERCOM3->USART.CTRLA.bit.FORM = 0;// 0 = no parity
SERCOM3->USART.CTRLB.bit.SBMODE = 0;// 0 = 1 stop bit , 1 = 2 stop bits
SERCOM3->USART.BAUD.bit.BAUD = 65326 * ( 1 - (16*(9600/48000000)) ); // BAUD = 65536 * ( 1 - (16*(fBAUD/fRef) ) )
SERCOM3->USART.CTRLB.bit.TXEN = 1; // 1= Tx Enabled
SERCOM3->USART.CTRLB.bit.RXEN = 1; // 1= Rx Enabled
SERCOM3->USART.CTRLA.bit.ENABLE = 1;// 1 = Once configured, enable SERCOM USART

while (SERCOM3->USART.SYNCBUSY.bit.ENABLE == 1); // wait for USART to be enable

And this is a simple example of writing and reading by polling from the UART:

 

uint8_t ui8_received=0;
uint8_t ui8_to_send=0;

while (1){

    if ( (ui8_to_send!=0) && (SERCOM3->USART.INTFLAG.bit.DRE == 1 ) ){
       SERCOM3->USART.DATA.bit.DATA = ui8_to_send;
       ui8_to_send = 0;
    }//if
    if (SERCOM3->USART.INTFLAG.bit.RXC == 1 ){
       ui8_received = SERCOM3->USART.DATA.bit.DATA;
       switch (ui8_received){
          case '1':
             ui8_to_send = 'h';
             break;
          case '2':
             ui8_to_send = 'e';
             break;
          case '3':
             ui8_to_send = 'l';
             break;
          case '4':
             ui8_to_send = 'l';
             break;
          case '5':
             ui8_to_send = 'o';
             break;
          default:
             ui8_to_send = ui8_received;
        }//switch

   }//if

}//while

 

 

Last Edited: Sun. May 10, 2020 - 07:48 PM