D20 USART interrupt

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

Hi,

I move from 8 bit MCU to SAM D20. I started to play with SAND20 xplained pro broad and using ASF. This time I have opportunity to configure SFR. But feel flexibility was gone. 

I try to do serial communication using USART. Just want to echo the string i type in terminal after found CR / LF . I found some tutorial for serial com, which have callback function after received fixed buffer length. for that also i have to call "usart_read_buffer_job". It is not looks pure interrupt driven method. 

is there any option in ASF can trigger RX interrupts for every byte received. So that i can check CR/LF there.

Sorry if i was missed out some fundamental of ASF.  

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

You do not need ASF for plain USART interrupt. may I offer you some lines of code, or must it be

complicated ASF code?

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

Thanks for all suggestions.

 

Can help me to find any tutorial / sample code for simple UART interrupt ? 

 

Yes I also tried single byte reading. but still someone need to read, then only we can know Received or not.

 

Last Edited: Wed. Mar 14, 2018 - 09:03 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I give you my Sercom_handler, written for SAM D10. Therefore you must possibly adapt some register addresses for your D20:

 

void SERCOM1_Handler()    
{
      unsigned char *status,*intflag,*data;
 
      data=(unsigned char *)DATA_SERCOM1;
      status=(unsigned char *)STATUS_SERCOM1;
      intflag=(unsigned char *)INTFLAG_SERCOM1;
 
      if((*intflag&RECV)==RECV)                                                           //character received?
     {
          recv=*data;                                                                                    //fetch received character    
          if((*status & 0b00000110)!=0)                                                   //receive errors happened?  
          {
               *status=6;                                                                                  //reset errors (framing and buffer overflow error)
               errors = errors | REC_ERR;                                                  //set global rec error flag in my global error variable not to use the char
          }                            
    }
    if((*intflag&TX_END)==TX_END)                                                   //transmission completed?
    {
          *intflag=2;                                                                                      //reset tx interrupt
          tx_empty=TRUE;                                                                         //set my global variable to indicate, I may reload tx buffer
     }
}     

 

And here are the symbolic constants/addresses:

#define INTFLAG_SERCOM1    0x42000C18
#define STATUS_SERCOM1      0x42000C1A
#define DATA_SERCOM1           0x42000C28

#define TX_ERR                            1
#define REC_ERR                        2
#define TX_END                            2

#define RECV                                 4

The transmit part is not necessary for you, but also a good example to transmit datas.

Best regards,

 

Uwe

 

Last Edited: Wed. Mar 14, 2018 - 04:34 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanksfor yours code. I was struggling on uart initialize, clock setting.... Si could you please give your USART initialization code?

Sorry to ask your code.

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

maaply wrote:
Thanksfor yours code. I was struggling on uart initialize, clock setting.... Si could you please give your USART initialization code? Sorry to ask your code.

That you are asking for code says a lot about the point you are at in the discovery of ​the SAM D20 Xplained Pro and the complexity of the SAM D20 ARM Cortex-M0+ chips.  Perhaps you need to read more of the datasheet and figure some of these things out on your own.  Regardless of that, I will try to help.

 

What parameters do you want for the USART, baud rate, sync or async, etc.

 

What clock settings are you talking about?

 

EDIT: Do the parameters below fit your requirements, they are the Start defaults for the USART_Async driver:  If so, create a Start project with just the USART driver added and the settings below and study the code it produces.  Think of it as homework even if you are not a student.

 

 

"I may make you feel but I can't make you think" - Jethro Tull - Thick As A Brick

"void transmigratus(void) {transmigratus();} // recursio infinitus" - larryvc

"It's much more practical to rely on the processing powers of the real debugger, i.e. the one between the keyboard and chair." - JW wek3

"When you arise in the morning think of what a privilege it is to be alive: to breathe, to think, to enjoy, to love." -  Marcus Aurelius

Last Edited: Thu. Mar 15, 2018 - 04:13 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks Larryvc for you advise. I was tried with ASF wizard to generate similar kind of code. But problem is in my first post. that code not support my requirement. I need something simple configuration to trigger UART Rx interrupt for each byte. I understand now, that is not that simple like AVR8. 

 

Sorry if my question disturbed you. I will keep on try to understand SAMxx MCU and no choice.

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

maaply wrote:
...I need something simple configuration to trigger UART Rx interrupt for each byte. I understand now, that is not that simple like AVR8.
ARM Cortex-M0+ are very different from AVR.  I am fortunate that I used ARM Cortex before I used AVR, I understand how difficult it is for the AVR users to make the transition to ARM Cortex.  Reading the datasheet is the key to using any MCU.

 

​Read Section 24. SERCOM USART​ in the datasheet, there you will find section 24.6.2 Basic Operation which has detailed initialization steps.

 

We are still going to need to know more about the USART parameters, what baud rate, sync or async, etc.  Perhaps Uwe60 will help out with the code.​

 

"I may make you feel but I can't make you think" - Jethro Tull - Thick As A Brick

"void transmigratus(void) {transmigratus();} // recursio infinitus" - larryvc

"It's much more practical to rely on the processing powers of the real debugger, i.e. the one between the keyboard and chair." - JW wek3

"When you arise in the morning think of what a privilege it is to be alive: to breathe, to think, to enjoy, to love." -  Marcus Aurelius

