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

I2C slave implementation

Dear community,

I need to operate a BM833A as I2C slave and to do so, I performed the following steps:

I modfied my sdk_config.h and set TWIS_ENABLED and NRFX_TWIS_ENABLED identically following hint at:

devzone.nordicsemi.com/.../merge-twis-i2c-slave-example-in-ble_template-project

(Either completely remove the legacy (non NRFX_...) for TWI(S) or set them equal to the NRFX_TWIS_... definitions.)

// <e> NRFX_TWIS_ENABLED - nrfx_twis - TWIS peripheral driver
//==========================================================
#ifndef NRFX_TWIS_ENABLED
#define NRFX_TWIS_ENABLED 1
//RH: changed from 0 to 1
#endif
// <q> NRFX_TWIS0_ENABLED  - Enable TWIS0 instance
 

#ifndef NRFX_TWIS0_ENABLED
#define NRFX_TWIS0_ENABLED 1
//RH: changed from 0 to 1
#endif

// <q> NRFX_TWIS1_ENABLED  - Enable TWIS1 instance
 

#ifndef NRFX_TWIS1_ENABLED
#define NRFX_TWIS1_ENABLED 0
#endif

// <q> NRFX_TWIS_ASSUME_INIT_AFTER_RESET_ONLY  - Assume that any instance would be initialized only once
 

// <i> Optimization flag. Registers used by TWIS are shared by other peripherals. Normally, during initialization driver tries to clear all registers to known state before doing the initialization itself. This gives initialization safe procedure, no matter when it would be called. If you activate TWIS only once and do never uninitialize it - set this flag to 1 what gives more optimal code.

#ifndef NRFX_TWIS_ASSUME_INIT_AFTER_RESET_ONLY
#define NRFX_TWIS_ASSUME_INIT_AFTER_RESET_ONLY 0
#endif

// <q> NRFX_TWIS_NO_SYNC_MODE  - Remove support for synchronous mode
 

// <i> Synchronous mode would be used in specific situations. And it uses some additional code and data memory to safely process state machine by polling it in status functions. If this functionality is not required it may be disabled to free some resources.

#ifndef NRFX_TWIS_NO_SYNC_MODE
#define NRFX_TWIS_NO_SYNC_MODE 0
#endif

// <o> NRFX_TWIS_DEFAULT_CONFIG_ADDR0 - Address0
#ifndef NRFX_TWIS_DEFAULT_CONFIG_ADDR0
#define NRFX_TWIS_DEFAULT_CONFIG_ADDR0 0x01
//RH: changed from 0 to 0x01
#endif

// <o> NRFX_TWIS_DEFAULT_CONFIG_ADDR1 - Address1
#ifndef NRFX_TWIS_DEFAULT_CONFIG_ADDR1
#define NRFX_TWIS_DEFAULT_CONFIG_ADDR1 0
#endif

// <o> NRFX_TWIS_DEFAULT_CONFIG_SCL_PULL  - SCL pin pull configuration
 
// <0=> Disabled
// <1=> Pull down
// <3=> Pull up

#ifndef NRFX_TWIS_DEFAULT_CONFIG_SCL_PULL
#define NRFX_TWIS_DEFAULT_CONFIG_SCL_PULL 3
//RH: enable pullup, see i2cslave from SBRLE
#endif

// <o> NRFX_TWIS_DEFAULT_CONFIG_SDA_PULL  - SDA pin pull configuration
 
// <0=> Disabled
// <1=> Pull down
// <3=> Pull up

#ifndef NRFX_TWIS_DEFAULT_CONFIG_SDA_PULL
#define NRFX_TWIS_DEFAULT_CONFIG_SDA_PULL 3
//RH: enable pullup, see i2cslave from SBRLE
#endif

// <o> NRFX_TWIS_DEFAULT_CONFIG_IRQ_PRIORITY  - Interrupt priority
 
// <0=> 0 (highest)
// <1=> 1
// <2=> 2
// <3=> 3
// <4=> 4
// <5=> 5
// <6=> 6
// <7=> 7

#ifndef NRFX_TWIS_DEFAULT_CONFIG_IRQ_PRIORITY
#define NRFX_TWIS_DEFAULT_CONFIG_IRQ_PRIORITY 6
#endif

I added to the segger-embedded-studio (SES) project file:

<folder Name="nRF_Drivers">
...
      <file file_name="../../../../../../modules/nrfx/drivers/src/nrfx_twis.c" />

<folder>

Then I added code to main.c following:

https://infocenter.nordicsemi.com/index.jsp?topic=%2Fcom.nordic.infocenter.sdk5.v12.0.0%2Fhardware_driver_twis_slave.html

