I2S not working on 32-bit data with DMA
Hi,
I am using a STM32F407 with the TLV320AIC3204 audio codec. I have verified that the I2S works with a logic analyzer:

I am trying to read the data using DMA (I tried both circular and normal).
Here is my I2S configuration:


I made sure to add the following line to fix the DMA bug:
__HAL_RCC_DMA1_CLK_ENABLE();
Here is the code that is giving me problems:
#include "dsp.h"
#define BUFSIZE 8192
#define MIN(a,b) (((a)<(b))?(a):(b))
#define MAX(a,b) (((a)>(b))?(a):(b))
static volatile int64_t sin_a;
static volatile int64_t cos_a;
static volatile int64_t sin_b;
static volatile int64_t cos_b;
uint16_t adcBuf[BUFSIZE];
static volatile int done;
static int bufLen;
static int32_t combineUint(uint16_t a, uint16_t b){
return (int32_t)(((uint32_t)a << 16))| (uint32_t)b ;
}
static int processArray(uint16_t* arr, int len){
for (int i = 0 ; i < len; i+= 16){
cos_a += combineUint(arr[i], arr[i+1]);
cos_b += combineUint(arr[i+2], arr[i+3]);
sin_a += combineUint(arr[i+4], arr[i+5]);
sin_b += combineUint(arr[i+6], arr[i+7]);
cos_a -= combineUint(arr[i+8], arr[i+9]);
cos_b -= combineUint(arr[i+10], arr[i+11]);
sin_a -= combineUint(arr[i+12], arr[i+13]);
sin_b -= combineUint(arr[i+14], arr[i+15]);
}
}
void HAL_I2S_RxHalfCpltCallback(I2S_HandleTypeDef *hi2s2){
if (bufLen >= 128){
//processArray(adcBuf, bufLen );
}
}
void HAL_I2S_RxCpltCallback(I2S_HandleTypeDef *hi2s2){
if (bufLen >= 128){
// processArray(adcBuf+bufLen , bufLen );
} else {
// processArray(adcBuf, bufLen * 2);
}
done = 1;
}
int dspDone(){
return done;
}
void startDSP(int avg){
bufLen = avg * 8;
if (bufLen * 2 > BUFSIZE ) return;
sin_a = 0;
sin_b = 0;
cos_a = 0;
cos_b = 0;
done = 0;
// while (HAL_GPIO_ReadPin (GPIOB, GPIO_PIN_12));
// while (!HAL_GPIO_ReadPin (GPIOB, GPIO_PIN_12)); // Wait for WS = LOW
HAL_I2S_Receive_DMA(&hi2s2, adcBuf, bufLen);
}
static float magnitude (int64_t a, int64_t b){
float c = a;
float d = b;
return sqrtf(c*c+d*d);
}
void getResults(float *mag, float *ang){
*mag = magnitude(sin_a, cos_a)/magnitude(sin_b, cos_b);
*ang = atan2(sin_a, cos_a) - atan2(sin_b , cos_b);
}
With lines 63 and 64 commented, I get random data sometimes (see picture below where I breakpointed on line 78, which is called after done = 1. You can see that the data is bit shifted by a random amount. There is nothing connected to the ADC, so the MSB should be close to 0xFFFF or 0x0000. However, these values are not.

I was able to fix the problem somewhat by uncommenting lines 63 and 64, which only allows the I2S to start when WS is low. (Trying it when WS=high gave me garbage every time). The issue now is that I am seeing the data offset by 16 bits sometimes.
For example, here, the MSB are in the even positions (all of the numbers in the even positions don't change very much, and are close to 0xFFFF):

However, if I wait until the breakpoint is triggered again, I get

Now the MSB is in the odd positions. Any idea why this is happening? With lines 63 and 64 uncommented, on most runs the MSB is in the even positions the first time, and every time after that the MSB is in the odd positions.
Here is my main function:
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
__HAL_RCC_DMA1_CLK_ENABLE();
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_I2S2_Init();
MX_DAC_Init();
MX_I2C1_Init();
MX_SPI3_Init();
MX_USART1_UART_Init();
MX_ADC1_Init();
MX_DMA_Init();
MX_USB_DEVICE_Init();
MX_ADC2_Init();
/* USER CODE BEGIN 2 */
resetRegisters();
HAL_DAC_Start(&hdac, DAC_CHANNEL_1);
HAL_DAC_Start(&hdac, DAC_CHANNEL_2);
setVoltage(-1.5, 1);
setVoltage(-1.5, 2);
HAL_Delay(100);
tlv320aic3204_init();
resetLMX();
int counter = 10;
float voltage = -2;
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
if (counter > 226){
counter = 10;
}
if (voltage > -1.45){
voltage = -2;
}
setFrequency(counter * 100 * MHz, 2);
HAL_Delay(20);
counter++;
voltage += 0.1;
setVoltage(voltage, 2);
setVoltage(voltage, 1);
startDSP(16);
while (!dspDone());
float m;
float a;
getResults(&m, &a);
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