Last Edited: Thu. Mar 15, 2018 - 05:00 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hallo Larry vc!

 

Very interesting graphical surface you introduce here to create code. But the disadvantage is like with ASF, you do not know, how

the uC works, what is going on, you do not learn anything. And in case of bugs, you are nearly helpless to find the bugs.

I always compare the situation with pilots in their highly computerized aircrafts. In case of emergency, they often fail,

as they do not know, how the computers works with the plane. They are no pilots any more, but system administrators.

 

You are certainly right, that our friend here should go on reading the manual, although I am not pleased with Atmel documention.

It must be read several times to find hidden words, to read between the lines. Therefore I will help him this time to get startet easily.

Best regards,

 

Uwe

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

you do not know, how

the uC works, what is going on, you do not learn anything

Not true, ASF 3 and 4 examples are not black boxes, you can look at the code which in my experience (mostly ASF 3) works fine. And you can run such examples for the purpose of looking at the register settings in the debugger. 

/Lars

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

Hello Maaply!

 

Of course, generally ARM Cortex M family, even the plain M0(+) are diffent worlds, compared with AVR. AVR is kindergarden, ARM Cortex university :-)

I give you my code to accelerate your development:

 

/***********************************************************************************************************************************/
void init_SERCOM1(void)
{
      uint32_t *pointer32,*p32_2;              
      unsigned char *pointer8;
      uint16_t *pointer16,*p16_2;
      struct CTRLA_SERC1 ctrla_ser1;        
      struct CTRLB_SERC1 ctrlb_ser1;
      struct CLKCTRLs clkctrl_ser1;
 
      pointer32=(uint32_t *)PORTOUTSET;            //PA30 output, PA31 remains input
      *pointer32=0x40000000;   
     
      pointer16=(uint16_t *)PINCFG;  
      *(pointer16+15)=0x0101;                      //prepare SERCOM1 input and output, Multiplexer on
 
      pointer8= (unsigned char *)PMUX;
      *(pointer8+15)=0x22;                            //PA30-31 as function C (Sercom 1)           
    
      clkctrl_ser1.ID=0xF;                              //clock for SERCOM1                       
      clkctrl_ser1.RES6_7=0;                       //reserved, reset
      clkctrl_ser1.GEN=CLKGEN0;             //connected to clock generator 0
      clkctrl_ser1.RES12_13=0;                  //reserved, reset
      clkctrl_ser1.CLKEN=_ENABLE;        //clock enable
      clkctrl_ser1.WRTLOCK=0;                  //write lock not used
      pointer16=(uint16_t *)CLKCTRL;          
      p16_2=(uint16_t *)&clkctrl_ser1;
      *pointer16=*p16_2;
      sync_clkctrl_bus();
 
      pointer16=(uint16_t *)APBCMASK;
      *pointer16=*pointer16 | 0x0008;          //SERCOM1 clock on
                                                                                                                                                                                                                                                         
      ctrla_ser1.SWRST=0;                            //no reset of SERCOM registers                    
      ctrla_ser1.ENABLE=NO;                      //disable SERCOM1 first        
      ctrla_ser1.MODE=1;                             //USART with internal clock
      ctrla_ser1.RES5_6=0;                         //reserved bits, always set 0
      ctrla_ser1.RUNSTDBY=YES;            //run also in standby
      ctrla_ser1.IBON=NO;                           //BUFOVF is asserted when happening in data stream    
      ctrla_ser1.RES9_12=0;                       //reserved, set 0
      ctrla_ser1.SAMPR=NO;                       //sample rate=16x + arithmetic baud rate generation
      ctrla_ser1.TXPO=2;                             //tx=pad[0]=pin12
      ctrla_ser1.RES18_19=0;                     //reserved, set 0
      ctrla_ser1.RXPO=1;                             //rx=pad[[1]    
      ctrla_ser1.SAMPA=0;                           //sample adjustment=7-8-9
      ctrla_ser1.FORM=0;                             //UART, no parity,no autobaud, no break detection
      ctrla_ser1.CMODE=0;                          //asynchronous mode
      ctrla_ser1.CPOL=0;                              //don't care in asynchronous mode    
      ctrla_ser1.DORD=1;                             //LSB first as usual
      ctrla_ser1.RES31=0;                          
 
      pointer32=(uint32_t *)CTRLA_SERCOM1;          
      p32_2=(uint32_t *)&ctrla_ser1;
      *pointer32=*p32_2;
         
      pointer16=(uint16_t *)BAUD_SERCOM1;          //set baud rate 19200
      *pointer16=64907;
          
      ctrlb_ser1.CHSIZE=EIGHT;                 //character size=8 bits,NINE possible  
      ctrlb_ser1.RES3_5=0;                         //reserved, set 0
      ctrlb_ser1.SBMODE=0;                        //one stop bit
      ctrlb_ser1.RES7=0;                             //reserved, set 0
      ctrlb_ser1.COLDEN=0;                       //no collision detection
      ctrlb_ser1.SFDE=0;                             //no wake-up by start bit    
      ctrlb_ser1.ENC=0;                             //no IrDA encoding
      ctrlb_ser1.RES11_12=0;                  //reserved, set 0
      ctrlb_ser1.PMODE=0;                       //no parity
      ctrlb_ser1.RES14_15=0;                  //reserved, set 0
      ctrlb_ser1.TXEN=1;                           //enable tx
      ctrlb_ser1.RXEN=1;                          //enable rx
      ctrlb_ser1.RES18_31=0;                 //reserved, set 0
 
      pointer32=(uint32_t *)CTRLB_SERCOM1;    
      p32_2=(uint32_t *)&ctrlb_ser1;
      *pointer32=*p32_2;      
      sync_ctrlb_sercom1();                   
    
      pointer8=(unsigned char *)INTENSET_SERCOM1;
      *pointer8=6;                                            //Interrupts on for receive and data register empty    
 
      ctrla_ser1.ENABLE=1;                         //now enable SERCOM1
      pointer32=(uint32_t *)CTRLA_SERCOM1;
      p32_2=(uint32_t *)&ctrla_ser1;
      *pointer32=*p32_2;
 
      sync_on_off_sercom1();
      enable_nvic_int(SERCOM1_IRQ);
}

