Search code examples
embeddedmicrocontrolleratmelmicrochipfirmware

How does a hardware interrupt trigger software handlers without any prior setup


I am currently learning about processor interrupts, and have run into some confusions. From what I understand, a processor has a set of external interrupts for peripherals. That way manufactures can provide a way to interrupt the processor via their own peripherals. I know that with this particular processor (ARM Cortex M0+) that once an external interrupt line is triggered, it will go to it's vector table and corresponding interrupt request offset and (I could be wrong here) will execute the ARM thumb code at that address.

And if I understand correctly, some processors will look at the value at said IRQ address, which will point to the address of the interrupt handler.

Question 1

While learning about the ARM Cortex M0+ vector table, what is the thumb code doing at that address? I am assuming it is doing something like setting the PC register to the interrupt handler address, but that is just a stab in the dark.

Question 2

Also the only way that I have found so far to handle the EIC interrupts is to use this following snippet

void EIC_Handler() {
  // Code to handle interrupt
}

I am perplexed how this function is called without setup or explicit reference to it in my actual c code. How does the program go from vector table look up to calling this function?

EDIT #1:

I was wrong about the vector table containing thumb code. The vector table contains addresses to the exception handlers.

EDIT #2:

Despite getting the answer I was looking for, my question apparently wasn't specific enough or was "off-topic", so let me clarify.

While reading/learning from multiple resources on how to handle external interrupts in software, I noticed every source was saying to just add the code snippet above. I was curious how the interrupt went from hardware, all the way to calling my EIC_Handler() without me setting anything up other than defining the function and the EIC. So I researched what a vector table is and how the processor will go to certain parts of it when different interrupts happen. That still didn't answer my question, as I wasn't setting up the vector table myself, yet my EIC_Handler() function was still being called.

So somehow at compile time, the vector table had to be created and the corresponding IRQ handle pointing to my EIC_Handler(). I searched through a good amount of SAML22 and Cortex M0+ documentation (and mis-read that the vector table contained thumb code) but couldn't find anything on how the vector table was being set up, which is why I decided to look for an answer here. And I got one!

I found that the IDE (Atmel studio) and the project configuration I had chosen came along with a little file defining weak functions, implementation of the reset handler, and the vector table. There was also a custom linker script grabbing the addresses to the functions and putting them into the vector table, which if a weak function was implemented, it would point to that implementation and call it when the appropriate interrupt request occurred.


Solution

  • For the Cortex M0 (and other cortexes? corticies?) the vector table doesn't contain thumb code, it is a list of addresses of functions which are the implementation of your exception handlers.

    When the processor gets an exception it first pushes a stack frame (xPSR, PC, LR, R12, R3-R0) to the currently active stack pointer (MSP or PSP), it then fetches the address of the exception handler from the vector table, and then starts running code from that location.

    When there is a POP instruction which loads the PC, or a BX instruction from within the exception handler the processor returns from the exception handler, it destacks the stack frame which was pushed and carries on executing from where it left off. This process is explained in the Cortex M0+ User Guide - Exception Entry And Exit

    For question 2, the vector table in the Cortex M0/M0+ is usually located at address 0x00000000. Some Cortex M0/M0+ implementations allow remapping of the vector table using a vector table offset register within the system control block, others allow you to remap which memory is available at address 0x00000000.

    Depending on which tool set/library you're using there are different ways of defining the vector table, and saying where it should live in memory.

    There are usually weakly linked functions with the name of the exceptions available for your microcontroller, which when you implement them in your source files are linked instead of the weak functions, and their addresses get put into the vector table.

    I have no experience with Atmel based ARMs, but @Lundin in the comments says the vector table is located in a "startup_samxxx.c" file. If you've started from scratch it is up to you to ensure you have a suitable vector table, and it's located in a sensible place.