0

I am writing a program for an nRF52 based board using the Redbear Arduino Library. Effectively treating my board as a BLE Nano 2.

I have a timer that ticks every x milliseconds, for example 50ms.

Inside that timer I would like to read data from an I2C sensor and add the reading to a buffer.

I am aware that by default, when inside the timer ISR, interrupts are disabled. I would like to know how to briefly re-enable the I2C interrupt, and get the sensor reading, then disable the interrupts again.

The interval between sensor readings is critical, and I don't just want to set a flag in the timer ISR as I don't know how long it will be before that flag is checked.

Please can someone instruct me on how to breifly enable the I2C interrupts from within a timer ISR?

I have experimented with:

__disable_irq();

__enable_irq();

NVIC_EnableIRQ(SPI0_TWI0_IRQn);

NRF_TWI0->INTENSET = 1;

No joy with any of these, I understand that some of them only work from certain locations in software, so were not functioning correctly within an ISR.

void setup() {
  // put your setup code here, to run once
  NVIC_SetPriority (TIMER0_IRQn, 2);
  NVIC_SetPriority (TIMER1_IRQn, 2);
  NVIC_SetPriority (TIMER2_IRQn, 2);
  NVIC_SetPriority (SPI0_TWI0_IRQn, 3);
  NVIC_SetPriority (SPI1_TWI1_IRQn, 3);
  Serial.begin(9600);
  Serial.println("Start ");
  Serial.print("Priority of TWI0: ");
  Serial.println(NVIC_GetPriority (SPI0_TWI0_IRQn));
  Serial.println(NVIC_GetPriority (SPI1_TWI1_IRQn));
  Serial.print("Priority of Ticker: ");
  Serial.println(NVIC_GetPriority (TIMER0_IRQn));
  Serial.println(NVIC_GetPriority (TIMER1_IRQn));
  Serial.println(NVIC_GetPriority (TIMER2_IRQn));


  Wire.begin();
  __disable_irq();
  __enable_irq();
  ticker1s.attach(task_handle, 1);
  Wire.requestFrom(0x02,6);

}

void task_handle(void) {
  __enable_irq();
  Serial.println("Task handle ");
  Serial.println("-IRQ enable status: ");
  Serial.println(NVIC_GetEnableIRQ(SPI0_TWI0_IRQn));
  Serial.println(NVIC_GetEnableIRQ(SPI1_TWI1_IRQn));
  NVIC_EnableIRQ(SPI0_TWI0_IRQn);
  NRF_TWI0->INTENSET = 1;

  NVIC_EnableIRQ(SPI1_TWI1_IRQn);
  NRF_TWI1->INTENSET = 1;
  Serial.println("-IRQ enable status: ");
  Serial.println(NVIC_GetEnableIRQ (SPI0_TWI0_IRQn));
  Serial.println(NVIC_GetEnableIRQ (SPI1_TWI1_IRQn));
  delay(1000);
  Wire.requestFrom(0x02,6);

}
Steve
  • 61
  • 1
  • 2
  • 5
  • I have also tried using NVIC_GetPriority and NVIC_SetPriority to make all of the SPIx_TWIx_IRQn interrupts both higher and lower than the priority of all of the TIMERx_IRQn priorities. NVIC_GetPriority is confirming that the priorities were set, but still no joy – Steve Jul 01 '17 at 16:31

1 Answers1

0

By default, interrupts are not disabled in ISRs on Cortex-M, but rather interrupts are pre-empted based on the priorities set in NVIC (hence the "Nested" part of NVIC). This means that you should simply enable the I2C interrupt as you usually do, and then set the priority using NVIC_SetPriority(IRQn, priority).

Note however that priority numbers are ordered in reverse, so a priority of 0 would pre-empt a priority of say 6. In this case you would set the Timer interrupt priorities to say 1 and the I2C interrupt to 0.

Tony K
  • 281
  • 1
  • 7
  • Thanks, I assumed that was the case, and I have tried setting all timer priorities to 2, and all SPIx_TWIx interrupts to 1, and then in a seperate test to 3. I checked that had been set using NVIC_GetEnableIRQ, and they seemed to be reporting their correct values, but my I2C call is still causing my program to hang if I use it in the timer ISR – Steve Jul 03 '17 at 08:55
  • @Steve I see you have included your sketch, however I notice the ISR for the I2C controllers are missing, by default I don't think the Arduino core uses interrupt to handle I2C so when you enable the interrupt it will jump to the default handler, which is an infinite loop. This likely explains the hang. – Tony K Jul 03 '17 at 11:05
  • Also, I notice that you are using a "Ticker" object as your "timer", however keep in mind that they are typically implemented using SysTick timer available on every Cortex-M, and its interrupt priority is separate from the ordinary "timers" available on the NRF52. – Tony K Jul 03 '17 at 11:16
  • Thanks for your comments. I don't really understand the cause for the hang. The I2C call works perfectly outside of the timer ISR, but not within it. Please can you suggest how I can get the I2C call to work within this (or another) timer based ISR? – Steve Jul 03 '17 at 12:29
  • Have you tried simply calling the I2C function, without enabling interrupt for the I2C? As I have mentioned the Arduino I2C code does not use interrupts. – Tony K Jul 03 '17 at 14:22
  • thanks for your suggestions. We moved to using a timer rather than the ticker and have been able to get everything working. If you would like to write up your comment as an answer I'd be happy to accept it. Thanks! – Steve Jul 25 '17 at 19:38