Now parts of my own headerfile I include at the beginning

 

#define CTRLA_SERCOM1         0x42000C00             //Sercom1
#define CTRLB_SERCOM1         0x42000C04
#define BAUD_SERCOM1           0x42000C0C
#define INTENCLR_SERCOM1  0x42000C14
#define INTENSET_SERCOM1   0x42000C16
#define INTFLAG_SERCOM1      0x42000C18
#define STATUS_SERCOM1        0x42000C1A
#define SYNC_SERCOM1           0x42000C1C
#define DATA_SERCOM1            0x42000C28

#define SERCOM0_IRQ               9
#define SERCOM1_IRQ              10
#define SERCOM2_IRQ              11

 

struct CTRLA_SERC1
{
    uint32_t SWRST:1;
    uint32_t ENABLE:1;
    uint32_t MODE:3;
    uint32_t RES5_6:2;
    uint32_t RUNSTDBY:1;
    uint32_t IBON:1;
    uint32_t RES9_12:4;
    uint32_t SAMPR:3;
    uint32_t TXPO:2;
    uint32_t RES18_19:2;
    uint32_t RXPO:2;
    uint32_t SAMPA:2;
    uint32_t FORM:4;
    uint32_t CMODE:1;
    uint32_t CPOL:1;
    uint32_t DORD:1;
    uint32_t RES31:1;
};
    
    
struct CTRLB_SERC1
{
    uint32_t CHSIZE:3;
    uint32_t RES3_5:3;
    uint32_t SBMODE:1;
    uint32_t RES7:1;
    uint32_t COLDEN:1;
    uint32_t SFDE:1;
    uint32_t ENC:1;
    uint32_t RES11_12:2;
    uint32_t PMODE:1;
    uint32_t RES14_15:2;
    uint32_t TXEN:1;
    uint32_t RXEN:1;
    uint32_t RES18_31:14;
};

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

maaply wrote:
Yes I also tried single byte reading. but still someone need to read, then only we can know Received or not.

I don't get this, can you try to rephrase it?

"still someone needs to read" may be a misunderstanding, you need a single usart_read_buffer_job to get things going, then repeat that call in the callback.

/Lars

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1
#define CTRLA_SERCOM1     0x42000C00             //Sercom1
#define CTRLB_SERCOM1     0x42000C04
#define BAUD_SERCOM1      0x42000C0C
#define INTENCLR_SERCOM1  0x42000C14
#define INTENSET_SERCOM1  0x42000C16
#define INTFLAG_SERCOM1   0x42000C18
#define STATUS_SERCOM1    0x42000C1A
#define SYNC_SERCOM1      0x42000C1C
#define DATA_SERCOM1      0x42000C28

Uwe, You do realize we have include files for this (and the bit definitions) I hope? It seems utterly pointless (end error-prone) to re-create all that.
/Lars

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

Yes I know Lars, also ready structures exist. Even ready code.  But I do not like their long and complicated names. And

strange expressions are difficult to keep in ones brain, I do not want to learn them by heart, so own invented names are much

easier to keep! Maybe, mistakes can be done, but I hate ready code, and even ASF is not quite free of bugs.....

 

Uwe

Last Edited: Thu. Mar 15, 2018 - 06:37 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Uwe60, I agree with Lars's posts #11 and #14.  I was going to reply to your post #10 but Lars wrote what I would have written.

 

The include files have nothing to do with Start or ASF in particular.  They contain the manufacturers definitions for the chip and formulate a standard.  Using your own defines only makes your code non-standard.  

 

If you were to use the include files your code could be used by anybody and would be standard.  Using the standard defines will also speed up your coding.

 

Code as you wish but please use the standard defines when you are sharing code, otherwise you are only causing more confusion for the OP when he tries to compare your code to others' code.

 

Also a bit of friendly advice, use spaces in your code, whitespace takes up no code space.  I find your code quite difficult to read, that makes comprehension of it all the more difficult.

 

EDIT: I admire your enthusiasm and effort, but much is missing:

 

"I may make you feel but I can't make you think" - Jethro Tull - Thick As A Brick

"void transmigratus(void) {transmigratus();} // recursio infinitus" - larryvc

"It's much more practical to rely on the processing powers of the real debugger, i.e. the one between the keyboard and chair." - JW wek3

"When you arise in the morning think of what a privilege it is to be alive: to breathe, to think, to enjoy, to love." -  Marcus Aurelius

