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.