Hi Nordic,
My application does the following:
- Timer 2 takes care of controlling a shift register (CLK and DATA)
- Timer 1 takes care of polling data from sensor via I2C, each 10ms
- We are continuously sending and receiving data from one opened ANT channel
The thing is that everything works good except when I try to read data from I2C at each timer 1 tick. What is more strange is that if I manually reset the microprocessor, sometimes everything works, and some other nothing works.
I am having the feeling that this may have to do with interrupt priority? But I have no idea.. Maybe timer 1 is already being used by I2C driver?
EDIT: timers code:
static void timer1_init()
{
NVIC_EnableIRQ(TIMER1_IRQn);
NVIC_SetPriority(TIMER1_IRQn, NRF_APP_PRIORITY_LOW);
NRF_TIMER1->TASKS_STOP = 1;
NRF_TIMER1->MODE = TIMER_MODE_MODE_Timer;
NRF_TIMER1->PRESCALER = 4; // Fhck / 2^4
const uint32_t PRESCALER_VALUE = 100;
NRF_TIMER1->CC[0] = PRESCALER_VALUE & 0xFFFF; // 10000 - 10ms
NRF_TIMER1->BITMODE = (TIMER_BITMODE_BITMODE_16Bit << TIMER_BITMODE_BITMODE_Pos);
NRF_TIMER1->TASKS_CLEAR = 1;
NRF_TIMER1->INTENSET = (TIMER_INTENSET_COMPARE0_Enabled << TIMER_INTENSET_COMPARE0_Pos);
NRF_TIMER1->EVENTS_COMPARE[0] = 0;
// start timer
NRF_TIMER1->TASKS_START = 1;
}
static void timer2_init()
{
NVIC_EnableIRQ(TIMER2_IRQn);
NVIC_SetPriority(TIMER2_IRQn, NRF_APP_PRIORITY_LOW);
NRF_TIMER2->TASKS_STOP = 1;
NRF_TIMER2->MODE = TIMER_MODE_MODE_Timer;
NRF_TIMER2->PRESCALER = 4; // Fhck / 2^4
const uint32_t PRESCALER_VALUE = 100;
NRF_TIMER2->CC[0] = PRESCALER_VALUE & 0xFFFF; // 10000 - 10ms
NRF_TIMER2->BITMODE = (TIMER_BITMODE_BITMODE_16Bit << TIMER_BITMODE_BITMODE_Pos);
NRF_TIMER2->TASKS_CLEAR = 1;
NRF_TIMER2->INTENSET = (TIMER_INTENSET_COMPARE0_Enabled << TIMER_INTENSET_COMPARE0_Pos);
NRF_TIMER2->EVENTS_COMPARE[0] = 0;
// start timer
NRF_TIMER2->TASKS_START = 1;
}
[...]
void TIMER1_IRQHandler(void)
{
if (NRF_TIMER1->EVENTS_COMPARE[0] != 0)
{
NRF_TIMER1->EVENTS_COMPARE[0] = 0;
NRF_TIMER1->TASKS_CLEAR = 1;
mpu_handle_timer_interrupt(); // here is where I send things over I2C
}
}
void TIMER2_IRQHandler(void)
{
if (NRF_TIMER2->EVENTS_COMPARE[0] != 0)
{
NRF_TIMER2->EVENTS_COMPARE[0] = 0;
NRF_TIMER2->TASKS_CLEAR = 1;
leds_handle_timer_interrupt();
}
}
EDIT2: mpu function:
void mpu_handle_timer_interrupt()
{
static bool var = false; // detect change in breaking level. When theres a positive edge, var = true and stays like that. When theres a negative edge, var = false and stays until positive edge
static uint16_t mpu_counter = 0;
if (mpu_counter > 50)
{
mpu_counter = 0;
//az = MPU6050_getAccelerationZ(&mpu);
MPU6050_getMotion6(&mpu, &ax, &ay, &az, &gx, &gy, &gz);
zAcc = az;
zAccAvg = smooth(zAcc);
if (zAccAvg > lowerB)
{
nrf_gpio_pin_set(break_pin);
lowerB = minVal + hist;
var = true;
}
else
{
if (var) // if out of threshold zone, turn off breaking pin. var is for edge detection
{
var = false;
nrf_gpio_pin_clear(break_pin);
lowerB = minVal;
}
}
}
else
{
mpu_counter++;
}
}
EDIT3: i2c driver .c
#include "app_util_platform.h"
#include "i2cdev.h"
/**
* @brief TWI events handler.
*/
static void twi_handler(nrf_drv_twi_evt_t const * p_event, void * p_context)
{
switch(p_event->type)
{
case NRF_DRV_TWI_RX_DONE:
twi_rx_done = 0x01;
break;
case NRF_DRV_TWI_TX_DONE:
twi_tx_done = 0x01;
break;
default:
break;
}
}
void twi_init (void)
{
ret_code_t err_code;
const nrf_drv_twi_config_t twi_mma = {
.scl = SCL_PIN,
.sda = SDA_PIN,
.frequency = NRF_TWI_FREQ_100K,
.interrupt_priority = APP_IRQ_PRIORITY_HIGH
};
err_code = nrf_drv_twi_init(&m_twi, &twi_mma, twi_handler, NULL);
APP_ERROR_CHECK(err_code);
nrf_drv_twi_enable(&m_twi);
}
static bool wrapper_nrf_drv_twi_tx(nrf_drv_twi_t const * const p_instance,
uint8_t address,
uint8_t const * p_data,
uint32_t length,
bool xfer_pending)
{
uint32_t err_code;
err_code = nrf_drv_twi_tx(p_instance, address, p_data, length, xfer_pending);
APP_ERROR_CHECK(err_code);
while(twi_tx_done == 0x00); // maybe make timeout here?
twi_tx_done = 0x00;
return true; // how or when return false?
}
static bool wrapper_nrf_drv_twi_rx(nrf_drv_twi_t const * const p_instance,
uint8_t address,
uint8_t * p_data,
uint32_t length,
bool xfer_pending)
{
uint32_t err_code;
err_code = nrf_drv_twi_rx(p_instance, address, p_data, length, xfer_pending);
APP_ERROR_CHECK(err_code);
while(twi_rx_done == 0x00); // maybe make timeout here?
twi_rx_done = 0x00; // how or when return false?
return true;
}
void i2c_read_bytes(uint8_t devAddr, uint8_t regAddr, uint8_t length, uint8_t *data)
{
wrapper_nrf_drv_twi_tx(&m_twi, devAddr, ®Addr, 1, true);
wrapper_nrf_drv_twi_rx(&m_twi, devAddr, data, length, false);
}
void i2c_write_byte(uint8_t devAddr, uint8_t regAddr, uint8_t data)
{
uint8_t w2_data[2];
w2_data[0] = regAddr;
w2_data[1] = data;
wrapper_nrf_drv_twi_tx(&m_twi, devAddr, w2_data, 2, false);
}
void i2c_write_bytes(uint8_t devAddr, uint8_t regAddr, uint8_t length, uint8_t* data)
{
wrapper_nrf_drv_twi_tx(&m_twi, devAddr, data, length, false);
}
void i2c_read_byte(uint8_t devAddr, uint8_t regAddr, uint8_t *data)
{
i2c_read_bytes(devAddr, regAddr, 1, data);
}
void i2c_read_bit(uint8_t devAddr, uint8_t regAddr, uint8_t bitNum, uint8_t *data)
{
uint8_t b;
i2c_read_byte(devAddr, regAddr, &b);
*data = b & (1 << bitNum); // returns in data a 1 or a 0, corresponding to that bit.
}
void i2c_read_bits(uint8_t devAddr, uint8_t regAddr, uint8_t bitStart, uint8_t length, uint8_t *data) {
// 01101001 read byte
// 76543210 bit numbers
// xxx args: bitStart=4, length=3
// 010 masked
// -> 010 shifted
uint8_t b;
i2c_read_byte(devAddr, regAddr, &b);
uint8_t mask = ((1 << length) - 1) << (bitStart - length + 1);
b &= mask;
b >>= (bitStart - length + 1);
*data = b;
}
void i2c_write_bit(uint8_t devAddr, uint8_t regAddr, uint8_t bitNum, uint8_t data)
{
uint8_t b;
i2c_read_byte(devAddr, regAddr, &b);
b = (data != 0) ? (b | (1 << bitNum)) : (b & ~(1 << bitNum));
i2c_write_byte(devAddr, regAddr, b);
}
void i2c_write_bits(uint8_t devAddr, uint8_t regAddr, uint8_t bitStart, uint8_t length, uint8_t data) {
// 010 value to write
// 76543210 bit numbers
// xxx args: bitStart=4, length=3
// 00011100 mask byte
// 10101111 original value (sample)
// 10100011 original & ~mask
// 10101011 masked | value
uint8_t b;
i2c_read_byte(devAddr, regAddr, &b);
uint8_t mask = ((1 << length) - 1) << (bitStart - length + 1);
data <<= (bitStart - length + 1); // shift data into correct position
data &= mask; // zero all non-important bits in data
b &= ~(mask); // zero all important bits in existing byte
b |= data; // combine data with existing byte
i2c_write_byte(devAddr, regAddr, b);
}
void i2c_write_words(uint8_t devAddr, uint8_t regAddr, uint8_t length, uint16_t *data)
{
wrapper_nrf_drv_twi_tx(&m_twi,devAddr,®Addr,1,true);
for (int i=0;i<length;i++)
{
uint8_t d[2];
d[0]=data[i]>>8;
d[1]=data[i]&0xff;
bool pending = i < length - 1;
wrapper_nrf_drv_twi_tx(&m_twi, devAddr, d, 2, pending);
}
}
void i2c_write_word(uint8_t devAddr, uint8_t regAddr, uint16_t data)
{
i2c_write_words(devAddr, regAddr, 1, &data);
}
Thanks a lot!