Beware that this post is related to an SDK in maintenance mode
More Info: Consider nRF Connect SDK for new designs
This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

TWI I2C problem ( ssd1306 display )

Hello,

I have a problem through which unfortunately I'm not able to come across alone. I'm using nRF52832 with softdevice and UART central example from SDK14.2 (..\examples\ble_central\ble_app_uart_c\pca10040\s132\arm5_no_packs). Right now I'm trying to communicate my nordic device with LED display which is using ssd1306 libraries. Problem occures at the moment when I'm trying to use nrf_drv_twi_tx() function to transmit datas over TWI. 

Of course I've set all necessary items in sdk_config file as below:

// <e> TWI_ENABLED - nrf_drv_twi - TWI/TWIM peripheral driver
//==========================================================
#ifndef TWI_ENABLED
#define TWI_ENABLED 1
#endif
// <o> TWI_DEFAULT_CONFIG_FREQUENCY  - Frequency
 
// <26738688=> 100k 
// <67108864=> 250k 
// <104857600=> 400k 

#ifndef TWI_DEFAULT_CONFIG_FREQUENCY
#define TWI_DEFAULT_CONFIG_FREQUENCY 26738688
#endif

// <q> TWI_DEFAULT_CONFIG_CLR_BUS_INIT  - Enables bus clearing procedure during init
 

#ifndef TWI_DEFAULT_CONFIG_CLR_BUS_INIT
#define TWI_DEFAULT_CONFIG_CLR_BUS_INIT 0
#endif

// <q> TWI_DEFAULT_CONFIG_HOLD_BUS_UNINIT  - Enables bus holding after uninit
 

#ifndef TWI_DEFAULT_CONFIG_HOLD_BUS_UNINIT
#define TWI_DEFAULT_CONFIG_HOLD_BUS_UNINIT 0
#endif

// <o> TWI_DEFAULT_CONFIG_IRQ_PRIORITY  - Interrupt priority
 

// <i> Priorities 0,2 (nRF51) and 0,1,4,5 (nRF52) are reserved for SoftDevice
// <0=> 0 (highest) 
// <1=> 1 
// <2=> 2 
// <3=> 3 
// <4=> 4 
// <5=> 5 
// <6=> 6 
// <7=> 7 

#ifndef TWI_DEFAULT_CONFIG_IRQ_PRIORITY
#define TWI_DEFAULT_CONFIG_IRQ_PRIORITY 7
#endif

// <e> TWI0_ENABLED - Enable TWI0 instance
//==========================================================
#ifndef TWI0_ENABLED
#define TWI0_ENABLED 1
#endif
// <q> TWI0_USE_EASY_DMA  - Use EasyDMA (if present)
 

#ifndef TWI0_USE_EASY_DMA
#define TWI0_USE_EASY_DMA 1
#endif

// </e>

// <e> TWI1_ENABLED - Enable TWI1 instance
//==========================================================
#ifndef TWI1_ENABLED
#define TWI1_ENABLED 1
#endif
// <q> TWI1_USE_EASY_DMA  - Use EasyDMA (if present)
 

#ifndef TWI1_USE_EASY_DMA
#define TWI1_USE_EASY_DMA 1
#endif

Below I've paste  my twi init code:

#define SSD1306_CONFIG_SCL_PIN  ARDUINO_SCL_PIN     //from pca10040.h  27 SCL signal pin
#define SSD1306_CONFIG_SDA_PIN  ARDUINO_SDA_PIN     //from pca10040.h  26 SDA signal pin

...

void ssd1306init() {
	ssd1306_init_i2c(SSD1306_CONFIG_SCL_PIN, SSD1306_CONFIG_SDA_PIN);
	ssd1306_begin(SSD1306_EXTERNALVCC, SSD1306_I2C_ADDRESS, false);
}

Than in ssd1306_init_i2c() function:

void ssd1306_init_i2c(uint32_t scl, uint32_t sda)
{
    _i2caddr = SSD1306_I2C_ADDRESS;
    use_i2c = true;
    twi_master_init(scl, sda);
}

