This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

Conflict between Timer Interrupt and BLE stack?

If I use the interrupt handler to set Flag, and read sensors and write data to SD card in the main loop as in the following code then everything works well.

#include <Wire.h>
#include <Adafruit_VCNL4010.h>
#include <SPI.h>
#include <SD.h>
#include <RFduinoBLE.h>


// Proximity sensor
Adafruit_VCNL4010 vcnl;
uint16_t proximity;
uint16_t ambientLight;

char buffer[12];

#define CHIPSELECT 2
uint_fast16_t volatile number_of_ms = 2;     // ms

void timer_config(void)
{
  NRF_TIMER2->TASKS_STOP = 1;  // Stop timer
  NRF_TIMER2->MODE = TIMER_MODE_MODE_Timer;  // taken from Nordic dev zone
  NRF_TIMER2->BITMODE = TIMER_BITMODE_BITMODE_16Bit;
  NRF_TIMER2->PRESCALER = 9;  // 32us resolution
  NRF_TIMER2->TASKS_CLEAR = 1; // Clear timer
  // With 32 us ticks, we need to multiply by 31.25 to get milliseconds
  NRF_TIMER2->CC[0] = number_of_ms * 31;
  NRF_TIMER2->CC[0] += number_of_ms / 4; 
  NRF_TIMER2->INTENSET = TIMER_INTENSET_COMPARE0_Enabled << TIMER_INTENSET_COMPARE0_Pos;  // taken from Nordic dev zone
  NRF_TIMER2->SHORTS = (TIMER_SHORTS_COMPARE0_CLEAR_Enabled << TIMER_SHORTS_COMPARE0_CLEAR_Pos);
  attachInterrupt(TIMER2_IRQn, TIMER2_Interrupt);    // also used in variant.cpp to configure the RTC1 
  NRF_TIMER2->TASKS_START = 1;  // Start TIMER
}

bool transmitFlag = 0;

void setup() {  
  // BLE stack
  RFduinoBLE.deviceName = "andrey";
  RFduinoBLE.begin();

  // start SD card
  pinMode(CHIPSELECT, OUTPUT);
  if (!SD.begin(CHIPSELECT)) {
    return;
  }

  timer_config();

  if (!vcnl.begin()) {
    return;
  }
}

void loop() {
  // put your main code here, to run repeatedly:
  if (transmitFlag) {
    transmitFlag = 0;
    
    proximity = vcnl.readProximity();
    ambientLight = vcnl.readAmbient();

    File myFile = SD.open("datafile.csv",  FILE_WRITE);
    if (myFile) {
      myFile.print(buffer);
      myFile.close();
    }
  }    
}

void TIMER2_Interrupt(void) {
  if (NRF_TIMER2->EVENTS_COMPARE[0] != 0) {
    transmitFlag = 1;
//    proximity = vcnl.readProximity();
//    ambientLight = vcnl.readAmbient();
//    sprintf(buffer, "%5d5d\n", 12, proximity, ambientLight);

    NRF_TIMER2->EVENTS_COMPARE[0] = 0;
  }
}

However, now if I move the reading sensor code to be inside the interrupt handler (as in the commented lines which has sprintf), then there's a conflict with BLE. BLE starts, but as soon as I connect to it there seems to be a deadlock and the whole board goes into freeze.

I need reading sensor (not write to SD card) to be inside the handler, since these samples will be accumulated to a buffer and then the buffer will be write just one time to SD card.

How could I resolve this problem?

Parents
  • You cannot run any time-consuming action inside interrupt handler because BLE is time-critical and stack (Soft Device) needs to run uninterrupted especially when handling connection interval. So if your read operation is longer then few dozens of microseconds (see more about Soft Device timing and interrupt handling here) you should keep processing out of interrupt handler. Usual method is to use scheduler (see it in SDK) or similar method of "set the flag and process it later (as soon as BLE stack gives you more time)".

Reply
  • You cannot run any time-consuming action inside interrupt handler because BLE is time-critical and stack (Soft Device) needs to run uninterrupted especially when handling connection interval. So if your read operation is longer then few dozens of microseconds (see more about Soft Device timing and interrupt handling here) you should keep processing out of interrupt handler. Usual method is to use scheduler (see it in SDK) or similar method of "set the flag and process it later (as soon as BLE stack gives you more time)".

Children
No Data
Related