cancel
Showing results for 
Search instead for 
Did you mean: 

Problem with CPU freezing/infinite loop when using HAL_SAI_Receive_IT()

RBamf.1
Associate III

Hi, i am trying to setup the SAI device in an interrupt mode but when I run the program, it gets stuck after the call to HAL_SAI_Receive_IT() completed.

When debugging with OpenOCD, after the line 280 has executed the program hangs.

Please help!

Here's the program:

#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 };
 
 
void HAL_SAI_TxHalfCpltCallback(SAI_HandleTypeDef* hsai)
 
{
 
   //Serial2.println("Received HAL_SAI_TxHalfCpltCallback");
 
}
 
 
void HAL_SAI_TxCpltCallback(SAI_HandleTypeDef* hsai)
 
{
 
   //Serial2.println("Received HAL_SAI_TxCpltCallback");
 
}
 
 
void HAL_SAI_RxHalfCpltCallback(SAI_HandleTypeDef* hsai)
 
{
 
   //Serial2.println("Received HAL_SAI_RxHalfCpltCallback");
 
}
 
 
void HAL_SAI_RxCpltCallback(SAI_HandleTypeDef* hsai)
 
{
 
   //Serial2.println("Received HAL_SAI_RxCpltCallback");
 
}
 
 
void HAL_SAI_ErrorCallback(SAI_HandleTypeDef* hsai)
 
{
 
   //Serial2.println("Received HAL_SAI_ErrorCallback");
 
}
 
 
void SAI1_IRQHandler(void)
 
{
 
   Serial2.println("Callback");
 
   //HAL_SAI_IRQHandler(&saiHandle);
 
}
 
 
// the setup function runs once when you press reset or power the board
 
void setup()
 
{
 
   delay(5000);
 
 
   Serial2.begin(115200);
 
   Serial2.println("Starting");
 
 
   __HAL_RCC_GPIOB_CLK_ENABLE();
 
   __HAL_RCC_SAI1_CLK_ENABLE();
 
 
   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_NVIC_SetPriority(SAI1_IRQn, 0, 0);
 
   HAL_NVIC_EnableIRQ(SAI1_IRQn);
 
 
   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_16K;
 
   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.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;
 
   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;
 
 
   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);
 
 
   if (saiStatus != HAL_OK)
 
   {
 
      Serial2.println("SAI ERROR");
 
      while (1) {}
 
   }
 
}
 
 
 
int32_t GetSample()
 
{
 
   uint8_t a1 = SAIDataBuffer[0];
 
   uint8_t b1 = SAIDataBuffer[1];
 
   uint8_t c1 = SAIDataBuffer[2];
 
   uint8_t d1 = SAIDataBuffer[3];
 
 
   uint8_t a2 = SAIDataBuffer[4];
 
   uint8_t b2 = SAIDataBuffer[5];
 
   uint8_t c2 = SAIDataBuffer[6];
 
   uint8_t d2 = SAIDataBuffer[7];
 
 
   // value as signed 24 bit integer
 
   int32_t slot24sb = 0;
 
   slot24sb = slot24sb | (a1 << 8);
 
   slot24sb = slot24sb | (b1 << 16);
 
   slot24sb = slot24sb | (c1 << 24);
 
   slot24sb = slot24sb >> 8;
 
 
   return slot24sb;
 
}
 
 
// the loop function runs over and over again until power down or reset
 
void loop()
 
{
 
   HAL_StatusTypeDef rxResponse;
 
 
   rxResponse = HAL_SAI_Receive_IT(&saiHandle, SAIDataBuffer, 2U);
 
 
   int sample = GetSample();
 
 
   if (rxResponse != HAL_OK)
 
   {
 
      Serial2.println("Error in SAI");
 
      while (1) {}
 
   }
 
   else
 
   {
 
      Serial2.println(sample);
 
   }
 
}

Output from OpenOCD when i break the program with the debugger:

openocd: Open On-Chip Debugger 0.10.0+dev-01058-g853a05287 (2020-02-13-16:41)
openocd: Licensed under GNU GPL v2
openocd: For bug reports, read
openocd: 	http://openocd.org/doc/doxygen/bugs.html
openocd: debug_level: 2
openocd: 
=thread-group-added,id="i1"
GNU gdb (xPack GNU Arm Embedded GCC, 32-bit) 8.3.0.20190709-git
Copyright (C) 2019 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "--host=i686-w64-mingw32 --target=arm-none-eabi".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
    <http://www.gnu.org/software/gdb/documentation/>.
 
For help, type "help".
Type "apropos word" to search for commands related to "word"...
=cmd-param-changed,param="pagination",value="off"
0x0800578e in delay (ms=5000) at C:\Users\Richa\AppData\Local\arduino15\packages\STM32\hardware\stm32\1.9.0\cores\arduino\wiring_time.c:43
43	    } while (getCurrentMillis() - start < ms);
Note: automatically using hardware breakpoints for read-only addresses.
 
Program received signal SIGINT, Interrupt.
WWDG_IRQHandler () at C:\Users\Richa\AppData\Local\arduino15\packages\STM32\hardware\stm32\1.9.0\system/Drivers/CMSIS/Device/ST/STM32L4xx/Source/Templates/gcc\startup_stm32l452xx.s:116
116		b	Infinite_Loop

Update:

if i change the callback declarations to be "extern C" then the following error occurs:

SAI_TEST_INTERRUPTS.ino: 67:7: error: conflicting declaration of 'void SAI1_IRQHandler()' with 'C' linkage

  67 | void SAI1_IRQHandler(void)

  |      ^~~~~~~~~~~~~~~

1 REPLY 1
RBamf.1
Associate III

Adding the __weak attribute to SAI1_IRQHandler() fixed it.