I’m trying to use a hardware interrupt on a Teensy 3.6. I assume this all compiles fine within the Arduino IDE but have chosen PlatformIO for it’s much improved debugging capabilities.
By including these at the top of the source file: #include <avr/io.h> #include <avr/interrupt.h>
The code, should compile
ISR (USART1_RX_vect)
{
…
}
But instead, it’s as if the headers were never included in the build:
error: expected constructor, destructor, or type conversion before ‘(’ token
will compile perfectly fine due to the Teensy2.0++ being an Atmel AVR style AT90USB1286.
For an ARM based Teensy, look into the NVIC (nested vectored interrupt controller) and some code using it (here, here, the VECTOR table). Vectors can be dynamically re-appointed using NVIC_SetVector().
For some reason unknown to me, this function was stripped from the core_cm4.h header file (but is present in e.g. core_cm7.h). It can still be hacked in there by adding the initially removed code.
For changing the intterrupt vector for the, say, IRQ_UART0_STATUS (IRQs are listed here) you would ‘just’ do…
#include <Arduino.h>
#define NVIC_USER_IRQ_OFFSET 16
#ifndef __STATIC_INLINE
#define __STATIC_INLINE static inline
#endif
#ifdef __cplusplus
#define __I volatile /*!< Defines 'read only' permissions */
#else
#define __I volatile const /*!< Defines 'read only' permissions */
#endif
#define __O volatile /*!< Defines 'write only' permissions */
#define __IO volatile /*!< Defines 'read / write' permissions */
/* following defines should be used for structure members */
#define __IM volatile const /*! Defines 'read only' structure member permissions */
#define __OM volatile /*! Defines 'write only' structure member permissions */
#define __IOM volatile /*! Defines 'read / write' structure member permissions */
/**
\brief Structure type to access the System Control Block (SCB).
*/
typedef struct
{
__IM uint32_t CPUID; /*!< Offset: 0x000 (R/ ) CPUID Base Register */
__IOM uint32_t ICSR; /*!< Offset: 0x004 (R/W) Interrupt Control and State Register */
__IOM uint32_t VTOR; /*!< Offset: 0x008 (R/W) Vector Table Offset Register */
__IOM uint32_t AIRCR; /*!< Offset: 0x00C (R/W) Application Interrupt and Reset Control Register */
__IOM uint32_t SCR; /*!< Offset: 0x010 (R/W) System Control Register */
__IOM uint32_t CCR; /*!< Offset: 0x014 (R/W) Configuration Control Register */
__IOM uint8_t SHP[12U]; /*!< Offset: 0x018 (R/W) System Handlers Priority Registers (4-7, 8-11, 12-15) */
__IOM uint32_t SHCSR; /*!< Offset: 0x024 (R/W) System Handler Control and State Register */
__IOM uint32_t CFSR; /*!< Offset: 0x028 (R/W) Configurable Fault Status Register */
__IOM uint32_t HFSR; /*!< Offset: 0x02C (R/W) HardFault Status Register */
__IOM uint32_t DFSR; /*!< Offset: 0x030 (R/W) Debug Fault Status Register */
__IOM uint32_t MMFAR; /*!< Offset: 0x034 (R/W) MemManage Fault Address Register */
__IOM uint32_t BFAR; /*!< Offset: 0x038 (R/W) BusFault Address Register */
__IOM uint32_t AFSR; /*!< Offset: 0x03C (R/W) Auxiliary Fault Status Register */
__IM uint32_t PFR[2U]; /*!< Offset: 0x040 (R/ ) Processor Feature Register */
__IM uint32_t DFR; /*!< Offset: 0x048 (R/ ) Debug Feature Register */
__IM uint32_t ADR; /*!< Offset: 0x04C (R/ ) Auxiliary Feature Register */
__IM uint32_t MMFR[4U]; /*!< Offset: 0x050 (R/ ) Memory Model Feature Register */
__IM uint32_t ISAR[5U]; /*!< Offset: 0x060 (R/ ) Instruction Set Attributes Register */
uint32_t RESERVED0[5U];
__IOM uint32_t CPACR; /*!< Offset: 0x088 (R/W) Coprocessor Access Control Register */
} SCB_Type;
#define SCS_BASE (0xE000E000UL) /*!< System Control Space Base Address */
#define SCB_BASE (SCS_BASE + 0x0D00UL) /*!< System Control Block Base Address */
#define SCnSCB ((SCnSCB_Type *) SCS_BASE ) /*!< System control Register not in SCB */
#define SCB ((SCB_Type *) SCB_BASE ) /*!< SCB configuration struct */
__STATIC_INLINE void __NVIC_SetVector(IRQ_NUMBER_t IRQn, uint32_t vector)
{
uint32_t *vectors = (uint32_t *)SCB->VTOR;
vectors[(int32_t)IRQn + NVIC_USER_IRQ_OFFSET] = vector;
}
/* -- start of actual program --*/
void my_uart0_status_irq() {
//do stuff
}
void setup() {
//steal UART0 status IRQ
//disable first
NVIC_DISABLE_IRQ(IRQ_UART0_STATUS);
__NVIC_SetVector(IRQ_UART0_STATUS, (uint32_t) &my_uart0_status_irq);
NVIC_ENABLE_IRQ(IRQ_UART0_STATUS);
}
void loop() {
}
One might think that due to the ISRs being marked as weak, one should be able to override them. But if the framework already implements them themselves, overriding is not possible anymore.
So code like this
#include <Arduino.h>
/* overwrite UART0 status IRQ from C++ code. Must be linked with C linkage. */
extern "C" void uart0_status_isr() {
}
void setup() {
}
void loop() {
}
won’t work
arm-none-eabi/bin/ld.exe: Disabling relaxation: it will not work with multiple definitions
But instead cmp0_isr (comparator 0?) as a function name will succeed, because it’s not used by the framework. So you have 3 possibilities for getting your interrupt code running:
Steal handler for any IRQ using NVIC_SetVector
if the framework implements vector, change its base implementation.
if the framework doesn’t implement it, just implement it yourself using the decleration found above