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

I2c + timer1 + timer2 + softdevice(S210)

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, &regAddr, 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,&regAddr,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!

Related