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

I2C communication between nrf52 and stm32

Hi all,

I am currently building I2C communication between nrf52832 and a stm32 chip, stm32 as the master and nrf52 as the slave.

The situation is the stm32 couldn't get the data from the nrf52 but I can actually the data flowing through the SDA channel via the oscilloscope.

When I change the slave to another sensor with I2C, the stm32 can receive the data from the sensor so I guess my stm32 code is good and the problem might be in the code of the nrf52.

But another weird thing is, when I use the arduino as the master and nrf52 as the slave, the arduino can receive the data from the nrf52.

I really have no idea what is wrong. Any suggestion would help.

Thanks in advance,

Duncan

Here is code for the nrf52 and the image from the oscilloscope.

#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include "nordic_common.h"
#include "nrf_sdh.h"
#include "nrf_sdh_ble.h"
#include "app_timer.h"
#include "bsp_btn_ble.h"
#include "ble.h"
#include "ble_hci.h"
#include "ble_advdata.h"
#include "ble_advertising.h"
#include "ble_conn_params.h"
#include "ble_db_discovery.h"
#include "ble_lbs_c.h"
#include "ble_conn_state.h"
#include "nrf_ble_gatt.h"
#include "nrf_pwr_mgmt.h"
#include <ble_types.h>
#include "nrf_log.h"
#include "nrf_log_ctrl.h"
#include "nrf_log_default_backends.h"
#include "nrfx_twis.h"  //header file for twis
#include "nrf_drv_twis.h"

#define APP_BLE_CONN_CFG_TAG      1                                     /**< A tag that refers to the BLE stack configuration we set with @ref sd_ble_cfg_set. Default tag is @ref APP_BLE_CONN_CFG_TAG. */
#define APP_BLE_OBSERVER_PRIO     3                                     /**< Application's BLE observer priority. You shouldn't need to modify this value. */

#define SCAN_INTERVAL             0x0100                                /**< Determines scan interval in units of 0.625 millisecond. */
#define SCAN_WINDOW               0x0050                                /**< Determines scan window in units of 0.625 millisecond. */
#define SCAN_DURATION             0x0000                                /**< Duration of the scanning in units of 10 milliseconds. If set to 0x0000, scanning will continue until it is explicitly disabled. */

#define target_uuid               0xAA10    // the 16 bit uuid of the target device, or the 12 and 13 octetcs of the 128 bit uuid(be careful to the order)
#define NRF_LOG_ENABLED           1
#define NRF_LOG_DEFAULT_LEVEL     3

/* TWI instance ID. */
#define TWIS_INST_ID         0

#define MASTER_ADDR0         0x29
#define MASTER_ADDR1         0
#define NRFX_TWIS_DEFAULT_CONFIG_SCL_PULL  0
#define NRFX_TWIS_DEFAULT_CONFIG_SDA_PULL  0


const uint8_t peer_address[6]  = {0x00,0x78,0xB9,0X48,0XB4,0XB0};

static int8_t m_rssi;                      //the varible used to store the signal strenth from the advertising report of the target device


//static char const m_target_periph_name[] = "Beacon";       /**< Name of the device we try to connect to.*/

static uint8_t m_scan_buffer_data[BLE_GAP_SCAN_BUFFER_MIN]; /**< buffer where advertising reports will be stored by the SoftDevice. */

/**@brief Pointer to the buffer where advertising reports will be stored by the SoftDevice. */
static ble_data_t m_scan_buffer =
{
    m_scan_buffer_data,
    BLE_GAP_SCAN_BUFFER_MIN
};

/**@brief Scan parameters requested for scanning and connection. */
static ble_gap_scan_params_t const m_scan_params =
{
    .active   = 0,
    .interval = SCAN_INTERVAL,
    .window   = SCAN_WINDOW,

    .timeout           = SCAN_DURATION,
    .scan_phys         = BLE_GAP_PHY_1MBPS,
    .filter_policy     = BLE_GAP_SCAN_FP_ACCEPT_ALL,

};