Last Edited: Thu. Mar 15, 2018 - 09:26 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Larry, I understand your argument, normally you are absolutely right! Originally I did not intend to spread my code (when I did it,

I did not think over), because programming is my hobby at my evening of life, as I am retired meanwhile after more than

25 years development of electronics. As it is only fun, pleasure, I have all freedom to write code  as I like. No rules like MISRA and

header files from manufacurer, and so on. I offer to clear my post with the code, and the theme is over!

 

Uwe

Last Edited: Thu. Mar 15, 2018 - 09:19 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

No, please don't remove your code. That would make the thread context incomplete.  Lets try to make it better for the OP, I will try to help with that using your code as a base.  Consider it a learning opportunity for us all.

"I may make you feel but I can't make you think" - Jethro Tull - Thick As A Brick

"void transmigratus(void) {transmigratus();} // recursio infinitus" - larryvc

"It's much more practical to rely on the processing powers of the real debugger, i.e. the one between the keyboard and chair." - JW wek3

"When you arise in the morning think of what a privilege it is to be alive: to breathe, to think, to enjoy, to love." -  Marcus Aurelius

Last Edited: Thu. Mar 15, 2018 - 09:13 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Uwe, would it be to much to ask for you to provide the missing defines and functions as shown in the screenshot of post #16,  I have completed much and just need that to finish.

"I may make you feel but I can't make you think" - Jethro Tull - Thick As A Brick

"void transmigratus(void) {transmigratus();} // recursio infinitus" - larryvc

"It's much more practical to rely on the processing powers of the real debugger, i.e. the one between the keyboard and chair." - JW wek3

"When you arise in the morning think of what a privilege it is to be alive: to breathe, to think, to enjoy, to love." -  Marcus Aurelius

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

Very friendly of you, ok, code remains as a bad, unintended example :-) I can correct the missing defines in my code example, so that

it is compileable for SAM D10. Whether few problems will come up with the very similiar SAM D20, I do not know! Therefore my code was not shown to be compiled, but to show the logical steps to do!

 

Last Edited: Thu. Mar 15, 2018 - 11:15 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

This is somewhat based on the original ASF callback example.  I'm using a fifo structure to take bytes (the fifo portions are not part of ASF, but something easy to add or find online).  Pin definitions are easier on SAMD20 by using the EXT1/2/3 USART defines

 

struct usart_module usart_instance;
uint8_t usart_rx_buffer[1];

void configure_usart(void)
{
    struct usart_config config_usart;
    fifo_init(&usart_fifo,usart_msg_buffer,MAX_PACKET_SIZE);
    usart_get_config_defaults(&config_usart);
    config_usart.baudrate    = 115200;  
    config_usart.mux_setting = USART_RX_3_TX_2_XCK_3;
    config_usart.pinmux_pad0 = PINMUX_UNUSED;   
    config_usart.pinmux_pad1 = PINMUX_UNUSED; 
    config_usart.pinmux_pad2 = PINMUX_PA24C_SERCOM3_PAD2;  // TX PIN
    config_usart.pinmux_pad3 = PINMUX_PA25C_SERCOM3_PAD3;  // RX PIN
    while (usart_init(&usart_instance, SERCOM3, &config_usart) != STATUS_OK)
    {}
    usart_enable(&usart_instance);
    
    usart_register_callback(&usart_instance, usart_receive_byte, USART_CALLBACK_BUFFER_RECEIVED);
    usart_enable_callback(&usart_instance, USART_CALLBACK_BUFFER_RECEIVED);

    usart_read_buffer_job(&usart_instance, usart_rx_buffer, 1); 
}


void usart_receive_byte(struct usart_module *const usart_module)
{
    uint8_t result = fifo_write(&usart_fifo, usart_rx_buffer,1);
    if (result == 0)
    {
        Assert(false);
    }
    usart_read_buffer_job(&usart_instance, usart_rx_buffer, 1);
}

 

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

@maaply, Ran out of time to complete it, so this code for the SAM D20 Xplained Pro does not have a fifo or ring buffer and it does nothing more than echo the typed character back out to the PC, and as all good micro programs should, it blinks an LED.  Only receive interrupts are in place at this time, transmit is handled by Sercom3_putchar().   Baud rate is set at 115200.

This code does not use ASF, Start, or any other code foundation, it uses only that which is provided in the include files from the pack for the SAM D20.  The code is not elegant, that is Uwe's faultwink​, but it does show how to initialize the SERCOM3 USART on the SAM D20 Xplained Pro.  I would like to thank Uwe for providing the code for the SAM D10 version, that saved an enormous amount of time to migrate the code to the SAM D20, I learned a lot and the effort was worth every minute.

 

Create an AS7 C project, copy these files into it, study them, then run them.  I will leave it as an exercise for you to add the code for the buffer and any other features that you want.

 

main.c

/*
* D20USART.c - really main.c
*
* For use on a SAM D20 Xplained Pro
*
* Created: 3/15/2018 13:17:44
* Author : Larry larryvc based on code by Uwe Uwe60
*/

#include "sam.h"
#include "stdbool.h"

volatile uint8_t sercom3_errors, sercom3_char_received, sercom3_data;

void Sercom3_Init(void);
char Sercom3_putchar(char ch);
char Sercom3_getchar();