I created a timer that executes continuously every 0.5s (function of that could be veryfied by LED blink).

Then I added I2C call to nrf_drv_twis_tx_prepare, hoping to get a transmission.

main.c modifications:

#include "nrf_drv_twis.h"

APP_TIMER_DEF(m_bsp_tmr);

//twi
/* TWI instance ID. */
#if TWIS0_ENABLED
#define TWIS_INSTANCE_ID     0
#endif

/* TWI instance. */
static const nrf_drv_twis_t m_twi = NRF_DRV_TWIS_INSTANCE(TWIS_INSTANCE_ID);

/**
 * @brief TWI initialization.
 */
void twi_init (void)
{
    ret_code_t err_code;

    const nrf_drv_twis_config_t twi_config = {
       .scl                = 27,
       .sda                = 26,
       .interrupt_priority = APP_IRQ_PRIORITY_HIGH
    };

    //err_code = nrf_drv_twis_init(&m_twi, &twi_config, twis_event_handler);
    err_code = nrf_drv_twis_init(&m_twi, &twi_config, NULL);
    APP_ERROR_CHECK(err_code);

    nrf_drv_twis_enable(&m_twi);
}

/**@brief Handle events from button timer.
 *
 * @param[in]   p_context   parameter registered in timer start function.
 */
static void m_timer_handler(void * p_context)
{
     uint16_t count=0;
     char txbuffer[32];
     strcpy(txbuffer, "ready!\n");
     uint16_t len=strlen(txbuffer);
        
     NRF_LOG_INFO("Sending Data: %d.", len);
     ret_code_t err_code = nrf_drv_twis_tx_prepare(&m_twi, txbuffer, len);
     APP_ERROR_CHECK(err_code);
     while(nrf_drv_twis_is_pending_tx(&m_twi) && count<350)
     {
         nrf_delay_ms(1);
         count++;
     }
     NRF_LOG_INFO("Loop hops: %d.", count);
}

int main(void)
{
    // Initialize.
    log_init();
    twi_init();
  

    uint32_t timeout_ticks = APP_TIMER_TICKS(500);
    ret_code_t err_code = app_timer_create(&m_bsp_tmr, APP_TIMER_MODE_REPEATED, m_timer_handler);
    APP_ERROR_CHECK(err_code);
    app_timer_start(m_bsp_tmr, timeout_ticks, NULL);

    // Start execution.
    printf("BLE UART central example started.\r\n");
    NRF_LOG_INFO("BLE UART central example started.");

    // Enter main loop.
    for (;;)
    {
        idle_state_handle();
    }

}

In SES-debugger, I get:

<info> app_timer: RTC: initialized.
<info> app: BLE UART central example started.
<info> app: Sending Data: 7.
<info> app: Loop hops: 0.
<info> app: Sending Data: 7.
<info> app: Loop hops: 0.

(...)

But measuring shows:

1) SCL is provided with 115k clock from master

2) SDA-PIN shows no activity

Any suggestions on corrections?

Best regards,

Richard

Parents
  • Hello Richard,

    I need to operate a BM833A as I2C slave and to do so, I performed the following steps:

    I modfied my sdk_config.h and set TWIS_ENABLED and NRFX_TWIS_ENABLED identically following hint at:

    Any suggestions on corrections?

    If I have understood your intentions correctly, you intend for the nRF to be the TWI master, and the BM833A to be the TWI slave - is this correct?
    If so, you will need to setup the nRF to use the TWIM driver, for it to be in the master configuration. Currently, it seems that you have configured your nRF to be a TWI slave, which will need a TWI Master to be present on the bus, for it to work.
    If you wish to make the nRF the bus master, you could start out by taking a look at the TWI Scanner example - if the scanner example functions as expected, it will confirm that the wiring and hardware connections between the master and slave device is correct. Then, you can move over to implementing the TWIM driver's behavior.

    (Either completely remove the legacy (non NRFX_...) for TWI(S) or set them equal to the NRFX_TWIS_... definitions.)

    You should always completely remove the legacy defines from the sdk_config when you intend to use the nrfx driver, because the nrfx enable will be overwritten by the apply_old_config file if the legacy definitions are left defined (their defined value does not matter).

    1) SCL is provided with 115k clock from master

    Where is this clock being supplied from? The clock should be supplied by the bus master, but it seems to me that your bus currently does not have a master, so I am not sure what is happening here. Where else in your application is the definition of the SCL pin used?

    For future reference, please use the Insert -> Code option when sharing code here on DevZone.

    Best regards,
    Karl

  • Dear Karl,

    I tried removing legacy defines

    removed all sdk config from:

    // <e> TWIS_ENABLED - nrf_drv_twis - TWIS peripheral driver - legacy layer

    (...until first...)

    // </e>

    This results in a broken config.

    Compiling, I get (in nrfx_twis.h):

    ‘NRF_TWISTWIS_INSTANCE_ID’ undeclared here (not in a function); did you mean ‘NRF_DRV_TWIS_INSTANCE’?

    in definition of macro ‘NRFX_CONCAT_2_’

    in expansion of macro ‘NRFX_CONCAT_2’

    in expansion of macro ‘NRFX_TWIS_INSTANCE’

    in expansion of macro ‘NRF_DRV_TWIS_INSTANCE’

    (...plus second, similar error)

    The referenced Code in nrfx_twis.h:

    /** @brief Macro for creating a TWIS driver instance. */
    #define NRFX_TWIS_INSTANCE(id)                               \
    {                                                            \
        .p_reg        = NRFX_CONCAT_2(NRF_TWIS, id),             \
        .drv_inst_idx = NRFX_CONCAT_3(NRFX_TWIS, id, _INST_IDX), \
    }

    The macro cannot be removed, as it is required in the main.c code:

    static const nrf_drv_twis_t m_twi = NRF_DRV_TWIS_INSTANCE(TWIS_INSTANCE_ID);

    So how could I succeed in removing?

    Best regards,

    Richard