/* TWIS instance. */
static const nrfx_twis_t m_twis = NRFX_TWIS_INSTANCE(TWIS_INST_ID);

/* Buffer for samples would be sent. */
const int8_t *m_data_buffer=&m_rssi;
int8_t received_value;




/**@brief Function to handle asserts in the SoftDevice.
 *
 * @details This function will be called in case of an assert in the SoftDevice.
 *
 * @warning This handler is an example only and does not fit a final product. You need to analyze
 *          how your product is supposed to react in case of Assert.
 * @warning On assert from the SoftDevice, the system can only recover on reset.
 *
 * @param[in] line_num     Line number of the failing ASSERT call.
 * @param[in] p_file_name  File name of the failing ASSERT call.
 */
void assert_nrf_callback(uint16_t line_num, const uint8_t * p_file_name)
{
    app_error_handler(0xDEADBEEF, line_num, p_file_name);
}


/**
 * @brief TWIS events handler.
 */
void twis_handler(nrfx_twis_evt_t const * p_event)
{
    switch (p_event->type)
    {
    //if get a reading request from the master
    case NRFX_TWIS_EVT_READ_REQ:
       if(p_event->data.buf_req) 
       {
            nrfx_twis_tx_prepare(&m_twis,m_data_buffer, sizeof(m_data_buffer));
            NRF_LOG_INFO("TWIS get data transfer request.\n");    
       }
       break;
   //once the reading is succfully done, clear the data buffer
   case NRFX_TWIS_EVT_READ_DONE:
        //memset(m_data_buffer, 0x00, sizeof(m_data_buffer));
        NRF_LOG_INFO("TWIS data transfer done.\n");
       break;
	  case NRFX_TWIS_EVT_WRITE_REQ:
			
       if(p_event->data.buf_req) {
           nrfx_twis_rx_prepare(&m_twis, &received_value, sizeof(&received_value));
       }		   
       break;
   case NRFX_TWIS_EVT_WRITE_DONE:
      break;	 
    default:
       break;
    }
}

/**
 * @brief twis initialization.
 */
void twis_init (void)
{
    ret_code_t err_code;

    const nrfx_twis_config_t m_twis_config = {
       .addr               = {MASTER_ADDR0, MASTER_ADDR1},
       .scl                = 27,
       .sda                = 26,
       .interrupt_priority = APP_IRQ_PRIORITY_HIGH,
    };

    err_code = nrfx_twis_init(&m_twis, &m_twis_config, twis_handler);
    APP_ERROR_CHECK(err_code);

    nrfx_twis_enable(&m_twis);
    NRF_LOG_INFO("TWIS initiation success.\n");
}


/**@brief Function to start scanning. */
static void scan_start(void)
{
    ret_code_t ret;

    (void) sd_ble_gap_scan_stop();

    //NRF_LOG_INFO("Start scanning for device name %s.", (uint32_t)m_target_periph_name);
    ret = sd_ble_gap_scan_start(&m_scan_params, &m_scan_buffer);
    APP_ERROR_CHECK(ret);
}

/**@brief Function for handling the advertising report BLE event.
 *
 * @param[in] p_adv_report  Advertising report from the SoftDevice.
 */
static void on_adv_report(ble_gap_evt_adv_report_t const * p_adv_report)
{

    uint8_t j=0;   //variable for printing out the peer address from the advertising report of our target device 
  uint8_t p_peer_address[6];
  ret_code_t err_code;

    
    
    //print out the peer address of the target device
    while (j<6)
  {
    p_peer_address[j]=p_adv_report->peer_addr.addr[j];
      j++;
  }

    // searching the device uuid, only works when the target uuid is specified as the type 0x02
    // we can use other feature to do the matching, like device name, manufature specified data, peer address...... 
    if (peer_address[0]==p_peer_address[0]&&
      peer_address[1]==p_peer_address[1]&&
      peer_address[2]==p_peer_address[2]&&
      peer_address[3]==p_peer_address[3]&&
      peer_address[4]==p_peer_address[4]&&
      peer_address[5]==p_peer_address[5])
    {
      m_rssi = p_adv_report->rssi;//taking the rssi value
      NRF_LOG_INFO("my_RSSI: %d",m_rssi);
    }

     err_code = sd_ble_gap_scan_start(NULL, &m_scan_buffer);
     APP_ERROR_CHECK(err_code);
}


