Problem with I2S TX / RX Circular DMA on STM32H743ZI2 board
I have a problem with DMA on this board that was not present on an F407 using code generated by Cube.
I2S2 has been configured as master half duplex and IS23 as slave half duplex (fed clock and WS of I2S2). The plan was to have a MEMS microphone on the slave and DAC on the I2S3.
I/O buffers for transfers have been placed in D2 RAM, cache then invalidated before setting off receive DMA (circular) and subsequently cleaned before setting off transmit DMA (circular).
Next is where I have been having issues, I have a tried and tested (F407) FIFO setup in a while loop to grab data and feed it through to TX. I have the problem that my DMA appears to block and mess up the while loop and each of the callbacks creating unexpected orders of code execution and intermittent hanging.
I and D cache enabled. Could this be a cache maintancne problem? If I disable the caches I still have issues.
__SECTION_RAM_D2
uint16_t txBuf[128];
__SECTION_RAM_D2
uint16_t rxBuf[128];
uint8_t txstate = 0;
uint8_t rxstate = 0;
#define LED_TIMEOUT PCM_SAMPLE_RATE / (128 / 4) // 1 second.
uint32_t LED3Timeout = 0;
uint32_t LED4Timeout = 0;
uint32_t LED5Timeout = 0;
uint32_t LED6Timeout = 0;
uint16_t fifobuf[256];
uint8_t fifo_w_ptr = 0;
uint8_t fifo_r_ptr = 0;
uint8_t fifo_read_enabled = 0;
int main(void)
{
SCB_EnableICache();
SCB_EnableDCache();
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_DMA_Init();
MX_I2S2_Init();
MX_I2S3_Init();
SCB_InvalidateDCache_by_Addr((uint32_t*)(((uint32_t)rxBuf) & ~(uint32_t)0x1F), sizeof(rxBuf));
HAL_I2S_Receive_DMA(&hi2s3, &rxBuf[0], 64);
SCB_CleanDCache_by_Addr((uint32_t*)(((uint32_t)txBuf) & ~(uint32_t)0x1F), sizeof(txBuf));
HAL_I2S_Transmit_DMA(&hi2s2, &txBuf[0], 64);
while (1)
{
if (txstate == 1)
{
if (fifo_read_enabled == 1)
{
memcpy(&txBuf[0], &fifobuf[fifo_r_ptr], 128);
fifo_r_ptr += 64;
}
SCB_CleanDCache_by_Addr((uint32_t*)(((uint32_t)txBuf) & ~(uint32_t)0x1F), sizeof(txBuf) / 2);
txstate = 0;
}
if (rxstate == 1)
{
SCB_InvalidateDCache_by_Addr((uint32_t*)(((uint32_t)rxBuf) & ~(uint32_t)0x1F), sizeof(rxBuf) / 2);
memcpy(&fifobuf[fifo_w_ptr], &rxBuf[0], 128);
fifo_w_ptr += 64;
if (fifo_w_ptr - fifo_r_ptr > 128)
{
fifo_read_enabled = 1;
}
rxstate = 0;
}
if (txstate == 2)
{
if (fifo_read_enabled == 1)
{
memcpy(&txBuf[64], &fifobuf[fifo_r_ptr], 128);
fifo_r_ptr += 64;
}
SCB_CleanDCache_by_Addr((uint32_t*)(((uint32_t)&txBuf[64]) & ~(uint32_t)0x1F), sizeof(txBuf) / 2);
txstate = 0;
}
if (rxstate == 2)
{
SCB_InvalidateDCache_by_Addr((uint32_t*)(((uint32_t)&rxBuf[64]) & ~(uint32_t)0x1F), sizeof(rxBuf) / 2);
memcpy(&fifobuf[fifo_w_ptr], &rxBuf[64], 128);
fifo_w_ptr += 64;
rxstate = 0;
}
}
}Here are the callbacks:
void HAL_I2S_TxHalfCpltCallback(I2S_HandleTypeDef *hi2s)
{
// Error LED.
if (LED3Timeout > 0)
{
LED3Timeout--;
}
if (txstate != 0)
{
HAL_GPIO_WritePin(LD1_GPIO_Port, LD1_Pin, GPIO_PIN_SET);
LED3Timeout = LED_TIMEOUT;
}
else if (LED3Timeout == 0)
{
HAL_GPIO_WritePin(LD1_GPIO_Port, LD1_Pin, GPIO_PIN_RESET);
}
// Ready to transmit
txstate = 1;
}
void HAL_I2S_RxHalfCpltCallback(I2S_HandleTypeDef *hi2s)
{
// Error LED.
if (LED4Timeout > 0)
{
LED4Timeout--;
}
if (rxstate != 0)
{
HAL_GPIO_WritePin(LD1_GPIO_Port, LD1_Pin, GPIO_PIN_SET);
LED4Timeout = LED_TIMEOUT;
}
else if (LED4Timeout == 0)
{
HAL_GPIO_WritePin(LD1_GPIO_Port, LD1_Pin, GPIO_PIN_RESET);
}
// Ready to receive
rxstate = 1;
}
void HAL_I2S_TxCpltCallback(I2S_HandleTypeDef *hi2s)
{
// Error LED.
if (LED5Timeout > 0)
{
LED5Timeout--;
}
if (txstate != 0)
{
HAL_GPIO_WritePin(LD2_GPIO_Port, LD2_Pin, GPIO_PIN_SET);
LED5Timeout = LED_TIMEOUT;
}
else if (LED5Timeout == 0)
{
HAL_GPIO_WritePin(LD2_GPIO_Port, LD2_Pin, GPIO_PIN_RESET);
}
// Ready to transmit
txstate = 2;
}
void HAL_I2S_RxCpltCallback(I2S_HandleTypeDef *hi2s)
{
// Error LED.
if (LED6Timeout > 0)
{
LED6Timeout--;
}
if (rxstate != 0)
{
HAL_GPIO_WritePin(LD3_GPIO_Port, LD3_Pin, GPIO_PIN_SET);
LED6Timeout = LED_TIMEOUT;
}
else if (LED6Timeout == 0)
{
HAL_GPIO_WritePin(LD3_GPIO_Port, LD3_Pin, GPIO_PIN_RESET);
}
// Ready to receive
rxstate = 2;
}