int main(void)
{
	REG_PORT_DIRSET0 = PORT_PA14;  // SAM D20 Xplained Pro LED

	// Initialize the SAM system

	SystemInit();

	// 8MHz oscillator - set to divide by 1
	// Allows for good BAUD rates up to 460800 - higher BAUD rates require a DFFL48 derived clock
	// Same as SYSCTRL->OSC8M.bit.PRESC = 0;
	REG_SYSCTRL_OSC8M &= ~SYSCTRL_OSC8M_PRESC_Msk;
	while ((REG_SYSCTRL_PCLKSR & SYSCTRL_PCLKSR_OSC8MRDY) == 0);

	Sercom3_Init();

	while (1) {

		if(sercom3_char_received ==  true) {
			if (sercom3_errors == false) {
				Sercom3_putchar(sercom3_data); // send received character
				sercom3_char_received = false;
				} else {
				// Do something about the error
				//while (1) { // trap for debug
				//	for(volatile uint32_t i = 0; i <= 10000; i++);
				//	REG_PORT_OUTTGL0 = PORT_PA14;
				sercom3_errors = false; // Ignored the char
			}
		}

		// Crude delay loop
		// Should use Systick for timing
		for(volatile uint32_t i = 0; i <= 100000; i++);
		REG_PORT_OUTTGL0 = PORT_PA14;
	}
}

sercom3usart.c

/*
* sercom3usart.c
*
* For use on a SAM D20 Xplained Pro
*
* Created: 3/17/2018 01:13:11
* Author : Larry larryvc based on code by Uwe Uwe60
*/

#include "sam.h"
#include "stdbool.h"

// BAUD calculation
#define CLOCKRATE 8000000
#define BAUDRATE 115200
#define BAUD 65536UL - ((uint64_t)65536 * 16 * BAUDRATE) / CLOCKRATE

#define REC_ERR 2

extern uint8_t sercom3_errors, sercom3_char_received, sercom3_data;

// Using Interrupt for receive only, Sercom3putchar for transmit
void SERCOM3_Handler()
{
	if(REG_SERCOM3_USART_INTFLAG & SERCOM_USART_INTFLAG_RXC)	//character received?
	{
		sercom3_char_received = true;
		sercom3_data = REG_SERCOM3_USART_DATA;	//fetch received character

		if(REG_SERCOM3_USART_STATUS & (SERCOM_USART_STATUS_FERR | SERCOM_USART_STATUS_BUFOVF))	//receive errors happened?
		{
			REG_SERCOM3_USART_STATUS = SERCOM_USART_STATUS_FERR | SERCOM_USART_STATUS_BUFOVF;	//reset errors (framing and buffer overflow error)
			sercom3_errors |= REC_ERR;	//set global rec error flag in my global error variable not to use the char
		}

	}
}

char Sercom3_putchar(char ch)
{
	while ((REG_SERCOM3_USART_INTFLAG & SERCOM_USART_INTFLAG_DRE) == 0);
	REG_SERCOM3_USART_DATA = ch;
	return ch;
}

char Sercom3_getchar(char ch)
{
	while ((REG_SERCOM3_USART_INTFLAG & SERCOM_USART_INTFLAG_RXC) == 0);
	return REG_SERCOM3_USART_DATA;
}

