Timer Interrupt Uno R4 Minima

Hi,

I want to use a timer interrupt on my Arduino Uno R4 Minima to execute a function in parallel to my program after a certain period (490 Hz). For the Uno R3 I have already managed this without problems for the timer 2 with the library TimerTwo.
Since there is no library for the R4 yet, I have to set the registers myself. But I can't find the right registers in the datasheet to set the timer interrupt. Can someone help me?

Thanks in advance,
Celine

1 Like

Phil Schatzmann wrote some very clean instruction that should allow easily replacing TimerTwo
Under the Hood: Arduino UNO R4 - Timers - Phil Schatzmann :slight_smile:

2 Likes

Thanks a lot!
I actually was on that website before, but didn't realize that there is a solution for my problem.

Not sure if i am in the right spot... I have done interrupt programming in the R3 that looks like the following below. Does this work in the R4 Uno? I am thinking maybe not. What would be the equivalent?

void setup() {
pinMode(11,OUTPUT); //LED pin (to blink in 50Hz frequency)
cli();//stop all interrupts
// turn on CTC mode
TCCR1A = 0;// set entire TCCR1A register to 0
TCCR1B = 0;// same for TCCR1B
TCCR1B |= (1 << WGM12);
TCCR1B |= (1 << CS11);
TCNT1 = 0;
// set timer count for 50Hz increments
OCR1A = 39999;
TIMSK1 |= (1 << OCIE1A);
sei();//allow interrupts
}
ISR(TIMER1_COMPA_vect) {//Interrupt at frequency of 50 Hz
digitalWrite(11,HIGH);
delay(15);
digitalWrite(11,LOW);
}

The R4 stepper program example in the following link looks like it does something similiar to the stepper interrupt control I was doing on the R3. Will try it and see how it does.

UNO R4 Wifi two 0.5 usec timers possible? - Using Arduino / Programming Questions - Arduino Forum

Thanks for your effort!

Just using the UNO R4 minima for the first time (using STM32 boards mostly).

I noticed that the warning still is being displayed?
WARNING: library TimerOne-1.1.1 claims to run on avr architecture(s) and may be incompatible with your current board which runs on renesas_uno architecture(s).

its that correct?

Not at all :relieved:.

But I am using your version from GitHub and the message stil appears. So I was wondering if your version stil generates that message.

I submitted a pull request to fix a problem with the metadata in @Delta_G's fork of the TimerOne that caused the warning to be displayed even though UNO R4 Minima support was added:

I have some 'bare metal' code for setting up timer interrupts on the Arduino R4 Minima that I share below. It is quite generic and can also be used to setup pin change interrupts on most pins. I have found i quite useful and maybe this can be of help. The code sets up a counter overflow interrupt on GPT7 and installs an ISR that increments a counter once every 1 msec. The pin change interrupt ISR stops the GPT on a falling edge on D2.

/**********************************************************************
 *                        Arduino UNO R4 Minima
 *             Renesas RA4M1 (Arm Cortex-M4), R7FA4M1AB3CFM
 *                       MCU: R7FA4M1AB3CFM (LQFP64)
 *
 *********************************************************************/
static const int dly_msec = 500;
static const IRQn_Type IRQn_OVF7 = IRQn_Type(16);    // Valid range is [0,31] but don't use low numbers
static const IRQn_Type IRQn_PCHGD2 = IRQn_Type(17);  // Valid range is [0,31] but don't use low numbers
static volatile int t7_cnt = 0;
static int cnt = 0;

//*********************************************************************
void gpt7_ovf_isr() {
  // Clear interrupt flag
  R_ICU->IELSR_b[IRQn_OVF7].IR = 0;
  // Increment GPT7 counter
  t7_cnt++;
}

//*********************************************************************
void pin_change_isr() {
  // Clear interrupt flag
  R_ICU->IELSR_b[IRQn_PCHGD2].IR = 0;
  // Stop GPT7
  R_GPT7->GTCR_b.CST = 0;
  // On-board LED off
  digitalWrite(LED_BUILTIN, LOW);
  // Clear GPT7 counter
  t7_cnt = 0;
}

