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

How can I reuse this library into TWI library in nrF52?

Hello all,

I am trying to make use of some Adafruit libraries for some sensors in my nrF52pca10040, the libraries are these twoAdafruit_BME280.cpp, Adafruit_BME280.h and Adafruit_TSL2591.h,Adafruit_TSL2591.cpp

They both make use of either SPI or I2C interfaces, I am interested on I2C, so I was trying to port both to the nrF52, I have started with the BME280 one. Using SEGGER I am compiling them but I am getting an error when reaching the method Wire.begin(); on Adafruit_BME280::begin(uint8_t a), which is expected since this function is from Arduino.

I have looked into the example twi_sensor and I see that there the twi_init is configured as

const nrf_drv_twi_config_t twi_lm75b_config = {
   .scl                = ARDUINO_SCL_PIN,
   .sda                = ARDUINO_SDA_PIN,
   .frequency          = NRF_TWI_FREQ_100K,
   .interrupt_priority = APP_IRQ_PRIORITY_HIGH,
   .clear_bus_init     = false
};

Can I use the same configuration for my case? What should I change to be able to make use of that library?

On the other hand, those libs work a lot with the definitions HIGH,LOW,INPUT or OUTPUT, where can I find those definitons for the nrf52 board? As well as functions as configuring the PIN(pinmode(pin,OUPUT)) and writing onto it (digitalWrite(pin,HIGH)) ?

Thank you very much in advance,

Kind regards

Edit: following the advice of Jorgen, I have created my own version of the begin, read and write, however, even though there is no compilation errors, debuging the lib it gets stack when reaching the condition if (read8(BME280_REGISTER_CHIPID) != 0x60) in the begin() method.

bool Adafruit_BME280::begin(uint8_t a) {
  _i2caddr = a;

  if (_cs == -1) {
    // i2c
    //Wire.begin();

    ret_code_t err_code;

    const nrf_drv_twi_config_t twi_BME280_config = {
       .scl                = ARDUINO_SCL_PIN,
       .sda                = ARDUINO_SDA_PIN,
       .frequency          = NRF_TWI_FREQ_100K,
       .interrupt_priority = APP_IRQ_PRIORITY_HIGH,
       .clear_bus_init     = false
    };

    err_code = nrf_drv_twi_init(&m_twi, &twi_BME280_config, twi_handler, NULL);
    APP_ERROR_CHECK(err_code);

    nrf_drv_twi_enable(&m_twi);

  } else {
//    digitalWrite(_cs, HIGH);
//    pinMode(_cs, OUTPUT);
//
//    if (_sck == -1) {
//      // hardware SPI
//      SPI.begin();
//    } else {
//      // software SPI
//      pinMode(_sck, OUTPUT);
//      pinMode(_mosi, OUTPUT);
//      pinMode(_miso, INPUT);
//    }
  }

  if (read8(BME280_REGISTER_CHIPID) != 0x60)
    return false;

  readCoefficients();

  //Set before CONTROL_meas (DS 5.4.3)
  write8(BME280_REGISTER_CONTROLHUMID, 0x05); //16x oversampling 

  write8(BME280_REGISTER_CONTROL, 0xB7); // 16x ovesampling, normal mode
  return true;
}

void Adafruit_BME280::write8(byte reg, byte value)
{
  if (_cs == -1) {

    ret_code_t err_code;
    err_code = nrf_drv_twi_tx(&m_twi, _i2caddr, (const byte*)reg, sizeof(reg), false);
    APP_ERROR_CHECK(err_code);

    err_code = nrf_drv_twi_tx(&m_twi, _i2caddr, (byte*)value, sizeof(value), false);
    APP_ERROR_CHECK(err_code);


//    Wire.beginTransmission((uint8_t)_i2caddr);
//    Wire.write((uint8_t)reg);
//    Wire.write((uint8_t)value);
//    Wire.endTransmission();
}}
uint8_t Adafruit_BME280::read8(byte reg)
{
  uint8_t value = 0;
  uint8_t valueAux = 0;

  if (_cs == -1) {
  
    ret_code_t err_code = nrf_drv_twi_rx(&m_twi, _i2caddr, &valueAux, sizeof(byte));
    APP_ERROR_CHECK(err_code);
    if (m_rxfer_done) {
      value = valueAux;//getting the value of the pointer
      m_rxfer_done = false;
    }


//    Wire.beginTransmission((uint8_t)_i2caddr);
//    Wire.write((uint8_t)reg);
//    Wire.endTransmission();
//    Wire.requestFrom((uint8_t)_i2caddr, (byte)1);
//    value = Wire.read();

  } 
  return value;
}