void Sercom3_Init(void)
{
	// PORT Setup

	// SERCOM3 PAD[2] PIN_PA24 is TXD, SERCOM3 PAD[3] PIN_PA25 is RXD
	// Set PAD[2] PIN_PA24 TXD to output
	// #define REG_PORT_DIRSET0           (*(RwReg  *)0x41004408UL) /**< \brief (PORT) Data Direction Set 0 */
	REG_PORT_DIRSET0 = PORT_PA24;

	// Set PMUXEN bit for both PINCFG24 PIN_PA24 TXD and PINCFG25 PIN_PA25 RXD
	// 24 8 bit registers offset to PINCFG24, pointer is 16 bit to handle int value, (32 - 24 * 2) = 12 16 bit pointer offset
	// Uses 4 instructions, 7 clock cycles, 12 bytes including pointer address
	// #define REG_PORT_PINCFG0           (*(RwReg  *)0x41004440UL) /**< \brief (PORT) Pin Configuration 0 */
	// Faster and shorter than
	// PORT->Group[0].PINCFG[24].reg |= PORT_PINCFG_PMUXEN;
	// PORT->Group[0].PINCFG[25].reg |= PORT_PINCFG_PMUXEN;
	*((uint16_t *)&REG_PORT_PINCFG0 + 12) = (PORT_PINCFG_PMUXEN) | (PORT_PINCFG_PMUXEN << 8);

	// Set PMUX12 to peripheral function C for PIN_PA24 TXD and PIN_PA25 RXD
	// 12 8 (4+4) bit registers offset to PMUX12
	// Uses 3 instructions, 5 clock cycles, 10 bytes including pointer address
	// #define REG_PORT_PMUX0             (*(RwReg  *)0x41004430UL) /**< \brief (PORT) Peripheral Multiplexing 0 */
	// Same result as PORT->Group[0].PMUX[12].reg = PORT_PMUX_PMUXO_C | PORT_PMUX_PMUXE_C;
	*((uint8_t *)&REG_PORT_PMUX0 + 12) = PORT_PMUX_PMUXO_C | PORT_PMUX_PMUXE_C;

	// Clock Setup

	// Set up GCLK - Generic Clock Controller
	// GCLK_CLKCTRL - GEN Generic Clock Generator is GCLKGEN0
	// GCLK_CLKCTRL - ID Generic Clock Selection ID is GCLK_SERCOM3_CORE
	// GCLK_CLKCTRL - CLKEN Clock Enable is enabled
	// #define REG_GCLK_CLKCTRL           (*(RwReg16*)0x40000C02UL) /**< \brief (GCLK) Generic Clock Control */
	REG_GCLK_CLKCTRL |= GCLK_CLKCTRL_GEN_GCLK0 | GCLK_CLKCTRL_ID_SERCOM3_CORE | GCLK_CLKCTRL_CLKEN;
	while(REG_GCLK_STATUS & GCLK_STATUS_SYNCBUSY);

	// Power Management

	// Enable peripheral clock for SERCOM3
	// APBC Mask SERCOM3 SERCOM3 APB Clock Enable is enabled
	// #define REG_PM_APBCMASK            (*(RwReg  *)0x40000420UL) /**< \brief (PM) APBC Mask */
	REG_PM_APBCMASK |= PM_APBCMASK_SERCOM3;

	// SERCOM3 Setup

	// SERCOM3 USART CTRLA register setup
	// Disables SERCOM3 registers Enable-Protection so we can write to all the SERCOM3 registers
	// SERCOM3_USART_CTRLA - Mode = USART with internal clock
	// SERCOM3_USART_CTRLA - RUNSTDBY = Generic clock is enabled in all sleep modes. Any interrupt can wake up the device.
	// SERCOM3_USART_CTRLA - TXPO assigned to PAD2
	// SERCOM3_USART_CTRLA - RXPO assigned to PAD3
	// SERCOM3_USART_CTRLA - DORD = LSB is transmitted first
	// #define REG_SERCOM3_USART_CTRLA    (*(RwReg  *)0x42001400UL) /**< \brief (SERCOM3) USART Control A */
	REG_SERCOM3_USART_CTRLA = SERCOM_USART_CTRLA_MODE_USART_INT_CLK | SERCOM_USART_CTRLA_RUNSTDBY | SERCOM_USART_CTRLA_TXPO_PAD2
							  | SERCOM_USART_CTRLA_RXPO_PAD3 | SERCOM_USART_CTRLA_DORD;
	while(REG_SERCOM3_USART_STATUS & SERCOM_USART_STATUS_SYNCBUSY);

	// SERCOM3 USART BAUD register setup
	// #define REG_SERCOM3_USART_BAUD     (*(RwReg16*)0x4200140AUL) /**< \brief (SERCOM3) USART Baud */
	REG_SERCOM3_USART_BAUD = BAUD;

	// SERCOM3 USART CTRLB register setup
	// TXEN is enabled
	// RXEN is enabled
	// DORD = LSB is transmitted first
	// #define REG_SERCOM3_USART_CTRLB    (*(RwReg  *)0x42001404UL) /**< \brief (SERCOM3) USART Control B */
	REG_SERCOM3_USART_CTRLB = SERCOM_USART_CTRLB_TXEN | SERCOM_USART_CTRLB_RXEN;
	while(REG_SERCOM3_USART_STATUS & SERCOM_USART_STATUS_SYNCBUSY);

	// Enable SERCOM3 interrupts
	// RXC Receive Complete Interrupt Enabled
	// #define REG_SERCOM3_USART_INTENSET (*(RwReg8 *)0x4200140DUL) /**< \brief (SERCOM3) USART Interrupt Enable Set */
	REG_SERCOM3_USART_INTENSET = SERCOM_USART_INTENSET_RXC;

	// Enable SERCOM3 NVIC Interrupt
	NVIC_EnableIRQ(SERCOM3_IRQn);

	// Enable SERCOM3
	// #define REG_SERCOM3_USART_CTRLA    (*(RwReg  *)0x42001400UL) /**< \brief (SERCOM3) USART Control A */
	REG_SERCOM3_USART_CTRLA |= SERCOM_USART_CTRLA_ENABLE;
	while(REG_SERCOM3_USART_STATUS & SERCOM_USART_STATUS_SYNCBUSY);
}

EDIT: Changed  the comments in block starting with "Set PMXEN bit for both PINCFG24 PIN_PA24 TXD and PINCFG PIN_PA25 RXD"

"I may make you feel but I can't make you think" - Jethro Tull - Thick As A Brick

"void transmigratus(void) {transmigratus();} // recursio infinitus" - larryvc

"It's much more practical to rely on the processing powers of the real debugger, i.e. the one between the keyboard and chair." - JW wek3

"When you arise in the morning think of what a privilege it is to be alive: to breathe, to think, to enjoy, to love." -  Marcus Aurelius

Last Edited: Tue. Mar 20, 2018 - 11:58 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thank you Larry for your nice words! 

 

Yes, I fully agree with you! And yes, I did not introduce a FIFO or even ring buffer. That's another item, another chapter, I have

certainly practised, but not published, as this item was not asked for. And 2 pointers for a ring buffer (one for next

free space, and one, next char to fetch) is an own long  chapter. And yes, I do not want to publish C novels. :-)

 

Frankly, I do not want to publish ASF like code, too complicated, too long, a deep jungle, sorry Atmel. And when I search for ASF

