interrupt handler in Atmel studio 7: SAMD without ASF

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

Hello,

 

I am programming in AS7 for SAMD-device without ASF.

I have already

#include "sam.h"

#include "component\... .h"

 

For other devices the

#include <avr\interupt.h>  and ISR(){...} worked. But for SAM there is no interupt.h.

How can I implement an interrupt-handler?
Please help.

I don't find any solution, but there is surely an easy one.

 

This topic has a solution.

Surprise: As soon as one's doing it correctly - it works!

Last Edited: Mon. Jun 22, 2020 - 08:06 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

 

DrDatasalad wrote:
For other devices the

#include <avr\interupt.h>  and ISR(){...} worked.

 

The clue is in the name there - AVR is an entirely different architecture from ARM !

 

One of the key features of Cortex-M is that it was specifically designed not to require any proprietary compiler magic for ISRs - on Cortex-M, ISRs are just plain vanilla 'C' functions.

 

The only thing you need to do is to put the ISRs address into the correct spot in the Vector Table.

 

Even though you're not actually using ASF, you should take a look at how it does it - you might as well take that as your model ...

 

EDIT

 

I would strongly recommend that you get a copy of this book - especially if you intend going "bare metal":

 

https://www.elsevier.com/books/the-definitive-guide-to-arm-cortex-m0-and-cortex-m0-processors/yiu/978-0-12-803277-0

 

 

EDIT 2

 

For a SAM-D10, the ASF file to look at is 

 

src\ASF\sam0\utils\cmsis\samd10\source\gcc\startup_samd10.c

 

There is a set of "weak" definitions there (which give a default handler), and you override the ones you want but just implementing a function with the same "signature".

 

This is pretty common across other manufacturers.

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
Last Edited: Fri. Jun 19, 2020 - 08:49 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

You get the startup file also for plain gcc projects, no need to look at ASF code.

/Lars

 

This reply has been marked as the solution. 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I use the SAML22, but the D21 interrupt is the same.  When you create a new project (using GCC C Executable project), you will get a file called startup_samd21.c generated.  Here you will find the IRQ vector table. To replace these vectors with your own, you just need to write a function with the same name.   For example to use the TC1 timer in your own code, you just need to include the function void TC1_Handler(void) in your own code.  This works because of the "weak" attribute on the Atmel provided functions, which means that your irq handler will be used instead of the Atmel version if your function has the same name.

 

 

John Malaugh

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

I am programming in AS7 for SAMD-device without ASF.

I have already

#include "sam.h"

#include "component\... .h"

First, I don't think you need the #include of the component/*.h files, because "sam.h" includes them for you...

 

 

For other devices the

#include <avr\interupt.h>  and ISR(){...} worked. But for SAM there is no interupt.h.

How can I implement an interrupt-handler?

Much of ARM Cortex-M interrupt processing is handled by hardware, so you don't need special function attributes like those added by AVR's "ISR(...)" macros.

SAM interrupt functions are simply C functions that happen to match the function names that are in the vector table included in the startup.c file (AS will normally consider the startup part of CMSIS, and CMSIS part of ASF, but you're already running into that with the component/* definitions.)

 

So for example, the startup_samd21.c has code for the vectors that looks like this:

 

/* Exception Table */
__attribute__ ((section(".vectors")))
const DeviceVectors exception_table = {

        /* Configure Initial Stack Pointer, using linker-generated symbols */
        (void*) (&_estack),

        (void*) Reset_Handler,
        (void*) NMI_Handler,
        (void*) HardFault_Handler,
        (void*) (0UL), /* Reserved */
        (void*) (0UL), /* Reserved */
        (void*) (0UL), /* Reserved */
        (void*) (0UL), /* Reserved */
        (void*) (0UL), /* Reserved */
        (void*) (0UL), /* Reserved */
        (void*) (0UL), /* Reserved */
        (void*) SVC_Handler,
        (void*) (0UL), /* Reserved */
        (void*) (0UL), /* Reserved */
        (void*) PendSV_Handler,
        (void*) SysTick_Handler,

        /* Configurable interrupts */
        (void*) PM_Handler,             /*  0 Power Manager */
        (void*) SYSCTRL_Handler,        /*  1 System Control */
        (void*) WDT_Handler,            /*  2 Watchdog Timer */
        (void*) RTC_Handler,            /*  3 Real-Time Counter */
        (void*) EIC_Handler,            /*  4 External Interrupt Controller */

 

If you wanted to add an interrupt handler for SysTick, you would just create a function in your code:

 

void SysTick_Handler() {
    ticks++;
}

 

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

But don't forget to clear the interrupt at the end of the interrupt handler, and that an interrupt from a particular peripheral can have several sources. 

An abbreviated  and commented example from a program to handle SERCOM USART interrupts from a GPS receiver:

#define GPS_SERCOM SERCOM0
/* GPS_Handler() was defined as the interrupt handler in the interrupt
  vector table
*/
void GPS_Handler()
{ Sercom *SERCOMp = GPS_SERCOM;

/* Only look at the flags which are actually used */
  uint8_t intflag = SERCOMp->USART.INTENSET.reg & SERCOMp->USART.INTFLAG.reg;

  if (intflag & SERCOM_USART_INTFLAG_RXC) /* char receive complete */
  {
/* Callback function to process the character received. GPSsercom_cb is
   a control block to store the data and state of the device
*/
  SERCOM_USART_GPS_rxc((void *) &GPSsercom_cb);
/* Clear the interrupt flag */
  SERCOMp->USART.INTFLAG.reg = SERCOM_USART_INTFLAG_RXC;
  }

  if (intflag & SERCOM_USART_INTFLAG_TXC) /* char transmission complete */
  { SERCOM_USART_txc((void *) &GPSsercom_cb);
  SERCOMp->USART.INTFLAG.reg = SERCOM_USART_INTFLAG_TXC;
  }

  if (intflag & SERCOM_USART_INTFLAG_DRE) /* TX data register empty */
  { SERCOM_USART_dre((void *) &GPSsercom_cb);
  SERCOMp->USART.INTFLAG.reg = SERCOM_USART_INTFLAG_DRE;
  }
} /* GPS_Handler() */

 

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

Thanks a lot for all your help!
Yes it was easier than i've expected.

Surprise: As soon as one's doing it correctly - it works!