/**@brief Function for handling BLE events.
 *
 * @param[in]   p_ble_evt   Bluetooth stack event.
 * @param[in]   p_context   Unused.
 */
static void ble_evt_handler(ble_evt_t const * p_ble_evt, void * p_context)
{
    //ret_code_t err_code;

    // For readability.
    ble_gap_evt_t const * p_gap_evt = &p_ble_evt->evt.gap_evt;

    switch (p_ble_evt->header.evt_id)
    {
        //once receive the advertising report, implement the report handler
        //potential changed: directly receive RSSI report might be more sensitive
        case BLE_GAP_EVT_ADV_REPORT:
            on_adv_report(&p_gap_evt->params.adv_report);
            break;
    
        default:
            // No implementation needed.
            break;
    }
}

/**@brief Function for initializing the BLE stack.
 *
 * @details Initializes the SoftDevice and the BLE event interrupts.
 */
static void ble_stack_init(void)
{
    ret_code_t err_code;

    err_code = nrf_sdh_enable_request();
    APP_ERROR_CHECK(err_code);

    // Configure the BLE stack using the default settings.
    // Fetch the start address of the application RAM.
    uint32_t ram_start = 0;
    err_code = nrf_sdh_ble_default_cfg_set(APP_BLE_CONN_CFG_TAG, &ram_start);
    APP_ERROR_CHECK(err_code);

    // Enable BLE stack.
    err_code = nrf_sdh_ble_enable(&ram_start);
    APP_ERROR_CHECK(err_code);

    // Register a handler for BLE events.
    NRF_SDH_BLE_OBSERVER(m_ble_observer, APP_BLE_OBSERVER_PRIO, ble_evt_handler, NULL);
}


/**@brief Function for initializing power management.
 */
static void power_management_init(void)
{
    ret_code_t err_code;
    err_code = nrf_pwr_mgmt_init();
    APP_ERROR_CHECK(err_code);
}


/**@brief Function for handling the idle state (main loop).
 *
 * @details Handle any pending log operation(s), then sleep until the next event occurs.
 */
static void idle_state_handle(void)
{
    if (NRF_LOG_PROCESS() == false)
    {
        nrf_pwr_mgmt_run();
    }
}


/** @brief Function for initializing the log module.
 */
static void log_init(void)
{
    ret_code_t err_code = NRF_LOG_INIT(NULL);
    APP_ERROR_CHECK(err_code);

    NRF_LOG_DEFAULT_BACKENDS_INIT();
}



int main(void)
{
    // Initialize.
    log_init();
    power_management_init();
    ble_stack_init();
    ble_conn_state_init();
    twis_init();

    // Start execution.
    NRF_LOG_INFO("BLE and I2C started.");
    scan_start();

    for (;;)
    {
        idle_state_handle();
    }
}

From the oscilloscope, I can see the stm32 sent the start condition, stop condition, the slave address, the write or read command; the nrf52 sent the ACK to appropriate positions and data.   

Parents
  • From the oscilloscope, I can see the stm32 sent the start condition, stop condition, the slave address, the write or read command; the nrf52 sent the ACK to appropriate positions and data.   
    So an Arduino can read the nRF52 just fine, and the nRF52 both acknowledges your commands and transfers data to the STM32? Doesn't all this indicate a bug in your STM32 code? Maybe it is expecting a certain number of bytes, but not getting as many?

    Or it could be an issue with the voltage levels. Are both the STM and the nRF52 running on the same supply voltage? And do they have common ground?

  • Thanks, Martin. Yes, but when I test the STM32 code with another I2C device and it works, so I couldn't sure whether the STM32 or nRF52 causes the problem. The STM32 and nRF52 are using the same supply voltage and share the same ground. I set the STM32 to receive one byte for each time and nRF52 prepares one byte too.   

Reply Children
Related