cancel
Showing results for 
Search instead for 
Did you mean: 

STM32 HAL_SAI_Receive() in ISR gets stuck.

RBamf.1
Associate III

Hi, i'm trying to get a value from a microphone using HAL_SAI_Receive() in blocking mode.

I'm trying to write a program that receives a value from the mic connected to the SAI block.

The HAL_SAI_Receive() is called in an ISR but when the program is ran, it stops instantly.

Can anyone help me figure out why this is happening?

CPU: STM32L452RE

#include <SoftwareSerial.h>
#include <Arduino.h>
#include <HardwareTimer.h>
 
#include "stm32l4xx.h"
#include "stm32l4xx_hal.h"
#include "stm32l4xx_hal_def.h"
#include "stm32l4xx_hal_gpio.h"
#include "stm32l4xx_hal_sai.h"
#include "stm32l4xx_hal_exti.h"
#include "stm32l4xx_hal_cortex.h"
 
#include "Sysclock_Config.h"
 
void assert_failed(uint8_t* inFileName, uint32_t line) {
	char* fileNameAsString = (char*)inFileName;
	Serial2.println(F("*** [HAL ASSERT FAILED] ***"));
	Serial2.printf("%s\r\n", (char*)inFileName);
	Serial2.printf("%i\r\n", line);
}
void _Error_Handler(const char* file, int line) {
	Serial2.println(F("*** [ERROR HANDLED] ***"));
	Serial2.printf("%s\r\n", file);
	Serial2.printf("%i\r\n", line);
}
 
 
GPIO_InitTypeDef gpioInit;
SAI_HandleTypeDef saiHandle;
RCC_PeriphCLKInitTypeDef periphInit;
uint8_t	SAIDataBuffer[8] = { 0 };
 
HardwareTimer sampleTimer(TIM3);
 
void samplerCallback();
 
// the setup function runs once when you press reset or power the board
void setup() {
	delay(5000);
 
	Serial2.begin(115200);
	Serial2.println("Starting");
 
		/*
			Enable the GPIO B clock.
		*/
	__HAL_RCC_GPIOB_CLK_ENABLE();
 
 
	/*
		Enable the peripheral clock.
	*/
 
	__HAL_RCC_SAI1_CLK_ENABLE();
 
 
	/*
		Configure the GPIO pins.
	*/
	/**
	SAI1_A_Block_A GPIO Configuration
	PB15     ------> SAI1_SD_A
	PB10     ------> SAI1_SCK_A
	PB12     ------> SAI1_FS_A
	*/
	gpioInit.Pin = GPIO_PIN_15 | GPIO_PIN_10 | GPIO_PIN_12;
	gpioInit.Mode = GPIO_MODE_AF_PP;
	gpioInit.Pull = GPIO_NOPULL;
	gpioInit.Speed = GPIO_SPEED_FREQ_LOW;
	gpioInit.Alternate = GPIO_AF13_SAI1;
	HAL_GPIO_Init(GPIOB, &gpioInit);
 
 
	pinMode(PB1, OUTPUT);
	digitalWrite(PB1, LOW);
 
 
	__HAL_SAI_DISABLE(&saiHandle);
 
	// Block type def.
	saiHandle.Instance = SAI1_Block_A; // audio block A.
 
	saiHandle.Init.Protocol = SAI_FREE_PROTOCOL;
	saiHandle.Init.FirstBit = SAI_FIRSTBIT_MSB;
	saiHandle.Init.AudioFrequency = SAI_AUDIO_FREQUENCY_44K;
	saiHandle.Init.AudioMode = SAI_MODEMASTER_RX; // block a must provide clock signals and receive from the data line.
	saiHandle.Init.Synchro = SAI_ASYNCHRONOUS;	// we only want to use this one audio block.
	saiHandle.Init.SynchroExt = SAI_SYNCEXT_DISABLE; // disable sychronizing the 2 audio blocks.
	saiHandle.Init.OutputDrive = SAI_OUTPUTDRIVE_DISABLE; // assume to power the data?
	saiHandle.Init.NoDivider = SAI_MASTERDIVIDER_ENABLE; // any frame length allowed.
	saiHandle.Init.FIFOThreshold = SAI_FIFOTHRESHOLD_EMPTY;	// used for interrupts.
	saiHandle.Init.MonoStereoMode = SAI_STEREOMODE; // mono mode only available in transmission mode.
	saiHandle.Init.CompandingMode = SAI_NOCOMPANDING; // telecommunications specification (not needed)
	saiHandle.Init.TriState = SAI_OUTPUT_NOTRELEASED; // assume the SAI is ma
 
	//saiHandle.Init.ClockStrobing = SAI_CLOCKSTROBING_FALLINGEDGE;
	//saiHandle.Init.DataSize = SAI_DATASIZE_32;
 
	// block frame parameters.
	saiHandle.FrameInit.FrameLength = 64; // 64 bit frame. (2 slots)
	saiHandle.FrameInit.ActiveFrameLength = 32; // Frame synchronization active level length. (half the frame length)
	saiHandle.FrameInit.FSDefinition = SAI_FS_CHANNEL_IDENTIFICATION;
	saiHandle.FrameInit.FSPolarity = SAI_FS_ACTIVE_LOW;
	saiHandle.FrameInit.FSOffset = SAI_FS_BEFOREFIRSTBIT;
 
	// block slot parameters.
	saiHandle.SlotInit.FirstBitOffset = 0; // no offset in receive mode -> FBOFF <= (SLOTSZ - DS)
	saiHandle.SlotInit.SlotSize = SAI_SLOTSIZE_32B; // 32 bits per slot to contain the 32 data bits (24 data, 8 zeroed)
	saiHandle.SlotInit.SlotNumber = 2;
	saiHandle.SlotInit.SlotActive = SAI_SLOTACTIVE_ALL;
 
	/*
			https://www.keil.com/pack/doc/CMSIS/Driver/html/group__sai__interface__gr.html
	*/
	HAL_StatusTypeDef saiStatus = HAL_SAI_InitProtocol(&saiHandle,
		SAI_I2S_STANDARD, // runs the SAI_InitI2S() function.
		SAI_PROTOCOL_DATASIZE_24BIT,// 24 bits (24 bit is standard for I2S).
		2);			 // number of slots per frame - 1
 
	__HAL_SAI_ENABLE(&saiHandle); // without this line of code the first read takes 84us because it settings sai enabled.
 
	if (saiStatus != HAL_OK)
	{
		Serial2.println("SAI ERROR");
		while (1) {}
	}
 
 
	sampleTimer.setMode(1, TIMER_OUTPUT_COMPARE, NC); // remove this for new version of STM32Dino, required version 1.8.0.
	sampleTimer.setOverflow(16000, HERTZ_FORMAT);
	sampleTimer.detachInterrupt();
	sampleTimer.attachInterrupt(samplerCallback);
	sampleTimer.resume();
}
 
