Real time timer, SLCK, IRQ... debug timer and interrupt

Hi.

I try to write a library for real time timer of sam3x to get an interrupt each second.

I’ve played a lot with the arduino DUE but it is the first time I try to use a peripheric without any example.

I have read the data sheet, and try to compare code of RTT (real time timer) to other peripheric like Tc.

Then, RTT is very simple but my first test give me 2 bugs:
1: my goal is to set timer at 1 Hz. from the data sheet, it is achieve by setting prescaler to 0x8000, so same count as SLCK frequency (RTT increment is SLCK / prescaler).
But I do not get the expected result.
The timer seem to not be accurate always… if I compare it to millis, it is good 6 time, then, one time it is not.

also, the goal is to trig a ISR at each increment, I set the RTTINCIEN bit and define RTT_Handler, but the ISR is never laugh, I do not know if I have something else to do to configure this…

note: compile with PlatformIo

here all file I use for this:

header:

#ifndef DUE_REAL_TIMER
#define DUE_REAL_TIMER

#include <Arduino.h>

#define RTT_PRESCALER 0x8000

class DueRealTimer {
    public:
    DueRealTimer();
    void init( void (*_callback)() );
    void (*callback)();
    uint32_t getTime();

    private:
    friend void RTT_Handler();
    
};

extern DueRealTimer dueRealTimer;

#endif

cpp:

#include "DueRealTimer.h"


DueRealTimer::DueRealTimer() {

}


void DueRealTimer::init( void (*_callback)() ) {
    //NVIC_DisableIRQ( RTT_IRQn );
    //NVIC_ClearPendingIRQ( RTT_IRQn );
    callback = _callback;
    //RTT_GetStatus( RTT ); //read status to clear IRQ and alarm count
    RTT_SetPrescaler( RTT, RTT_PRESCALER ); //set timer to 1Hz
    RTT_EnableIT( RTT, RTT_MR_RTTINCIEN ); //enable increment interrupt
    //NVIC_EnableIRQ( RTT_IRQn );   
}

uint32_t DueRealTimer::getTime() {
    uint32_t value;
    do {
        value = RTT_GetTime( RTT );
    } while ( value != RTT_GetTime( RTT ) );// read the register twice at the same value to improve accuracy
}


DueRealTimer dueRealTimer;

inline void RTT_Handler ( void ) {
    RTT_GetStatus( RTT ); //read status to clear IRQ and alarm bits
    dueRealTimer.callback();
}

ino:

#include "DueRealTimer.h"

volatile uint32_t count = 0;
volatile bool t = false;

uint32_t lastMillis = 0;
uint32_t lastCount = 0;

void isr() {
  count++;
  t = true;
}

void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200);
  dueRealTimer.init(isr);
  delay(2000);
  Serial.print("slow clock");
  Serial.print(CHIP_FREQ_SLCK_RC);
  Serial.print("RTT_MR: ");
  Serial.println(RTT->RTT_MR, BIN);
}

void loop() {
  // put your main code here, to run repeatedly:
  Serial.print("read RTT: ");
  Serial.print( dueRealTimer.getTime() );
  //Serial.print(" count: ");
  //Serial.print(count);
  if( t ) {
    Serial.println("irs trigged");
    t = false;
  }
  int period = (millis()-lastMillis) / (dueRealTimer.getTime()-lastCount);
  Serial.print(" RTT period: ");
  Serial.println(period);
  lastMillis = millis();
  lastCount = dueRealTimer.getTime();
  delay(1000);
}

Thanks

An example sketch to trigger an interrupt at 1 Hz frequency:

const uint32_t AL = 0;
volatile boolean flag = 0;

void setup() {
  Serial.begin(250000);

  RTT->RTT_MR = RTT_MR_RTTRST
                | RTT_MR_RTPRES (32768) // T = 1 second
                | RTT_MR_ALMIEN;
  RTT->RTT_AR = RTT_AR_ALMV(AL); //Defines the alarm value (ALMV+1) compared with the Real-time Timer
  NVIC_EnableIRQ(RTT_IRQn);

}

void loop() {

  if (flag == 0) {
    Serial.println("Hello");
    flag = 1;
  }
}

void RTT_Handler () {
  /* To prevent several executions of the interrupt handler,
     the interrupt must be disabled in the interrupt handler
     and re-enabled when the status register is cleared.
  */
  RTT->RTT_MR &= ~RTT_MR_ALMIEN;
  RTT->RTT_SR;
  RTT->RTT_AR = RTT_AR_ALMV(AL);
  RTT->RTT_MR |= RTT_MR_ALMIEN;
  RTT->RTT_MR |= RTT_MR_RTTRST;
  flag = 0;
}