//*********************************************************************
void setup_pin_change_interrupt() {

  // Pin change interrupt on pin D3/P104/IRQ1
  // See chapter 1.7 Pin Lists for LQFP64

  // Setup I/O pin P104
  //R_PFS->PORT[1].PIN[4].PmnPFS_b.PODR = 0b0;   // Low
  //R_PFS->PORT[1].PIN[4].PmnPFS_b.PDR = 0b0;    // Input
  //R_PFS->PORT[1].PIN[4].PmnPFS_b.PMR = 0b0;    // I/O pin

  R_PFS->PORT[1].PIN[4].PmnPFS_b.PCR = 0b1;    // Enable pull-up
  R_PFS->PORT[1].PIN[4].PmnPFS_b.EOFR = 0b10;  // Event on falling edge
  // Tables 19.5 and onwards
  R_PFS->PORT[1].PIN[4].PmnPFS_b.ISEL = 0b1;  // Use as IRQn pin

  // The Interrupt Controller Unit (ICU) controls which event signals are linked to the Nested Vector Interrupt Controller
  // (NVIC), Data Transfer Control (DTC), and Direct Memory Access Controller (DMAC) modules.
  // See Table 13.3 Interrupt vector table
  // See Table 13.4 Event table
  // There are 47 exceptions that can be connected to events, Table 13.3
  // The first 16 exceptions are fixed NMIs, the first user definable
  // exception is number 16 = interrupt number 0, valid interrupt numbers are [0, 31]
  // To assign which event that triggers which interrupt, set:
  // R_ICU->IELSR[IRQn] = EVENTn;

  // LQFP64 D2/P104/IRQ1, Table 13.4, table 18.3, table 19.5
  // Select the IRQn_PCHG2 interrupt to be triggered by the pin change event IRQ1 (2)
  R_ICU->IELSR_b[IRQn_PCHGD2].IELS = ELC_EVENT_ICU_IRQ1;
  // Install the ISR in the IRQn_PCHGD2 interrupt vector element
  NVIC_SetVector(IRQn_PCHGD2, (uint32_t)pin_change_isr);
  // Set a suitable interrupt priority
  NVIC_SetPriority(IRQn_PCHGD2, 12);
  // Enable the interrupt
  NVIC_EnableIRQ(IRQn_PCHGD2);
}

//*********************************************************************
void setup_gpt7() {

  // Enable peripherals
  // RA4M1 User’s Manual: Hardware, chapter 10.2.5, Module stop control register D
  //R_MSTP->MSTPCRD_b.MSTPD5 = 0;  // Enable 32-bit GPT321 to GPT320, GPT0, GPT1
  R_MSTP->MSTPCRD_b.MSTPD6 = 0;  // Enable 16-bit GPT167 to GPT162, GPT2-GPT7

  // The Interrupt Controller Unit (ICU) controls which event signals are linked to the Nested Vector Interrupt Controller
  // (NVIC), Data Transfer Control (DTC), and Direct Memory Access Controller (DMAC) modules.
  // See Table 13.3 Interrupt vector table
  // See Table 13.4 Event table
  // There are 47 exceptions that can be connected to events, Table 13.3
  // The first 16 exceptions are fixed NMIs, the first user definable
  // exception is number 16 = interrupt number 0, valid interrupt numbers are [0, 31]
  // To assign which event that triggers which interrupt, set:
  // R_ICU->IELSR[IRQn] = EVENTn;

  // Select the IRQn_OVF7 interrupt to be triggered by the GPT7 overflow event (0x95 = 149, Table 13.4)
  R_ICU->IELSR_b[IRQn_OVF7].IELS = ELC_EVENT_GPT7_COUNTER_OVERFLOW;
  // Install the ISR in the IRQn_OVF7 interrupt vector element
  NVIC_SetVector(IRQn_OVF7, (uint32_t)gpt7_ovf_isr);
  // Set a suitable interrupt priority
  NVIC_SetPriority(IRQn_OVF7, 12);
  // Enable the interrupt
  NVIC_EnableIRQ(IRQn_OVF7);

  // Timer counter
  R_GPT7->GTCNT = 0;
  // Timer period, pwm period
  R_GPT7->GTPR = 48000 - 1;  // OVF interrupt every 1000 usec at PS=1 and f_MCU 48 MHz
  // Zero timer control register
  R_GPT7->GTCR = 0;
  // Timer pre-scaler
  R_GPT7->GTCR &= ~(0b111 << 24);  // Clear bits, PS = 1
  //R_GPT7->GTCR |= (0b011 << 24);  // PS = 64, 64/48 = 4/3 usec per TCLK
  //R_GPT7->GTCR |= (0b101 << 24);  // PS = 1024
  // Start timer
  R_GPT7->GTCR_b.CST = 1;
}

//*********************************************************************
void setup() {
  Serial.begin(9600);
  //Serial.dtr();  // Only needed for Arduino R4 Minima
  pinMode(LED_BUILTIN, OUTPUT);
  digitalWrite(LED_BUILTIN, LOW);
  setup_gpt7();
  setup_pin_change_interrupt();
}

//*********************************************************************
void loop() {

  for (t7_cnt = 0; t7_cnt < dly_msec;) {}
  digitalWrite(LED_BUILTIN, HIGH);

  for (t7_cnt = 0; t7_cnt < dly_msec;) {}
  digitalWrite(LED_BUILTIN, LOW);

  cnt++;
  Serial.print(" Counter value = ");
  Serial.println(cnt);
}

Yes, you are absolutely correct. The 32 interrupt vector positions may be populated by other conflicting activities. The only checking I did was to print out all the interrupt vector elements in the setup() function and then found that only the four or five lowest vector elements contained values (addresses) different from zero. So setting up timer interrupts this way is outside the 'Arduino API', but I could not find a way to do it with the Arduino API for the Arduino R4 Minima or the Arduino R4 WiFi. So this became my 'least bad solution'.
Tomas

Excellent, thank you Delta_G.

The "cfg.irq = FSP_INVALID_VECTOR" did the trick.

Do you know if the FSP management of interrupt vectors also is consistent with Arduino API calls such as the attachInterrupt(...)?
(Maybe the more correct question is if the Arduino API builds on the Renesas FSP.)

Once again thank you,
Tomas.