functions, their contents, I always loose in spite of Google! So far, I will go on writing my own private code for fun, uncomplicated,

not much time and without rules. If I worked commercially, I would obey rules, as this waste of time is payed......

Best regards,

 

Uwe

 

Last Edited: Tue. Mar 20, 2018 - 06:43 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

@maaply, Here is a version using interrupts for both receive and transmit, no blinking LED.

 

main.c

/*
* D20USART.c - really main.c
*
* For use on a SAM D20 Xplained Pro
*
* Created: 3/15/2018 13:17:44
* Author : Larry larryvc based on code by Uwe Uwe60
*/

#include "sam.h"
#include "stdbool.h"

volatile uint8_t sercom3_errors, sercom3_char_received, sercom3_data;

void Sercom3_Init(void);
char Sercom3_putchar(char ch);
char Sercom3_getchar();

int main(void)
{
	REG_PORT_DIRSET0 = PORT_PA14;  // SAM D20 Xplained Pro LED

	// Initialize the SAM system

	SystemInit();

	// 8MHz oscillator - set to divide by 1
	// Allows for good BAUD rates up to 460800 - higher BAUD rates require a DFFL48 derived clock
	// Same as SYSCTRL->OSC8M.bit.PRESC = 0;
	REG_SYSCTRL_OSC8M &= ~SYSCTRL_OSC8M_PRESC_Msk;
	while ((REG_SYSCTRL_PCLKSR & SYSCTRL_PCLKSR_OSC8MRDY) == 0);

	Sercom3_Init();

	while (1) {

		if(sercom3_char_received ==  true) {
			if (sercom3_errors == false) {
				REG_SERCOM3_USART_DATA = sercom3_data;
				sercom3_char_received = false;
				} else {
				// Do something about the error
				sercom3_errors = false; // Ignored the char
			}
		}
	}
}

sercom3usart.c

 

/*
* sercom3usart.c
*
* For use on a SAM D20 Xplained Pro
*
* Created: 3/17/2018 01:13:11
* Author : Larry larryvc based on code by Uwe Uwe60
*/

#include "sam.h"
#include "stdbool.h"

// BAUD calculation
#define CLOCKRATE 8000000
#define BAUDRATE 115200
#define BAUD 65536UL - ((uint64_t)65536 * 16 * BAUDRATE) / CLOCKRATE

#define REC_ERR 2

extern uint8_t sercom3_errors, sercom3_char_received, sercom3_data;

// Using interrupts for receive and transmit
void SERCOM3_Handler()
{
	if(REG_SERCOM3_USART_INTFLAG & SERCOM_USART_INTFLAG_RXC)	//character received?
	{
		sercom3_char_received = true;
		sercom3_data = REG_SERCOM3_USART_DATA;	//fetch received character

		if(REG_SERCOM3_USART_STATUS & (SERCOM_USART_STATUS_FERR | SERCOM_USART_STATUS_BUFOVF))	//receive errors happened?
		{
			REG_SERCOM3_USART_STATUS = SERCOM_USART_STATUS_FERR | SERCOM_USART_STATUS_BUFOVF;	//reset errors (framing and buffer overflow error)
			sercom3_errors |= REC_ERR;	//set global rec error flag in my global error variable not to use the char
		}

	}

	if (REG_SERCOM3_USART_INTFLAG & SERCOM_USART_INTFLAG_TXC)
	{
		while ((REG_SERCOM3_USART_INTFLAG & SERCOM_USART_INTFLAG_DRE) == 0);
		REG_SERCOM3_USART_INTFLAG |= SERCOM_USART_INTFLAG_TXC;
	}
}

