Hi,
I'm using a nRF52 DK (nRF52832) and nRF5 SDK 17.0.1. to read data from an external ADC via I2S. I can read some data from the I2S bus, but I'm confused about the bit alignment.
The ADC is configured to provide 24 bit samples. The Product Specification of the nRF52832 states (on page 453):
The size of the buffers is specified in a number of 32-bit words. Such a 32-bit memory word can either contain four 8-bit samples, two 16-bit samples or one right-aligned 24-bit sample sign extended to 32 bit.
Since I need to send the data via BLE, I want to get rid of the sign extension and only send the 24 bit samples (or 3 x 8 bits). So my strategy was the following:
1. the data handler which is called on a new interrupt by the i2s driver, writes the data to mp_block_to_check (see also the i2s example of the SDK):
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 { mp_block_to_check = p_released->p_rx_buffer; // 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)); } }
2. a custom function (similar to the check_samples function of the SDK's i2s example), iterates over all 32-bit samples in mp_block to check and discards the first 8 bits (because each sample should be right-aligned and sign extended to 32-bits):
static void queue_data() { 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]; sample[0] = ((uint8_t const *)p_word)[1]; sample[1] = ((uint8_t const *)p_word)[2]; sample[2] = ((uint8_t const *)p_word)[3]; //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)); APP_ERROR_CHECK(err_code); } }
3. As you can see, the 3 x 8 bits samples are added to a queue from where they are sent via BLE.
The problem is, that the data on the receiver's side (nrf connect for desktop with nRF42840 dongle) does not match the expected data. I also saw that the sdk_config.h specifies:
// <o> I2S_CONFIG_ALIGN - Alignment // <0=> Left // <1=> Right #ifndef I2S_CONFIG_ALIGN #define I2S_CONFIG_ALIGN 0 #endif
So I'm confused. Is the data now right-aligned and sign-extended like stated in the Product Specs or is it aligned as I specify in the sdk_config.h?
Am I handling the bytes in the correct way or am I doing something wrong? Could my problem (received data does not match the exptected data) could have other problems?
Thanks a lot for any hints.