void twi_master_init(uint32_t scl, uint32_t sda)
{
    ret_code_t ret;
    const nrf_drv_twi_config_t config = {
        .scl                = scl,
        .sda                = sda,
        .frequency          = NRF_TWI_FREQ_100K,
        .interrupt_priority = APP_IRQ_PRIORITY_HIGH,
        .clear_bus_init     = true
    };

    do {
	ret = nrf_drv_twi_init(&m_twi_master, &config, twi_handler, NULL);
        if (NRF_SUCCESS != ret) {
            break;
        }
        nrf_drv_twi_enable(&m_twi_master);
    }
    while (0);
    return;
}

And than in ssd1306_begin() function i call ssd1306_command() function  which looks like this:

void ssd1306_command(uint8_t c)
{
    if (use_i2c) {
        ret_code_t ret;
        uint8_t dta_send[] = {0x00, c};
		while(!m_xfer_done);
		m_xfer_done = false;
        ret = nrf_drv_twi_tx(&m_twi_master, _i2caddr, dta_send, 2, false);
		APP_ERROR_CHECK(ret);
        UNUSED_VARIABLE(ret);
    }
    else {
        _HI_CS();
        _LO_DC();
        _LO_CS();
        _HI_CS();
    }
}

m_xfer_done is hendled in twi_hendler which looks like this:

static volatile bool m_xfer_done = false;

void twi_evt_handler(nrf_drv_twi_evt_t const * p_event, void * p_context)
{
    if (p_event->type == NRF_DRV_TWI_EVT_DATA_NACK) {
				m_xfer_done = false;
    }

    if (p_event->type == NRF_DRV_TWI_EVT_DONE) {
				m_xfer_done = true;
    }

    if (p_event->type == NRF_DRV_TWI_EVT_ADDRESS_NACK) {
				m_xfer_done = false;
    }
}

Summarazing whole problem. All code stucks because NRF_DRV_TWI_EVT_DONE is never done actually. Something cosue that nrf_drv_twi_tx() function doesn't work properly and I can not figure out why. I'll be super grateful if someone could help me in solving this problem. So far I've been trying to use higher priority levels for example because I've read on this formu that it could cause some problems regarding to softdevice, but of course it didn't help.

  • Hi,

    Have you first tried: \nRF5_SDK_14.2.0_17b948a\examples\peripheral\twi_scanner?

    Do you have a logic analyzer plot showing the SCL and SDA lines?

    Do you have other events such as NRF_DRV_TWI_EVT_ADDRESS_NACK or NRF_DRV_TWI_EVT_DATA_NACK instead of NRF_DRV_TWI_EVT_DONE?

     

     

  • Yes I've tried twi_scanner it returns correct i2c address as shown below:

    <info> app: TWI scanner.
    <info> app: TWI device detected at address 0x3C.

    Unfortunately I don't have logic analyzer to monitor the SCL and SDA lines.

    It seems that I'm not receiving NRF_DRV_TWI_EVT_ADDRESS_NACK or NRF_DRV_TWI_EVT_DATA_NACK events either.

    I've just printf error code returned from nrf_drv_twi_tx() function, and it is 0x11, but unfortunately I've no idea what does it mean :( Have you any idea which of the error from this list match with my error number?

     * @retval NRF_SUCCESS                  If the procedure was successful.
     * @retval NRF_ERROR_BUSY               If the driver is not ready for a new transfer.
     * @retval NRF_ERROR_INTERNAL           If an error was detected by hardware.
     * @retval NRF_ERROR_INVALID_ADDR       If the EasyDMA is used and memory adress in not in RAM.
     * @retval NRF_ERROR_DRV_TWI_ERR_ANACK  If NACK received after sending the address in polling mode.
     * @retval NRF_ERROR_DRV_TWI_ERR_DNACK  If NACK received after sending a data byte in polling mode.

  • Error code 11 (=NRF_ERROR_INVALID_ADDR) from nrf_drv_twi_tx() means "If the EasyDMA is used and memory adress in not in RAM." Are you sure all parameters (pointers, values, data and addresses) here is in RAM, and not flash when calling nrf_drv_twi_tx()?

  • I'm afraid I'm not able to give an answer for your question. Could you specified when exactly this arguments will be not in RAM?

  • Typically if for instance any of the parameters are of 'const' type they may be placed in flash, not RAM. Also hard coded values, like the parameter value '2' may be stored in flash here. This will cause problem, so instead use a variable length = 2, and then use length variable as input parameter.

Related