Reply
  • Dear Karl,

    I tried removing legacy defines

    removed all sdk config from:

    // <e> TWIS_ENABLED - nrf_drv_twis - TWIS peripheral driver - legacy layer

    (...until first...)

    // </e>

    This results in a broken config.

    Compiling, I get (in nrfx_twis.h):

    ‘NRF_TWISTWIS_INSTANCE_ID’ undeclared here (not in a function); did you mean ‘NRF_DRV_TWIS_INSTANCE’?

    in definition of macro ‘NRFX_CONCAT_2_’

    in expansion of macro ‘NRFX_CONCAT_2’

    in expansion of macro ‘NRFX_TWIS_INSTANCE’

    in expansion of macro ‘NRF_DRV_TWIS_INSTANCE’

    (...plus second, similar error)

    The referenced Code in nrfx_twis.h:

    /** @brief Macro for creating a TWIS driver instance. */
    #define NRFX_TWIS_INSTANCE(id)                               \
    {                                                            \
        .p_reg        = NRFX_CONCAT_2(NRF_TWIS, id),             \
        .drv_inst_idx = NRFX_CONCAT_3(NRFX_TWIS, id, _INST_IDX), \
    }

    The macro cannot be removed, as it is required in the main.c code:

    static const nrf_drv_twis_t m_twi = NRF_DRV_TWIS_INSTANCE(TWIS_INSTANCE_ID);

    So how could I succeed in removing?

    Best regards,

    Richard

Children
  • Hello Richard,

    RichardHdrd said:

    Sorry, that is not the case.

    The BM833A contains a nordic 52811 chip. This platform shall act as I2C (TWI) slave.Programming this is the issue of my inquiry here.

    Thank you for clarifying this. 

    RichardHdrd said:
    What you see is the code that I used to drive the BM833A (52811 nordic) hardware to send data as I2C slave to that other hardware platform.

    It would also be good if you could share your entire main.c code, either through the Insert -> Code option, or by uploading the main.c file as a whole. In your current code, I see no mention of your twis_event_handler, except for in the initialization function - so I only know it exists, but not its contents.
    It might also be helpful for you to take a look at the eeprom_simulator.c file of the TWI master with TWIS slave example from the SDK. This file demonstrates how to implement a TWI slave on the nRF side.

    RichardHdrd said:
    Currently, there are no other slaves connected to the I2C-bus, but the plan is (once the single slave works) to connect five more BM833A slaves to the I2C-bus.

    This should be no problem, since the bus master will address each slave separately.

    Could you confirm for me which SDK you are using?
    I see now that one of the API reference links you provided is for SDK v12, which does not contain the nrfx drivers.

    RichardHdrd said:

    The macro cannot be removed, as it is required in the main.c code:

    static const nrf_drv_twis_t m_twi = NRF_DRV_TWIS_INSTANCE(TWIS_INSTANCE_ID);

    So how could I succeed in removing?

    Yes, you must still declare an TWIS instance, but you may do so using the NRFX version of the macro: NRFX_TWIS_INSTANCE.
    Please replace this macro call with the nrfx version, and see if it resolves the broken build issue.

    Best regards,
    Karl

Related