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

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

Reply Children
  • Hi,

    Did you any clock signal on SCLK? 

    What about CS?

    regards

    Jared 

  • No but maybe I'm making some mistake. I connect the SPI Master to the SPI Driver (so I disconnected the SPI Slave), is it right?

  • However, I think the main problem is in the fact the SPI Master code isn't included in the ble_app_att_mtu_throughput project. I tried to add the spis code but is not enough. But another problem is the fact that the SPI Master is an nRF52840 board, not nRF52832 board as the SPI Slave or the ble client.

    I think it's ambitious, but I would try to include nRF52840 in the project. Is possible? The problem I'm afraid of is the fact that the SPI Master is an nRF52840 so I can't run the ble_app_att_mtu_throughput_pca_10040 as SPI Slave (which is also ble server) or ble client

  • Hi,

    Earlier you wrote that the example works when the SPI code is not included. You mentioned that you do not see any SPI activity on SCLK, CS, MOSI or MISO when including the SPI code. Have you made sure to test only the SPI code separate from the BLE code, and verified that it works?

    I think that would be a good first step, before trying to merge that in to the BLE sample,

    regards

    Jared 

  • Hi,

    Earlier you wrote that the example works when the SPI code is not included

    Yes, right. I moved the spi part from the main to the amts.c and it doesn't interfere, so the code run, but what the server receive is just 0 (instead of the data I send).

    Have you made sure to test only the SPI code separate from the BLE code, and verified that it works?

    Yes, and in this case the SPI communication between SPI Master and SPI Slave works perfectly. It seems like the SPI Slave (when become also BLE server), when I run the ble code, can't receive data via SPI.

    Regards

Related