Hi,
I am writing an application that reads data from the I2S interface, adds it to a queue and sends it via BLE (the code I have implemented so far is added at the end of this post).
In a previous thread (https://devzone.nordicsemi.com/f/nordic-q-a/87656/create-custom-event-to-trigger-updating-data-in-gatt-table), I have reached a state where I am able to send arbitrary data via BLE. I also know that reading data from the I2S works. However, integrating those parts into one application causes the application to run into an error (all 4 LEDs on my nRF52 DK are on).
EDIT: For clarification: the nRF is advertising and I can connect to it from nRF Connect for Desktop and Mobile. The problem starts when I enable notifications and the code, thereby, enters the if-clause in line 46 in my main function (i2s_transfer becomes true).
The code is based on the ble_app_template and the I2S loopback example. I'm using the nRF52 DK, nRF5 SDK 17.1.0 with S132 and Segger emStudio 5.42a.
Could there be too many interrupts that call the data_handler so that the rest of the code cannot be executed (I'm sampling with ~ 44 kHz, so the buffer of 256 bytes will be filled quickly)? I'm also thinking that the allocated RAM could be insufficient (I attach my section placement macros below).
Can anybody suggest a fix that I can try or an alternative implementation to achieve what I have mentioned above? Any help is appreciated.
CODE:
The section placement macros:
FLASH_PH_START=0x0 FLASH_PH_SIZE=0x80000 RAM_PH_START=0x20000000 RAM_PH_SIZE=0x10000 FLASH_START=0x26000 FLASH_SIZE=0x5a000 RAM_START=0x20002ad8 RAM_SIZE=0xd528
Here are the relevant declarations:
#define I2S_DATA_BLOCK_WORDS 256 static uint32_t m_buffer_rx[2][I2S_DATA_BLOCK_WORDS]; static uint32_t m_buffer_tx[2][I2S_DATA_BLOCK_WORDS]; NRF_QUEUE_DEF(uint8_t, m_queue, 3072, NRF_QUEUE_MODE_OVERFLOW); uint8_t m_array[244] = {0};
Here is my main function:
/**@brief Function for application main entry. */ int main(void) { bool erase_bonds; uint8_t err_code; // Initialize. log_init(); timers_init(); buttons_leds_init(&erase_bonds); power_management_init(); // Initialize TWI/ I2C & Setup ADC twi_adc_configuration(); // Initialize i2s err_code = i2s_init(); if (err_code == NRF_SUCCESS) { NRF_LOG_INFO("I2S successfully initialized."); } else { NRF_LOG_INFO("Error initializing I2S."); } // Initialize BLE ble_stack_init(); gap_params_init(); gatt_init(); services_init(); advertising_init(); conn_params_init(); peer_manager_init(); // Start execution. NRF_LOG_INFO("Template example started."); // Start advertising advertising_start(erase_bonds); // Enter main loop. for (;;) { if (i2s_transfer) { // start i2s err_code = start_i2s(); if (err_code == NRF_SUCCESS) { NRF_LOG_INFO("I2S started"); } else { NRF_LOG_INFO("Failed starting I2S"); } if (nrf_queue_utilization_get(&m_queue) >= 244) { // get data from the queue err_code = nrf_queue_read(&m_queue, &m_array, sizeof(m_array)); if ((err_code != NRF_SUCCESS) && (err_code != NRF_ERROR_INVALID_STATE) && (err_code != NRF_ERROR_RESOURCES) && (err_code != NRF_ERROR_BUSY) && (err_code != BLE_ERROR_GATTS_SYS_ATTR_MISSING) ) { APP_ERROR_CHECK(err_code); } // send data via BLE err_code = ble_aas_value_update(&m_aas, &m_array); if ((err_code != NRF_SUCCESS) && (err_code != NRF_ERROR_INVALID_STATE) && (err_code != NRF_ERROR_RESOURCES) && (err_code != NRF_ERROR_BUSY) && (err_code != BLE_ERROR_GATTS_SYS_ATTR_MISSING) ) { APP_ERROR_CHECK(err_code); } if (err_code == NRF_ERROR_RESOURCES) { NRF_LOG_DEBUG("error resources"); if (ble_ready != true) { idle_state_handle(); } ble_ready = false; } } } } nrf_drv_i2s_stop(); NRF_LOG_FLUSH(); bsp_board_leds_off(); }
My start_i2s function:
int start_i2s() { uint32_t err_code = NRF_SUCCESS; nrf_drv_i2s_buffers_t const initial_buffers = { .p_tx_buffer = NULL, .p_rx_buffer = m_buffer_rx[0], }; err_code = nrf_drv_i2s_start(&initial_buffers, I2S_DATA_BLOCK_WORDS, 0); APP_ERROR_CHECK(err_code); return err_code; }
and my data handler:
static void data_handler(nrf_drv_i2s_buffers_t const * p_released, uint32_t status) { // 'nrf_drv_i2s_next_buffers_set' is called directly from the handler // each time next buffers are requested, so data corruption is not // expected. ASSERT(p_released); // When the handler is called after the transfer has been stopped // (no next buffers are needed, only the used buffers are to be // released), there is nothing to do. if (!(status & NRFX_I2S_STATUS_NEXT_BUFFERS_NEEDED)) { return; } // First call of this handler occurs right after the transfer is started. // No data has been transferred yet at this point, so there is nothing to // check. Only the buffers for the next part of the transfer should be // provided. if (!p_released->p_rx_buffer) { // .p_tx_buffer = m_buffer_tx[1] changed to .p_tx_buffer = NULL, since we only receive data nrf_drv_i2s_buffers_t const next_buffers = { .p_rx_buffer = m_buffer_rx[1], .p_tx_buffer = NULL, }; APP_ERROR_CHECK(nrf_drv_i2s_next_buffers_set(&next_buffers)); } else { uint16_t i; uint32_t const * p_word = NULL; uint8_t sample[3]; for (i = 0; i < I2S_DATA_BLOCK_WORDS; ++i) { p_word = &mp_block_to_check[i]; //decompose 32-bit sample and discard msb sample[0] = ((uint8_t const *)p_word)[0]; sample[1] = ((uint8_t const *)p_word)[1]; sample[2] = ((uint8_t const *)p_word)[2]; printf("\n %2x%2x%2x", sample[0], sample[1], sample[2]); // copy data to the queue ret_code_t err_code; err_code = nrf_queue_write(&m_queue, &sample, sizeof(sample)); NRF_LOG_DEBUG("data added to queue."); } // The driver has just finished accessing the buffers pointed by // 'p_released'. They can be used for the next part of the transfer // that will be scheduled now. APP_ERROR_CHECK(nrf_drv_i2s_next_buffers_set(p_released)); } }