Author Topic: SAMD21g18: How to configure interrupt on UART byte sent?  (Read 1425 times)

0 Members and 1 Guest are viewing this topic.

Offline renemanTopic starter

  • Contributor
  • Posts: 21
  • Country: 00
SAMD21g18: How to configure interrupt on UART byte sent?
« on: July 29, 2021, 08:53:35 am »
Hi, I've been reading the samd21 datasheet but I cannot seem to find if this is possible.
I would like to have a sercom configured as UART to send a byte (over the TX Line) and trigger an interrupt once the transmission has been completed.

Do you have any sample code to do this, or could you point me to the part of the datasheet where this is explained (if it's supported)?

Thank you
Always Learning
 

Offline mikerj

  • Super Contributor
  • ***
  • Posts: 3237
  • Country: gb
Re: SAMD21g18: How to configure interrupt on UART byte sent?
« Reply #1 on: July 29, 2021, 09:53:27 am »
This is certainly possible, though I don't have any example code.  The interrupt flag you need is called TXC (transmit complete) and it's action is (briefly) described in section 26.6.2.5 of the family datasheet. 

There is one interrupt vector for each USART, you have configure the INTENSET register for the events you want to raise an interrupt, TXC in your case.  Additionally you will need to configure the NVIC interrupt priority (NVIC_SetPriority) and enable the interrupt (NVIC_EnableIRQ) for the USART you wish to use.

In the interrupt handler, you need to check which event has caused the interrupt by reading the INTFLAG register and testing the bits.  You then should clear the interrupt by writing a 1 to the bit.

Note that if you want to send multiple bytes, then waiting for TXC after each one will not provide the best throughput.  The data register is double buffered, so you can load the next byte to send whilst the previous one is being transmitted, and you should use the Data Register Empty (INTFLAG.DRE) interrupt in this case to load the next byte in.  You'd likely only want to use TXC on the last byte in this case, so you can tell when it has been shifted out.
 
The following users thanked this post: reneman

Online ataradov

  • Super Contributor
  • ***
  • Posts: 11236
  • Country: us
    • Personal site
Re: SAMD21g18: How to configure interrupt on UART byte sent?
« Reply #2 on: July 29, 2021, 04:15:17 pm »
Here is an example of a complete interrupt-driven UART driver https://github.com/ataradov/vcp/blob/master/samd11/uart.c
Alex
 
The following users thanked this post: reneman

Offline renemanTopic starter

  • Contributor
  • Posts: 21
  • Country: 00
Re: SAMD21g18: How to configure interrupt on UART byte sent?
« Reply #3 on: August 02, 2021, 07:52:39 am »
Here is an example of a complete interrupt-driven UART driver https://github.com/ataradov/vcp/blob/master/samd11/uart.c

Could you provide an example of how to use the driver and configure the interrupt routine that is called when a byte is sent over uart?

Thank you
Always Learning
 

Online ataradov

  • Super Contributor
  • ***
  • Posts: 11236
  • Country: us
    • Personal site
Re: SAMD21g18: How to configure interrupt on UART byte sent?
« Reply #4 on: August 02, 2021, 03:57:33 pm »
This is the example. I don't understand what else do you need. UART_SERCOM_IRQ_HANDLER() is the interrupt handler, and "if (flags & SERCOM_USART_INTFLAG_RXC)" is the part that is executed when the byte is received.

Note that "#define UART_SERCOM_IRQ_HANDLER  irq_handler_sercom0" must match the actual name of the interrupt handler in the vector table. This depends on your startup code.
Alex
 

Offline renemanTopic starter

  • Contributor
  • Posts: 21
  • Country: 00
Re: SAMD21g18: How to configure interrupt on UART byte sent?
« Reply #5 on: August 03, 2021, 08:22:25 am »
This is the example. I don't understand what else do you need. UART_SERCOM_IRQ_HANDLER() is the interrupt handler, and "if (flags & SERCOM_USART_INTFLAG_RXC)" is the part that is executed when the byte is received.

Note that "#define UART_SERCOM_IRQ_HANDLER  irq_handler_sercom0" must match the actual name of the interrupt handler in the vector table. This depends on your startup code.

Ah, now I see. I was a bit confused, because I asked for TXC like @mikerj mentioned but your driver doesn't use it.

Will uart_write_byte() trigger an interruption as well, so in the handler can I do if(flags & SERCOM_USART_INTFLAG_TXC) { ... } ?
Always Learning
 

Offline renemanTopic starter

  • Contributor
  • Posts: 21
  • Country: 00
Re: SAMD21g18: How to configure interrupt on UART byte sent?
« Reply #6 on: August 03, 2021, 10:42:33 am »
This is the example. I don't understand what else do you need. UART_SERCOM_IRQ_HANDLER() is the interrupt handler, and "if (flags & SERCOM_USART_INTFLAG_RXC)" is the part that is executed when the byte is received.

Note that "#define UART_SERCOM_IRQ_HANDLER  irq_handler_sercom0" must match the actual name of the interrupt handler in the vector table. This depends on your startup code.

Ah, now I see. I was a bit confused, because I asked for TXC like @mikerj mentioned but your driver doesn't use it.

Will uart_write_byte() trigger an interruption as well, so in the handler can I do if(flags & SERCOM_USART_INTFLAG_TXC) { ... } ?

So, i've tested this. This is my ISR:

Code: [Select]
void irq_handler_sercom5(void)
{
  int flags = SERCOM5->USART.INTFLAG.reg;

  if (flags & SERCOM_USART_INTFLAG_TXC) //BYTE Sent
  {
    HAL_GPIO_LED_toggle();
  }

}

Which should toggle a led each time a byte is sent over uart

Then on main():

Edit: Adding
Code: [Select]
SERCOM5->USART.INTENSET.reg = SERCOM_USART_INTENSET_TXC; as mikerj suggested, the interrupt is now triggered (once). I think i need yet to acknowledge the interrupt so if works perfectly.

Code: [Select]
NVIC_EnableIRQ(SERCOM5_IRQn);

  while(1)
  {
    myclass.uart_putc('a');
    myclass.delay(1000);
  }

UART Works fine (byte is sent) but the led is never toggled. What am I missing?
« Last Edit: August 03, 2021, 11:00:48 am by reneman »
Always Learning
 

Online ataradov

  • Super Contributor
  • ***
  • Posts: 11236
  • Country: us
    • Personal site
Re: SAMD21g18: How to configure interrupt on UART byte sent?
« Reply #7 on: August 03, 2021, 04:15:21 pm »
Are you sure that in your startup code the interrupt handler is called  irq_handler_sercom5? I bet it is not.

So first of all, figure out of interrupt handler is called at all, then see what flags are set.
Alex
 

Offline renemanTopic starter

  • Contributor
  • Posts: 21
  • Country: 00
Re: SAMD21g18: How to configure interrupt on UART byte sent?
« Reply #8 on: August 04, 2021, 07:47:50 am »
Are you sure that in your startup code the interrupt handler is called  irq_handler_sercom5? I bet it is not.

So first of all, figure out of interrupt handler is called at all, then see what flags are set.

It was. Only thing missing was SERCOM5->USART.INTFLAG.bit.TXC = 1; at the end of the interrupt routine.
Thanks guys
Always Learning
 

Online ataradov

  • Super Contributor
  • ***
  • Posts: 11236
  • Country: us
    • Personal site
Re: SAMD21g18: How to configure interrupt on UART byte sent?
« Reply #9 on: August 04, 2021, 08:00:06 am »
SERCOM5->USART.INTFLAG.bit.TXC = 1;
This is incorrect. This will clear all the bits, not just TXC. The correct way of clearing a single bit is this:

SERCOM5->USART.INTFLAG.reg = SERCOM_USART_INTFLAG_TXC;

Also, in most cases you actually want to use DRE, as my code does, not TXC.
Alex
 

Offline renemanTopic starter

  • Contributor
  • Posts: 21
  • Country: 00
Re: SAMD21g18: How to configure interrupt on UART byte sent?
« Reply #10 on: August 05, 2021, 10:31:46 am »
SERCOM5->USART.INTFLAG.bit.TXC = 1;
This is incorrect. This will clear all the bits, not just TXC. The correct way of clearing a single bit is this:

SERCOM5->USART.INTFLAG.reg = SERCOM_USART_INTFLAG_TXC;

Also, in most cases you actually want to use DRE, as my code does, not TXC.

What's the difference between DRE and TXC?
Always Learning
 

Online ataradov

  • Super Contributor
  • ***
  • Posts: 11236
  • Country: us
    • Personal site
Re: SAMD21g18: How to configure interrupt on UART byte sent?
« Reply #11 on: August 05, 2021, 04:38:12 pm »
What's the difference between DRE and TXC?
There are two buffers. One is the data buffer and one is the shift register. DRE is set when the value from the data register moved to the shift register. The value is not yet shifted out, but SERCOM is already ready to accept the new data.

TXC is set when the byte is actually sent.

So if you use DRE, then you have a whole byte duration to react to the interrupt in order to ensure solid uninterrupted stream of bytes. If you use TXC, then you will have gaps between the bytes while firmware reacts to the interrupt and  sends a next byte.

The only time TXC matters is when device goes to sleep right after sending the byte, for example. In this case you can still use DRE, but also poll for TXC before going to sleep to let it send out the last byte.
Alex
 
The following users thanked this post: reneman


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf