Hi,
I'm struggling to use ble_app_att_mtu_throughput and spi. Some help?
When I merge the two codes the main code (ble_app_att_mtu_throughput) doesn't work.
Thanks for your help
Hi,
I'm struggling to use ble_app_att_mtu_throughput and spi. Some help?
When I merge the two codes the main code (ble_app_att_mtu_throughput) doesn't work.
Thanks for your help
Hi Susheel,
Thanks. Meanwhile, adding what I said to Jared in previous messages, I show you something else.
This is a simply spi-spis SPI comunication where I send via SPI 10 packets of 244 bytes (from 0 to 243) from the Master and these bytes arrives to the Slave. I'll show just the firsts 10 bytes for each packets to avoid filling the buffer log:

I verified bytes are succesfully send/received for each packets.
The problem come when I run on the the board which receive data via spi (so the board where I charge spis) the ble_att_app_mtu_thrpughput+spis:

This image show what I receive via spi with this code.
The news (compared to what I said to Jared) is that I'm trying to implement the spis part of the code on the amts.c and not in the main.c:
#include "amt.h"
#include "app_error.h"
#include "ble_err.h"
#include "ble_srv_common.h"
#include "nrf_error.h"
#include "sdk_common.h"
#include "nrf_drv_spis.h"
#define NRF_LOG_MODULE_NAME AMTS
#include "nrf_log.h"
NRF_LOG_MODULE_REGISTER();
#define OPCODE_LENGTH 1 /**< Length of opcode inside a notification. */
#define HANDLE_LENGTH 2 /**< Length of handle inside a notification. */
static const nrf_drv_spis_t spis = NRF_DRV_SPIS_INSTANCE(1);
#define MAX_PACKET_SIZE 244
static uint8_t m_tx_buf[MAX_PACKET_SIZE] = {0};
static uint8_t m_rx_buf[MAX_PACKET_SIZE + 1];
static const uint8_t m_length = MAX_PACKET_SIZE;
static volatile bool spis_xfer_done = false;
static uint8_t packets_received = 0;
static nrf_ble_amts_t *p_ctx;
void spis_event_handler(nrf_drv_spis_event_t event)
{
if (event.evt_type == NRF_DRV_SPIS_XFER_DONE)
{
spis_xfer_done = true;
packets_received++;
NRF_LOG_INFO("SPIS Transfer completed. Received data:");
for (uint8_t i = 0; i < m_length; i++)
{
NRF_LOG_INFO("%03d", m_rx_buf[i]); // Log in decimal
}
if (p_ctx->conn_handle != BLE_CONN_HANDLE_INVALID)
{
// Aggiorna bytes_sent con la lunghezza dei dati ricevuti via SPI
p_ctx->bytes_sent += m_length;
// Invia i dati ricevuti via SPI tramite BLE
nrf_ble_amts_send(p_ctx, m_rx_buf, m_length);
// Genera l'evento per la trasmissione dei dati
nrf_ble_amts_evt_t evt;
evt.evt_type = NRF_BLE_AMTS_EVT_TRANSFER_244B;
evt.bytes_transfered_cnt = p_ctx->bytes_sent;
p_ctx->evt_handler(evt);
}
}
}
void spis_init(nrf_ble_amts_t *p_ctx)
{
nrf_drv_spis_config_t spis_config = NRF_DRV_SPIS_DEFAULT_CONFIG;
spis_config.csn_pin = APP_SPIS_CS_PIN;
spis_config.miso_pin = APP_SPIS_MISO_PIN;
spis_config.mosi_pin = APP_SPIS_MOSI_PIN;
spis_config.sck_pin = APP_SPIS_SCK_PIN;
APP_ERROR_CHECK(nrf_drv_spis_init(&spis, &spis_config, spis_event_handler));
}
static void char_notification_send(nrf_ble_amts_t *p_ctx);
/**@brief Function for handling the Connect event.
*
* @param p_ctx Pointer to the AMTS structure.
* @param[in] p_ble_evt Event received from the BLE stack.
*/
static void on_connect(nrf_ble_amts_t *p_ctx, ble_evt_t const *p_ble_evt)
{
p_ctx->conn_handle = p_ble_evt->evt.gap_evt.conn_handle;
}
/**@brief Function for handling the Disconnect event.
*
* @param p_ctx Pointer to the AMTS structure.
* @param[in] p_ble_evt Event received from the BLE stack.
*/
static void on_disconnect(nrf_ble_amts_t *p_ctx, ble_evt_t const *p_ble_evt)
{
p_ctx->conn_handle = BLE_CONN_HANDLE_INVALID;
}
/**@brief Function for handling the TX_COMPLETE event.
*
* @param p_ctx Pointer to the AMTS structure.
*/
static void on_tx_complete(nrf_ble_amts_t *p_ctx)
{
if (p_ctx->busy)
{
p_ctx->busy = false;
char_notification_send(p_ctx);
}
}
/**@brief Function for handling the Write event.
*
* @param p_ctx Pointer to the AMTS structure.
* @param[in] p_ble_evt Event received from the BLE stack.
*/
static void on_write(nrf_ble_amts_t *p_ctx, ble_evt_t const *p_ble_evt)
{
ble_gatts_evt_write_t const *p_evt_write = &p_ble_evt->evt.gatts_evt.params.write;
if ((p_evt_write->handle == p_ctx->amts_char_handles.cccd_handle) && (p_evt_write->len == 2))
{
// CCCD written, call the application event handler.
nrf_ble_amts_evt_t evt;
if (ble_srv_is_notification_enabled(p_evt_write->data))
{
evt.evt_type = NRF_BLE_AMTS_EVT_NOTIF_ENABLED;
}
else
{
evt.evt_type = NRF_BLE_AMTS_EVT_NOTIF_DISABLED;
}
p_ctx->evt_handler(evt);
}
}
void nrf_ble_amts_on_ble_evt(ble_evt_t const *p_ble_evt, void *p_context)
{
nrf_ble_amts_t *p_ctx = (nrf_ble_amts_t *)p_context;
switch (p_ble_evt->header.evt_id)
{
case BLE_GAP_EVT_CONNECTED:
on_connect(p_ctx, p_ble_evt);
break;
case BLE_GAP_EVT_DISCONNECTED:
on_disconnect(p_ctx, p_ble_evt);
break;
case BLE_GATTS_EVT_WRITE:
on_write(p_ctx, p_ble_evt);
break;
case BLE_GATTS_EVT_HVN_TX_COMPLETE:
on_tx_complete(p_ctx);
break;
default:
break;
}
}
void nrf_ble_amts_init(nrf_ble_amts_t *p_ctx, amts_evt_handler_t evt_handler)
{
ret_code_t err_code;
uint16_t service_handle;
ble_uuid_t ble_uuid;
ble_uuid128_t base_uuid = {SERVICE_UUID_BASE};
err_code = sd_ble_uuid_vs_add(&base_uuid, &(p_ctx->uuid_type));
APP_ERROR_CHECK(err_code);
ble_uuid.type = p_ctx->uuid_type;
ble_uuid.uuid = AMT_SERVICE_UUID;
// Add service.
err_code = sd_ble_gatts_service_add(BLE_GATTS_SRVC_TYPE_PRIMARY, &ble_uuid, &service_handle);
APP_ERROR_CHECK(err_code);
// Add AMTS characteristic.
ble_add_char_params_t amt_params;
memset(&amt_params, 0, sizeof(amt_params));
amt_params.uuid = AMTS_CHAR_UUID;
amt_params.uuid_type = p_ctx->uuid_type;
amt_params.max_len = NRF_SDH_BLE_GATT_MAX_MTU_SIZE;
amt_params.char_props.notify = 1;
amt_params.cccd_write_access = SEC_OPEN;
amt_params.is_var_len = 1;
err_code = characteristic_add(service_handle, &amt_params, &(p_ctx->amts_char_handles));
APP_ERROR_CHECK(err_code);
// Add AMT Received Bytes Count characteristic.
ble_add_char_params_t amt_rbc_params;
memset(&amt_rbc_params, 0, sizeof(amt_rbc_params));
amt_rbc_params.uuid = AMT_RCV_BYTES_CNT_CHAR_UUID;
amt_rbc_params.uuid_type = p_ctx->uuid_type;
amt_rbc_params.max_len = AMT_RCV_BYTES_CNT_MAX_LEN;
amt_rbc_params.char_props.read = 1;
amt_rbc_params.read_access = SEC_OPEN;
err_code = characteristic_add(service_handle, &amt_rbc_params, &(p_ctx->amt_rbc_char_handles));
APP_ERROR_CHECK(err_code);
p_ctx->evt_handler = evt_handler;
spis_init(p_ctx);
}
void nrf_ble_amts_notif_spam(nrf_ble_amts_t *p_ctx)
{
p_ctx->kbytes_sent = 0;
p_ctx->bytes_sent = 0;
char_notification_send(p_ctx);
}
void nrf_ble_amts_on_gatt_evt(nrf_ble_amts_t *p_ctx, nrf_ble_gatt_evt_t const *p_gatt_evt)
{
if (p_gatt_evt->evt_id == NRF_BLE_GATT_EVT_ATT_MTU_UPDATED)
{
p_ctx->max_payload_len =
p_gatt_evt->params.att_mtu_effective - OPCODE_LENGTH - HANDLE_LENGTH;
}
}
static void char_notification_send(nrf_ble_amts_t *p_ctx)
{
uint16_t payload_len = p_ctx->max_payload_len;
nrf_ble_amts_evt_t evt;
if (p_ctx->bytes_sent >= AMT_BYTE_TRANSFER_CNT)
{
evt.bytes_transfered_cnt = p_ctx->bytes_sent;
evt.evt_type = NRF_BLE_AMTS_EVT_TRANSFER_FINISHED;
p_ctx->evt_handler(evt);
p_ctx->busy = false;
p_ctx->bytes_sent = 0;
p_ctx->kbytes_sent = 0;
return;
}
ble_gatts_hvx_params_t hvx_param =
{
.type = BLE_GATT_HVX_NOTIFICATION,
.handle = p_ctx->amts_char_handles.value_handle,
.p_data = m_rx_buf,
.p_len = &payload_len,
};
uint32_t err_code = NRF_SUCCESS;
uint16_t packets_to_send = PACKETS;
while (err_code == NRF_SUCCESS && packets_to_send > 0)
{
err_code = sd_ble_gatts_hvx(p_ctx->conn_handle, &hvx_param);
if (err_code == NRF_ERROR_RESOURCES)
{
// Wait for BLE_GATTS_EVT_HVN_TX_COMPLETE.
p_ctx->busy = true;
break;
}
else if (err_code != NRF_SUCCESS)
{
NRF_LOG_ERROR("sd_ble_gatts_hvx() failed: 0x%x", err_code);
}
p_ctx->bytes_sent += payload_len;
if (p_ctx->kbytes_sent != (p_ctx->bytes_sent / 244))
{
p_ctx->kbytes_sent = (p_ctx->bytes_sent / 244);
NRF_LOG_INFO("Sending data: ");
for (uint16_t i = 0; i < 10; i++)
{
NRF_LOG_INFO("Byte %d: %d", i, m_rx_buf[i]);
}
evt.evt_type = NRF_BLE_AMTS_EVT_TRANSFER_244B;
evt.bytes_transfered_cnt = p_ctx->bytes_sent;
p_ctx->evt_handler(evt);
}
packets_to_send--;
}
}
void nrf_ble_amts_rbc_set(nrf_ble_amts_t *p_ctx, uint32_t byte_cnt)
{
uint8_t data[AMT_RCV_BYTES_CNT_MAX_LEN];
uint16_t len;
ble_gatts_value_t value_param;
memset(&value_param, 0x00, sizeof(value_param));
len = (uint16_t)uint32_encode(byte_cnt, data);
value_param.len = len;
value_param.p_value = data;
ret_code_t err_code = sd_ble_gatts_value_set(p_ctx->conn_handle,
p_ctx->amt_rbc_char_handles.value_handle,
&value_param);
if (err_code != NRF_SUCCESS)
{
NRF_LOG_ERROR("sd_ble_gatts_value_set() failed: 0x%x", err_code);
}
}
void nrf_ble_amts_send(nrf_ble_amts_t *p_ctx, uint8_t *data, uint16_t length)
{
if (p_ctx->conn_handle == BLE_CONN_HANDLE_INVALID)
{
NRF_LOG_ERROR("No connection established, cannot send data.");
return;
}
ble_gatts_hvx_params_t hvx_params = {
.type = BLE_GATT_HVX_NOTIFICATION,
.handle = p_ctx->amts_char_handles.value_handle,
.p_data = data,
.p_len = &length,
};
uint32_t err_code = sd_ble_gatts_hvx(p_ctx->conn_handle, &hvx_params);
if (err_code != NRF_SUCCESS)
{
NRF_LOG_ERROR("sd_ble_gatts_hvx() failed: 0x%x", err_code);
}
else
{
NRF_LOG_INFO("Data sent successfully.");
}
}
Thanks for all,
Best regards.
Hi,
Based on your latest answer, it seems like you are able to get logs compared to earlier. That is good.
I know understand that you are not getting the desired data on the log output from the SPI communication.
First step in debugging this is to either connect a logic analyzer or a oscilloscope to the MOSI/MISO pins, and confirm if the Master/slave is sending the expected data.
regards
Jared
Hi,
Is an SPI Driver suitable to this scope? For istance I connected the SPI Driver to the pins of the SPI Slave/Master but I see nothing (maybe because 0 is the data received
Yes, the SPI driver should be able to work along side the BLE samples. Did you probe the SPI lines as I suggested in my last reply?
Yes, I connected the MISO/MOSI to the SPI Driver but nothing happen. I think because 0 is transmitting.