Hello Nordic Semiconductor
I am developing a small application on the nRF52840 development kit where I need to transfer I2S signals in/out of the MCU. I have set up an I2S_IRQHandler() that gets triggered whenever EVENT_TXPTRUPD gets set. However, I cannot clear it again, which I am supposed to do in the interrupt handler. Basically, this turns my interrupt handler into an endless loop, never returning to the main loop after the event.
I believe this is a bug. I found this thread as well, which I believe is the same problem:
So, I created a small project that can reproduce the problem. I used Ozone - The J-Link Debugger to debug the problem. However, I could not find the EVENTS_TXPTRUPD register inside the register viewer, so I watched a variable "tmp" instead.
I have included a source file that can reproduce the problem below, as well as some screenshots, where I go through a few breakpoints. Watch the variable "tmp" in the "Global Data" window in the upper right corner.
My SDK and toolchain versions are nRF5_SDK_17.1.0_ddde560 and gcc-arm-none-eabi-9-2020-q2-update respectively.
I am not sure which revision of the nRF52840 DK I am using, but there is a sticker saying "PCA10056, 2.0.2, 2021.50, 683128720". Please let me know if you need further information.
Thank you in advance :-)
#include "boards.h" // Temporary variable to store register value volatile uint32_t tmp; // RX and TX buffers for I2S volatile int16_t i2s_rx_buf[128]; volatile int16_t i2s_tx_buf[128]; int main(void) { tmp = 0; // Set I2S in master mode and the clocks to ~ 48 kHz sample rate NRF_I2S->CONFIG.MODE = I2S_CONFIG_MODE_MODE_Master; NRF_I2S->CONFIG.MCKFREQ = I2S_CONFIG_MCKFREQ_MCKFREQ_32MDIV21; NRF_I2S->CONFIG.RATIO = I2S_CONFIG_RATIO_RATIO_32X; // Set the format to 16-bit stereo NRF_I2S->CONFIG.CHANNELS = I2S_CONFIG_CHANNELS_CHANNELS_Stereo; NRF_I2S->CONFIG.FORMAT = I2S_CONFIG_FORMAT_FORMAT_I2S; NRF_I2S->CONFIG.ALIGN = I2S_CONFIG_ALIGN_ALIGN_Left; NRF_I2S->CONFIG.SWIDTH = I2S_CONFIG_SWIDTH_SWIDTH_16Bit; // Buffer setup NRF_I2S->RXTXD.MAXCNT = 64; NRF_I2S->RXD.PTR = (uint32_t)i2s_rx_buf; NRF_I2S->TXD.PTR = (uint32_t)i2s_tx_buf; // Pin setup NRF_I2S->PSEL.MCK = (1<<5) | 1; // Connect MCK to P1.01 NRF_I2S->PSEL.SCK = (1<<5) | 2; // Connect SCK to P1.02 NRF_I2S->PSEL.LRCK = (1<<5) | 3; // Connect LRCK to P1.03 NRF_I2S->PSEL.SDIN = (1<<5) | 4; // Connect SDIN to P1.04 NRF_I2S->PSEL.SDOUT = (1<<5) | 5; // Connect SDOUT to P1.05 // Configure interrupts NRF_I2S->INTEN = I2S_INTEN_TXPTRUPD_Enabled; NVIC_EnableIRQ(I2S_IRQn); // Enable and start NRF_I2S->CONFIG.RXEN = I2S_CONFIG_RXEN_RXEN_Enabled; NRF_I2S->CONFIG.TXEN = I2S_CONFIG_TXEN_TXEN_Enabled; NRF_I2S->CONFIG.MCKEN = I2S_CONFIG_MCKEN_MCKEN_Enabled; NRF_I2S->ENABLE = 1; NRF_I2S->TASKS_START = 1; // Main loop while (1); } void I2S_IRQHandler() { // Clear the event (but store the value before and after for debugging) tmp = NRF_I2S->EVENTS_TXPTRUPD; // Set breakpoint here NRF_I2S->EVENTS_TXPTRUPD = 0; tmp = NRF_I2S->EVENTS_TXPTRUPD; // Set another break point here tmp; // and a third breakpoint here }