What is your experience with platform.io, is it not too slow?

@ard_newbie :

I was trying to use counter increment interrupt instead of alarm, but ether way, it do not work.

ISR is not call...

with my example, I add check RTT_MR and the the bit 15 is on, for 32768, and the bit 17 for the increment interrupt.

And a just check into the loop, the status register bit 2: RTTINC: Real-time Timer Increment,

It is set to 1. so the interrupt should be called... What I missing?

@phr3ak:

is it not too slow?

for what? compile? May be the first compilation, it is a little longer but after, it is the same or even better.

For the rest, I really love the intellisence of visual studio code, it avoid me many typos... Also I like to compile with command prompt, with a full screen and all warning on...

Also, as I mention, the timing seems wrong, I made another test loop:

void loop() {
  if ( dueRealTimer.getTime() != lastCount ) {
    Serial.print("Timing = ");
    Serial.println(millis()- lastMillis);
    lastMillis = millis();
    lastCount =  dueRealTimer.getTime();
  }
}

setup() print me the RTT_MR to : 101000000000000000
as expected

loop print me:

Timing = 1178
Timing = 1178
Timing = 1178
Timing = 1177
Timing = 1177
Timing = 1178
Timing = 1177
Timing = 1178
Timing = 1177

that should not be... should be around 1000...

Clone boards does not have external 32.768k XTAL for RTC. Is it the problem?

it is not a clone.

futher test, seem that if I set presclaler at 27830, I got close to a 1000ms tick, +-1 ms.

Ok, more developpement, I fix a little typo into init function, I was enabling RTC_IRQn instead of RTT_IRQn… fix and edit into code…

But the IRQ still not trig.

Even more I add this check in my loop and it return true:

   if ( NVIC_GetPendingIRQ( RTT_IRQn ) ) {
      Serial << "pending IRQ" << endl;
    }

@ard_newbie A should try your sketch as is at the beginning ... I was only comparing it with mine on library.

After try it, I move peace by peace the cone into library and here what I found:

It is strange, it is when I put the NVIC_EnableIRQ inside the library, in init function that it sis not work...

any idea why ??

I would test it but I'm afraid it cannot work on a clone board. Why using RTT is so crucial?

It is not crucial, it is more for the fun of it, to learn, probably to try to make my own version of time library...
With an automatic time increase.

But now, there is some progress: for the timing, I change the way I test it and, in fact, I was wrong.

Averaging value, compare to micros this time, I get a more fit value.

The average was about 10us different. But it could be cause by the async timing of MCK and SLCK.

Or, here a question: how precise are the 32768xtal of SLCK? is it thermally compensated ?

anyway, seems good enough.

Now for the interrupt problem, I must do something wrong as always... I add to much function, test and comment muted... so, I restard the example of ard_newbie, try to make thing work as close as I want it to do, then I will tray to put it into library... we should see then.

Now a new question:

The way I want it to work, I want a count value to be increment into the ISR (or a callback that do it anyway...).

But first test, each time the interrupt in trigged, the count in increment by at least 30, even more... instead of one.
The way I understand it: the interrupt is trigged by RTT->RTT_SR, reading it reset it state at 0.

But changing vale of enable interrupt of RTT_SR take 2 SLCK cycle to apply, so the interrupt is call many time.

I tried to disable nvic RTT_IRQn, did not help

So I try to wait for RTT_SR to be 0 to increment count... here to way I fount, if condition or while loop...

Note that I bring back using increment interrupt instead alarm, but it was the same behavior.

void RTT_Handler () {
  /* To prevent several executions of the interrupt handler,
     the interrupt must be disabled in the interrupt handler
     and re-enabled when the status register is cleared.
  */
  RTT->RTT_MR &= ~RTT_MR_RTTINCIEN;
  //method 1
  while(RTT->RTT_SR != 0); //wait status register to reset
  count++;
  //methode 2
  if ( RTT->RTT_SR == 0) {
    count++;
  }

  RTT->RTT_MR |= RTT_MR_RTTINCIEN;
  flag = 0;
}

Is there one of the 2 method that is good, or a better way ?

Conclusion: I’m a dummie…

I knew it will be something very stupid: a was eciting the library inside platformIO folder, but I add the arduino library folder into property to use streaming library to troubleshoot.

But the linker was using this library instead of the one I was working on… I found it by hazard…

So, the good solution was always post #1 from ard_newbie.

That lest me only the question in my previous post: about the multi interrupt call.

Thank all.