Timer and register definitions

Status
Not open for further replies.

cbAMDC

Member
Hello everyone!

Due to the beefy nature of the Teensy 4.0 we're trying to run some complex code on it, which requires quite some computational power.
Since many software components run in parallel (well, not really, but you know what I mean) we use an actor framework that ties into hardware timers and uses interrupts to send messages to the actors.

The 3rd party framework uses several low-level functions to achieve this. I've already successfully compiled a few simple examples for the teensy, but for some reason now the code won't compile any more, even though it hasn't changed. I suspect that some header files defining the registers and timers cannot be found any more. Some of the definitions that cannot be found are:

NVIC_SetPriority
TC3_IRQn
pmc_set_writeprotect()
NVIC_EnableIRQ()
...

I've searched this forum for these functions and could see, that some other people apparently were using some of these, so these function should be defined as part of the Teensyduino library I guess.
Complete uninstalling Arduino and Teensyduino and reinstalling both did not fix the issue.

So, TLDR:
In which files are NVIC_SetPriority and pmc_set_writeprotect() defined?

Regards,
Christian
 
I've found Agent Ransack to be an invaluable tool for answering questions like this.

I used that tool to go through the teensy files and some of the macros are defined in:
core_cm7.h

However, that file doesn't seem to be referenced by teensyduino and cannot be included manually because it references a missing file.
So, I'm at a loss :-(
 
Using editor here SublimeText has inbuilt global search.

Only two instances of pmc_set_writeprotect are under non-Teensy hardware ???:
Code:
#elif defined(__SAM3X8E__) // Arduino Due
// ...
  pmc_set_writeprotect(false);

So this is trying to port Teensy Arduino to another build platform?
 
I was/am going to ask many of the same questions and same answers as @defraster.

I use global search and replace in SublimeText.

Helps to know what build system you are using, on what platform, what framework...

As you noticed some of these are defined in cores\teensy4\core_cm7.h ... (NVIC_ functions).
But I don't believe we use these.

Instead we use the Macros that are defined in imxrt.h like:

Code:
#define NVIC_ENABLE_IRQ(n)      (*(&NVIC_ISER0 + ((n) >> 5)) = (1 << ((n) & 31)))
#define NVIC_DISABLE_IRQ(n)     (*(&NVIC_ICER0 + ((n) >> 5)) = (1 << ((n) & 31)))

and likewise:
Code:
// 0 = highest priority
// Cortex-M7: 0,16,32,48,64,80,96,112,128,144,160,176,192,208,224,240
#define NVIC_SET_PRIORITY(irqnum, priority)  (*((volatile uint8_t *)0xE000E400 + (irqnum)) = (uint8_t)(priority))
#define NVIC_GET_PRIORITY(irqnum) (*((uint8_t *)0xE000E400 + (irqnum)))


#define __disable_irq() __asm__ volatile("CPSID i":::"memory");
#define __enable_irq()  __asm__ volatile("CPSIE i":::"memory");

Also functions like:
Code:
#ifdef __cplusplus
extern "C" void (* _VectorsRam[NVIC_NUM_INTERRUPTS+16])(void);
static inline void attachInterruptVector(IRQ_NUMBER_t irq, void (*function)(void)) __attribute__((always_inline, unused));
static inline void attachInterruptVector(IRQ_NUMBER_t irq, void (*function)(void)) { _VectorsRam[irq + 16] = function; asm volatile("": : :"memory"); }
#else
extern void (* _VectorsRam[NVIC_NUM_INTERRUPTS+16])(void);
static inline void attachInterruptVector(enum IRQ_NUMBER_t irq, void (*function)(void)) __attribute__((always_inline, unused));
static inline void attachInterruptVector(enum IRQ_NUMBER_t irq, void (*function)(void)) { _VectorsRam[irq + 16] = function; asm volatile("": : :"memory"); }
#endif

Have no idea on the TC3... or pmc_...
 
Thank you for your replies and sorry about the confusion.

We're using a Visual Studio Arduino plugin (VisualMicro) to compile and upload the code to the teensy. This plugin either goes through the Arduino IDE or optionally uses the GNU-ARM compiler. As comfortable as it is this also means that the whole build chain is not very transparent.

The actor framework we use was ported to Arduino SAM-devices, which is why it seems to compile fine for the Arduino Due. In the meantime the framework-vendor provided the information, that the pmc_set_writeprotect() function is provided by Arduino for SAM devices. From anything I found out now I think it never should have compiled for Teensy in the first place, but strangely enough, it did. However, I never checked whether the code actually works on the real controller.

This is the part of the framework example code, that causes the issues:

Code:
void QF::onStartup(void) {
    // configure the timer-counter channel........
    pmc_set_writeprotect(false);   // disable write protection
    pmc_enable_periph_clk(TIMER_IRQn); // enable peripheral clock
    TC_Configure(TIMER, TIMER_CHANNEL,
                 TC_CMR_WAVE           // WAVE mode
                 | TC_CMR_WAVSEL_UP_RC // count-up with trigger on RC compare
                 | TC_CMR_TCCLKS_TIMER_CLOCK4);  // internal Clock4
    TC_SetRC(TIMER, TIMER_CHANNEL,
             TIMER_CLCK_HZ / BSP::TICKS_PER_SEC); // set the RC compare value
    TC_Start(TIMER, TIMER_CHANNEL);
    // enable interrrupt for RC compare
    TIMER->TC_CHANNEL[TIMER_CHANNEL].TC_IER = TC_IER_CPCS;
    TIMER->TC_CHANNEL[TIMER_CHANNEL].TC_IDR = ~TC_IER_CPCS;
    pmc_set_writeprotect(true); // enable write protection

    // explicitly set the NVIC priorities for all "kernel AWARE" interrupts
    // NOTE: This is important!
    NVIC_SetPriority(TIMER_IRQn,  QF_AWARE_ISR_CMSIS_PRI);
    // ...

    // enable the interrupts in the NVIC
    NVIC_EnableIRQ(TIMER_IRQn);
    // ...
}

From what I understand it creates a timer, which periodically raises interrupts with a specified priority. The priority part is important, since the interrupt for the client code needs to be above that of the framework in order to allow the framework scheduler to do its job.

Edit:

By throwing out the fine-grained timer and interrupt control and using PeriodicTimer instead I could get the example to work:

Code:
#define __NVIC_PRIO_BITS               4         /**< Number of priority bits implemented in the NVIC */

IntervalTimer T1;
//............................................................................
void QF::onStartup(void) {

    T1.priority(QF_AWARE_ISR_CMSIS_PRI);
    T1.begin(TIMER_HANDLER, 1.0 / BSP::TICKS_PER_SEC * 1e6);

}
//............................................................................


However, I had to look up the value for the __NVIC_PRIO_BITS macro, which is defined in core_cm7.h.

With these modifications the example runs successfully on the actual hardware... a big step for me!

But now the question is: how many IntervalTimers does the Teensy 4 support? This information seems to be missing on the corresponding site.

Regards,

Christian
 
Last edited:
Status
Not open for further replies.
Back
Top