void Sercom3_Init(void)
{
	// PORT Setup

	// SERCOM3 PAD[2] PIN_PA24 is TXD, SERCOM3 PAD[3] PIN_PA25 is RXD
	// Set PAD[2] PIN_PA24 TXD to output
	// #define REG_PORT_DIRSET0           (*(RwReg  *)0x41004408UL) /**< \brief (PORT) Data Direction Set 0 */
	REG_PORT_DIRSET0 = PORT_PA24;

	// Set PMUXEN bit for both PINCFG24 PIN_PA24 TXD and PINCFG25 PIN_PA25 RXD
	// 24 8 bit registers offset to PINCFG24, pointer is 16 bit to handle int value, (32 - 24 * 2) = 12 16 bit pointer offset
	// Uses 4 instructions, 7 clock cycles, 12 bytes including pointer address
	// #define REG_PORT_PINCFG0           (*(RwReg  *)0x41004440UL) /**< \brief (PORT) Pin Configuration 0 */
	// Faster and shorter than
	// PORT->Group[0].PINCFG[24].reg |= PORT_PINCFG_PMUXEN;
	// PORT->Group[0].PINCFG[25].reg |= PORT_PINCFG_PMUXEN;
	*((RwReg16 *)&REG_PORT_PINCFG0 + 12) = (PORT_PINCFG_PMUXEN) | (PORT_PINCFG_PMUXEN << 8);

	// Set PMUX12 to peripheral function C for PIN_PA24 TXD and PIN_PA25 RXD
	// 12 8 (4+4) bit registers offset to PMUX12
	// Uses 3 instructions, 5 clock cycles, 10 bytes including pointer address
	// #define REG_PORT_PMUX0             (*(RwReg  *)0x41004430UL) /**< \brief (PORT) Peripheral Multiplexing 0 */
	// Same result as PORT->Group[0].PMUX[12].reg = PORT_PMUX_PMUXO_C | PORT_PMUX_PMUXE_C;
	*((RwReg8 *)&REG_PORT_PMUX0 + 12) = PORT_PMUX_PMUXO_C | PORT_PMUX_PMUXE_C;

	// Clock Setup

	// Set up GCLK - Generic Clock Controller
	// GCLK_CLKCTRL - GEN Generic Clock Generator is GCLKGEN0
	// GCLK_CLKCTRL - ID Generic Clock Selection ID is GCLK_SERCOM3_CORE
	// GCLK_CLKCTRL - CLKEN Clock Enable is enabled
	// #define REG_GCLK_CLKCTRL           (*(RwReg16*)0x40000C02UL) /**< \brief (GCLK) Generic Clock Control */
	REG_GCLK_CLKCTRL |= GCLK_CLKCTRL_GEN_GCLK0 | GCLK_CLKCTRL_ID_SERCOM3_CORE | GCLK_CLKCTRL_CLKEN;
	while(REG_GCLK_STATUS & GCLK_STATUS_SYNCBUSY);

	// Power Management

	// Enable peripheral clock for SERCOM3
	// APBC Mask SERCOM3 SERCOM3 APB Clock Enable is enabled
	// #define REG_PM_APBCMASK            (*(RwReg  *)0x40000420UL) /**< \brief (PM) APBC Mask */
	REG_PM_APBCMASK |= PM_APBCMASK_SERCOM3;

	// SERCOM3 Setup

	// SERCOM3 USART CTRLA register setup
	// Disables SERCOM3 registers Enable-Protection so we can write to all the SERCOM3 registers
	// SERCOM3_USART_CTRLA - Mode = USART with internal clock
	// SERCOM3_USART_CTRLA - RUNSTDBY = Generic clock is enabled in all sleep modes. Any interrupt can wake up the device.
	// SERCOM3_USART_CTRLA - TXPO assigned to PAD2
	// SERCOM3_USART_CTRLA - RXPO assigned to PAD3
	// SERCOM3_USART_CTRLA - DORD = LSB is transmitted first
	// #define REG_SERCOM3_USART_CTRLA    (*(RwReg  *)0x42001400UL) /**< \brief (SERCOM3) USART Control A */
	REG_SERCOM3_USART_CTRLA = SERCOM_USART_CTRLA_MODE_USART_INT_CLK | SERCOM_USART_CTRLA_RUNSTDBY | SERCOM_USART_CTRLA_TXPO_PAD2
							  | SERCOM_USART_CTRLA_RXPO_PAD3 | SERCOM_USART_CTRLA_DORD;
	while(REG_SERCOM3_USART_STATUS & SERCOM_USART_STATUS_SYNCBUSY);

	// SERCOM3 USART BAUD register setup
	// #define REG_SERCOM3_USART_BAUD     (*(RwReg16*)0x4200140AUL) /**< \brief (SERCOM3) USART Baud */
	REG_SERCOM3_USART_BAUD = BAUD;

	// SERCOM3 USART CTRLB register setup
	// TXEN is enabled
	// RXEN is enabled
	// DORD = LSB is transmitted first
	// #define REG_SERCOM3_USART_CTRLB    (*(RwReg  *)0x42001404UL) /**< \brief (SERCOM3) USART Control B */
	REG_SERCOM3_USART_CTRLB = SERCOM_USART_CTRLB_TXEN | SERCOM_USART_CTRLB_RXEN;
	while(REG_SERCOM3_USART_STATUS & SERCOM_USART_STATUS_SYNCBUSY);

	// Enable SERCOM3 interrupts
	// RXC Receive Complete Interrupt Enabled
	// TXC Transmit Complete Interrupt Enabled
	// #define REG_SERCOM3_USART_INTENSET (*(RwReg8 *)0x4200140DUL) /**< \brief (SERCOM3) USART Interrupt Enable Set */
	REG_SERCOM3_USART_INTENSET = SERCOM_USART_INTENSET_RXC | SERCOM_USART_INTENSET_TXC;

	// Enable SERCOM3 NVIC Interrupt
	NVIC_EnableIRQ(SERCOM3_IRQn);

	// Enable SERCOM3
	// #define REG_SERCOM3_USART_CTRLA    (*(RwReg  *)0x42001400UL) /**< \brief (SERCOM3) USART Control A */
	REG_SERCOM3_USART_CTRLA |= SERCOM_USART_CTRLA_ENABLE;
	while(REG_SERCOM3_USART_STATUS & SERCOM_USART_STATUS_SYNCBUSY);
}

EDIT: Changed  the comments in block starting with "Set PMXEN bit for both PINCFG24 PIN_PA24 TXD and PINCFG PIN_PA25 RXD"

"I may make you feel but I can't make you think" - Jethro Tull - Thick As A Brick

"void transmigratus(void) {transmigratus();} // recursio infinitus" - larryvc

"It's much more practical to rely on the processing powers of the real debugger, i.e. the one between the keyboard and chair." - JW wek3

"When you arise in the morning think of what a privilege it is to be alive: to breathe, to think, to enjoy, to love." -  Marcus Aurelius

Last Edited: Tue. Mar 20, 2018 - 11:58 PM