Merging spi and ble_app_att_mtu_throughput

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

Parents Reply Children
  • 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.

Related