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

TWI: prevent repeated start between non stop transfer

Hi,

I am debugging an SSD1306 OLED library, and in the datasheet, it does not explicitly mention support for repeated start bits. But using the nrf_drv_ API's with NRF_DRV_TWI_FLAG_TX_NO_STOP flag set, the successive nrf_drv_twi_tx or nrf_drv_twi_xfer function starts sending data with a start condition.

image description

As shown by the logic analyzer, the Green dot is a start ad red dot is a stop. I dont not want the last green dot to the right. Is this possible using the nrf_drv_twi_ API ?

  • I just verified that SSD1306 really requires not to have start bits in between. I tried splitting up the data to be sent into smaller chunk with no lone start bits in between and I get correct display as expected. It would be nice to have another flag in the nrf_drv_twi_ API not to put a start bit, just like not putting a stop bit. Why I cannot send the whole data at one go is possibly another issue - if I give smaller data lengths, they work.

  • I'm not sure I understand what you are asking about. Do you want the stop bit but not the start bit, or was this just for illustration? Are you only doing TX or do you want to do TX with no stop bit and then do RX without repeated start? If you are only doing TX, how is this different from just transmitting multiple bytes in one transfer?

  • Hi Aurabindo, I am getting the same problem with the SSD1306. Splitting up the data to smaller chunks did not work for me. I think its caused by the extra start bit everything a new chunk begins. How did you solve the problem? Thank you!

  • He wants to do the same thing as I'm trying to right now. I'm working with the sensor MPL3115A2 and it does not work with a repeated start either, similar to above. First of all I'm using the TWI Manager and I'm using defines to split my communication. I want to do, for example:

    1. Write <Data1> to CTRL register1
    2. Write <Data2> to CTRL register 2
    3. Write <Data3> to INT_SRC register
    4. ...

    by using defines as follows:

    #define MPL3115A2_READ(p_reg_addr, p_buffer, byte_cnt) \
        NRF_TWI_MNGR_WRITE(MPL3115A2_ADDR, p_reg_addr, 1, NRF_TWI_MNGR_NO_STOP), \
        NRF_TWI_MNGR_READ (MPL3115A2_ADDR, p_buffer, byte_cnt, 0)

    As you see above It is easy to create one define that can handle both different register addresses and data. With this method however you will always get a repeated start between the WRITE and READ, i.e.

    START | ADDR + W | REG ADDR | START | DATA | STOP

    As mentioned the MPL3115A2 among others obviously does not support repeated start, but required communication in the shape of:

    START | ADDR + W | REG ADDR | DATA | STOP

    Thus removing the START generated from the NRF_TWI_MNGR_READ.

    Right now I have solved this as follows:

    #define MPL3115A2_WRITE_REG(p_data)\
        NRF_TWI_MNGR_WRITE(MPL3115A2_ADDR, p_data, 2, 0)
        
    static inline void init_press_measure()
    {
        static uint8_t config_1[2] = {MPL3115A2_CTRL_REG1, MPL3115A2_OVERSAMPLE_RATIO_128};
        
        static nrf_twi_mngr_transfer_t const transfers[] =
        {
            MPL3115A2_WRITE_REG(config_1),
        };
        
        static nrf_twi_mngr_transaction_t NRF_TWI_MNGR_BUFFER_LOC_IND transaction =
        {
            .callback            = NULL,
            .p_user_data         = NULL,
            .p_transfers         = transfers,
            .number_of_transfers = sizeof(transfers) / sizeof(transfers[0])
        };
        
        APP_ERROR_CHECK(nrf_twi_mngr_schedule(&m_nrf_twi_mngr, &transaction));
    }

    In other words, I have to create a temporary array with the length of 2 and assign values and then use that configuration variable.

    If it was possible to add a flag such as "NRF_TWI_MNGR_NO_START" it would have been possible to create a neat macro such as below:

    uint8_t NRF_TWI_MNGR_BUFFER_LOC_IND mpl3115a2_ctrl_reg1 = MPL3115A2_CTRL_REG1;
    uint8_t mpl3115a2_oversample_ratio_128 = MPL3115A2_OVERSAMPLE_RATIO_128;
    
    #define MPL3115A2_WRITE_CTRL_REG1(p_data) \
        MPL3115A2_WRITE_REG(&mpl3115a2_ctrl_reg1, p_data, 2)
        
    #define MPL3115A2_WRITE_REG(p_reg_addr, p_buffer, byte_cnt) \
        NRF_TWI_MNGR_WRITE(MPL3115A2_ADDR, p_reg_addr, 1, NRF_TWI_MNGR_NO_STOP), \
        NRF_TWI_MNGR_WRITE(MPL3115A2_ADDR, p_buffer, byte_cnt, NRF_TWI_MNGR_NO_START)
        
    ...
        static nrf_twi_mngr_transfer_t const transfers[] =
        {
            MPL3115A2_WRITE_CTRL_REG1(&mpl3115a2_oversample_ratio_128),
            ...
        };
    ...

    I also see now that it would be very neat if it was possible to also add support for not using pointers. I don't know if that is a good idea or not resource wise but it would allow you to keep almost all configuration data in defines and give you a very clean interface without the need to declare a lot of extra variables only for the reason to point at them.

    #define MPL3115A2_WRITE_CTRL_REG1(data) \
        MPL3115A2_WRITE_REG(MPL3115A2_CTRL_REG1, data, 2)
        
    #define MPL3115A2_WRITE_REG(reg_addr, data, byte_cnt) \
        NRF_TWI_MNGR_WRITE(MPL3115A2_ADDR, reg_addr, 1, NRF_TWI_MNGR_NO_STOP), \
        NRF_TWI_MNGR_WRITE(MPL3115A2_ADDR, data, byte_cnt, NRF_TWI_MNGR_NO_START)
        
    ...
        static nrf_twi_mngr_transfer_t const transfers[] =
        {
            MPL3115A2_WRITE_CTRL_REG1(MPL3115A2_OVERSAMPLE_RATIO_128),
            ...
        };
    ...
    

    Regards

    Robert

Related