long elapsed = 0;
 
void samplerCallback()
{
 
	long stamp = micros();
 
	HAL_StatusTypeDef rxResponse;
 
	/*
	* Perform sampling
	*/
	rxResponse = HAL_SAI_Receive(&saiHandle, SAIDataBuffer, 2U, 10000);
 
	if (rxResponse != HAL_OK)
	{
		Serial2.println("Error in SAI");
		while (1) { }
	}
 
	elapsed = micros() - stamp;
}
 
void signalWatchdog()
{
	// do signal watchdog (placeholder)
}
 
void loop() {
	signalWatchdog();
	Serial2.println(elapsed);
}

 Here is an output log:

11:33:44.117 -> 4Starting
11:34:45.448 -> 0
11:34:45.448 -> 0
11:34:45.448 -> 0
11:34:45.448 -> 0
11:34:45.448 -> 0
11:34:45.448 -> 0
11:34:45.448 -> 0
11:34:45.448 -> 0
11:34:45.448 -> 0
11:34:45.448 -> 0
11:34:45.448 -> 0
11:34:45.448 -> 0
11:34:45.448 -> 0
11:34:45.448 -> 0
11:34:45.448 -> 0
11:34:45.448 -> 0
11:34:45.448 -> 0
11:34:45.448 -> 0
11:34:45.448 -> 0
11:34:45.448 -> 0
11:34:45.448 -> 0
11:34:45.448 -> 4
11:34:45.448 -> 11
11:34:45.448 -> 4
11:34:45.448 -> 5
11:34:45.448 -> 5
11:34:45.448 -> 4
11:34:45.448 -> 4
11:34:45.448 -> 4
11:34:45.448 -> 5
11:34:45.448 -> 10
11:34:45.448 -> 4             <------------ program stops here, notice the timstamps. it should continue forever

6 REPLIES 6

I don't understand what that output log is supposed to indicate.

Try to reduce the code to bare minimum, avoiding interrupts etc., receiving in a loop. Still no luck?

JW

RBamf.1
Associate III

The output log prints the amount of time the HAL_SAI_Receive() took in microseconds. It should keep on printing forever, but it stops almost instantly. (updated the post)

The output log prints the amount of time the HAL_SAI_Receive() took in microseconds. It should keep on printing forever, but it stops almost instantly. (updated the post)

TDK
Guru

The output log doesn't print "Error in SAI" either, so probably HAL_SAI_Receive isn't the problem. Debug the code and find out where it's stuck.

All of your lines have the exact same timestamp (11:34:45.448). Be aware there is a bandwidth limit to the amount of info you can push out of a UART channel.

If you feel a post has answered your question, please click "Accept as Solution".
RBamf.1
Associate III

If i run the program without the serial prints, the loop() function still is never called. It seems like the hardware timer callback wont "let" the loop() run.

My susipcion is that the hardware timer callback is taking up all of the CPUs time so it never executes the loop() function?

Try to reduce the code to bare minimum, avoiding interrupts etc., receiving in a loop. Still no luck?

JW