void Adafruit_BME280::twi_handler(nrf_drv_twi_evt_t const *p_event, void *p_context) {
  switch (p_event->type) {
  case NRF_DRV_TWI_EVT_DONE:
    if (p_event->xfer_desc.type == NRF_DRV_TWI_XFER_RX) {
      m_rxfer_done = true;
    } else if (p_event->xfer_desc.type == NRF_DRV_TWI_XFER_TX) {
      m_txfer_done = true;
    }

    break;
  default:
    break;
  }
}

EDIT2image description Debug

  • What is the purpose of the 3rd last line of your above code? You are also waiting for m_txfer_done, while in the if-check you have m_rxfer_done.

  • sorry, you're right I had changed that in the code but not in the post, now it goes through the condition if (read8(BME280_REGISTER_CHIPID) != 0x60) but it stalls in the read16 function, I need to figure out how to translate these lines

    //    Wire.requestFrom((uint8_t)_i2caddr, (byte)2);
    //    value = (Wire.read() << 8) | Wire.read();
    

    for reading 16bits, so far I have done this but still not working as expected

    err_code = nrf_drv_twi_rx(&m_twi, _i2caddr, &valueAux, 2*sizeof(byte));//2*sizeof(byte) = 2bytes = 16bits
    APP_ERROR_CHECK(err_code);
    while (m_rxfer_done == false);
    if (m_rxfer_done) {
      value = valueAux << 8;
      value = value | valueAux;
      m_rxfer_done = false;
    }
    
  • You will need a transmitt here as well. I would suggest something like this (not tested):

    uint8_t Adafruit_BME280::read16(byte reg)
    {
      uint16_t value = 0;
      uint8_t valueAux[2];
      ret_code_t err_code;
    
      if (_cs == -1) {
    
        err_code = nrf_drv_twi_tx(&m_twi, _i2caddr, (const byte*)reg, sizeof(reg), false);
        APP_ERROR_CHECK(err_code);
        while (m_txfer_done == false);
    
        err_code = nrf_drv_twi_rx(&m_twi, _i2caddr, valueAux, 2*sizeof(byte));
        APP_ERROR_CHECK(err_code);
        while (m_rxfer_done == false);
        if (m_rxfer_done) {
          value = valueAux[0] << 8;
    	  value = value | valueAux[1];
          m_rxfer_done = false;
        }
      }
      return value;
    }
    

    You don't really need the if (m_rxfer_done) part though, as the above while loop will ensure the RX operation in finished.

  • Thanks Jorgen, I had the transmit as well but I didn't show before. Thanks for the tip I will incorporate as well, could you tell me why is better using an array than two variables, performance? In case of reading 24 bits, I can reuse the above function like this

    uint32_t Adafruit_BME280::read24(byte reg)
    {
      uint32_t value = 0;
      uint8_t valueAux[3] ;
      ret_code_t err_code;
    
      if (_cs == -1) {
    
        byte xfer[1] = {reg};
        err_code = nrf_drv_twi_tx(&m_twi, _i2caddr, (const byte*)xfer, sizeof(xfer), false);
        APP_ERROR_CHECK(err_code);
        while (m_txfer_done == false);
    
        err_code = nrf_drv_twi_rx(&m_twi, _i2caddr, valueAux, 3*sizeof(byte));//2*sizeof(byte) = 2bytes = 16bits
        APP_ERROR_CHECK(err_code);
        while (m_txfer_done == false);
          value = valueAux[0] << 8;
          value = valueAux[1] << 8;
          value = value | valueAux[0] | valueAux[1];
          m_rxfer_done = false;
    
    //    Wire.beginTransmission((uint8_t)_i2caddr);
    //    Wire.write((uint8_t)reg);
    //    Wire.endTransmission();
    //    Wire.requestFrom((uint8_t)_i2caddr, (byte)3);
    //    
    //    value = Wire.read();
    //    value <<= 8;
    //    value |= Wire.read();
    //    value <<= 8;
    //    value |= Wire.read();
          return value;
        }
    
  • The TWI driver will read one byte at a time and place it into the buffer. If you do not provide an array to the buffer parameter, the driver will try to access an index outside of the provided buffer on the second read. If you want to use single variable you need to call the rx function two times with a size of 1 byte to receive 16 bits.

Related