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
  • Hi,

    Does the merged code build without any errors?

    regards

    Jared

  • I have so many doubt. 

    I don't know if you run the ble_app_att_mtu_throughput code, but normally you charge the code on the first nRF52832 and on the second nRF52832 and you can choose which one is the tester (the Central) and which one is the responder (the Peripheral). Once you choose it, data is sent from tester to responder. 

    Now, once I choose which one is the tester and which one is the responder, before send data via ble, start the spis code (in meanwhile I start the spi code in the nRF52840 which send data via spi) which is the part that allow to receive data, then send data via BLE.

  • Just to simplify the reading of the code. Before I tried to add the SPIS part, data were generated in the amts.c as mentioned in line 220-222:

    for (uint16_t i = 0; i < payload_len; i++) {
          data[i] = i % 244;  // Riempie il buffer con valori da 0 a 243
      }

    so I think I should work there.

  • sorry for late response here Stefano, Jared is away and will be back on Monday. Thanks for your patience so far.

  • 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 

Reply
  • 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 

Children
Related