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));
}
}