HAL_SAI_Receive() causes hardware timer callback to never exit?

Post here all questions related to STM32 core if you can't find a relevant section!
Post Reply
Bambo
Posts: 75
Joined: Wed Jan 15, 2020 8:36 pm

HAL_SAI_Receive() causes hardware timer callback to never exit?

Post by Bambo »

Hi,

i'm trying to sample a microphone inside a hardware timer callback, but the program gets stuck when it runs.

CPU: STM32L452RE

Here is the program:

Code: Select all

#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);
}
The output when i run this program is:
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 <------------ The printing stops here, but the program carries on running
For some reason it stops printing the elapsed time after a coupe of micros(). I'm not sure why it stops?

More links: https://community.st.com/s/question/0D5 ... n-isr-loop

Thanks!
Last edited by Bambo on Thu May 20, 2021 3:47 pm, edited 1 time in total.
mlundin
Posts: 94
Joined: Wed Nov 04, 2020 1:20 pm
Answers: 6
Location: Sweden

Re: HAL_SAI_Receive() causes hardware timer callback to never exit?

Post by mlundin »

Does the sound work ?

The time display discrepancies are most likely because the SAI_Receive inside the timer irq blocks the SysTick interrupts and therefore makes the micros() nonfunctional.

Also note that variables used to communicate between IRQ handlers and loop level should be marked as volatile (elapsed)
Bambo
Posts: 75
Joined: Wed Jan 15, 2020 8:36 pm

Re: HAL_SAI_Receive() causes hardware timer callback to never exit?

Post by Bambo »

The sound works yeah, but the program halts because the watchdog serial is never signaled.

Code: Select all

void loop() {
	signalWatchdog(); // this is never called
	Serial2.println(elapsed);
}
mlundin
Posts: 94
Joined: Wed Nov 04, 2020 1:20 pm
Answers: 6
Location: Sweden

Re: HAL_SAI_Receive() causes hardware timer callback to never exit?

Post by mlundin »

Program seems to be overflowing serial buffers, looking at the timestamps,

the Serial2.println(elapsed) seems to get called ok,
and so should signalWatchdog(), but that function is empty so how do you know its not called ?
Bambo
Posts: 75
Joined: Wed Jan 15, 2020 8:36 pm

Re: HAL_SAI_Receive() causes hardware timer callback to never exit?

Post by Bambo »

mlundin wrote: Thu May 20, 2021 3:36 pm Program seems to be overflowing serial buffers, looking at the timestamps,

the Serial2.println(elapsed) seems to get called ok,
and so should signalWatchdog(), but that function is empty so how do you know its not called ?
The serial2.println() is called fine for the first second or so, but the loop() is stopped being called afterwards.

I have editted the log in the post, it shows that the printing stops but the program carries on running. I think the ISR wont "let" the loop() execute somehow.

Here's a timeline:

11:33:44.117 to 11:34:45.448 the program prints values.
11:34:45.448+ the program is still running but no prints are happening.

I have a much larger program running the same scenario, the computer is reset by the watchdog because its loop() is never called.
Post Reply

Return to “General discussion”