2021-12-16 01:25 PM
My program keeps crashing in my uiTask loop, and I figured out the common denominator is a call to portYIELD_WITHIN_API().
Here's the relevant code in main. Obviously there are a lot of calls to classes / structs here that aren't shown, but I've sifted through them enough that I don't think they are the issue.
osThreadId_t processAudioBluHandle;
const osThreadAttr_t processAudioBlu_attributes = {
.name = "processAudioBlu",
.stack_size = 512,
.priority = (osPriority_t) osPriorityRealtime
};
/* Definitions for uiTask */
osThreadId_t uiTaskHandle;
const osThreadAttr_t uiTask_attributes = {
.name = "uiTask",
.stack_size = 2048,
.priority = (osPriority_t) osPriorityNormal
};
osEventFlagsId_t potBufferReadyFlag;
osEventFlagsId_t audioBufferReadyFlag;
#define NUM_POTS 6
#define BUFFER_LEN 512
#define HALF_BUFFER_LEN BUFFER_LEN>>1
#define AUDIO_FLOAT_RES 4096.0f
static uint16_t adcBuffer[BUFFER_LEN] = {0};
static uint16_t dacBuffer[BUFFER_LEN] = {0};
static volatile uint16_t potBuffer[NUM_POTS] = {0};
int main(void)
{
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* Configure the system clock */
SystemClock_Config();
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_DMA_Init();
MX_ADC3_Init();
MX_DAC_Init();
MX_TIM6_Init();
MX_ADC2_Init();
MX_FMC_Init();
MX_TIM7_Init();
MX_TIM2_Init();
/* USER CODE BEGIN 2 */
HAL_TIM_Base_Start_IT(&htim2);
HAL_TIM_Base_Start_IT(&htim6);
HAL_TIM_Base_Start_IT(&htim7);
HAL_ADC_Start_DMA(&hadc2, (uint32_t*)&potBuffer, NUM_POTS);
HAL_ADC_Start_DMA(&hadc3, (uint32_t*)&adcBuffer, BUFFER_LEN);
HAL_DAC_Start_DMA(&hdac, DAC_CHANNEL_1, (uint32_t*)&dacBuffer, BUFFER_LEN, DAC_ALIGN_12B_R);
/* USER CODE END 2 */
/* Init scheduler */
osKernelInitialize();
potBufferReadyFlag = osEventFlagsNew(NULL);
audioBufferReadyFlag = osEventFlagsNew(NULL);
/* creation of processAudioBlu */
processAudioBluHandle = osThreadNew(StartProcessAudioBufferTask, NULL, &processAudioBlu_attributes);
/* creation of uiTask */
uiTaskHandle = osThreadNew(StartUITask, NULL, &uiTask_attributes);
/* Start scheduler */
osKernelStart();
while (1)
{
}
}
extern "C" {
void TIM2_IRQHandler() {
HAL_TIM_IRQHandler(&htim2);
}
void TIM6_IRQHandler() {
HAL_TIM_IRQHandler(&htim6);
}
#define ADC_HALF_FLAG 0x00000001U
#define ADC_FULL_FLAG 0x00000002U
#define POT_FLAG 0x00000004U
#define ANIMATION_FLAG 0x00000008U
void HAL_ADC_ConvHalfCpltCallback(ADC_HandleTypeDef* hadc) {
if (hadc->Instance == ADC3) { // Guitar
osEventFlagsSet(audioBufferReadyFlag, ADC_HALF_FLAG);
}
}
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc) {
if (hadc->Instance == ADC3) { // Guitar
osEventFlagsSet(audioBufferReadyFlag, ADC_FULL_FLAG);
} else if (hadc->Instance == ADC2) {
osEventFlagsSet(potBufferReadyFlag, POT_FLAG);
}
}
}
void StartProcessAudioBufferTask(void *argument) // runs fine
{
/* USER CODE BEGIN 5 */
uint32_t flag;
magna::Effect<uint16_t> * currentEffect;
currentEffect = new magna::VolumeDummyEffect<uint16_t>();
/* Infinite loop */
for(;;)
{
/* briefly check for potentiometer updates */
flag = osEventFlagsWait(potBufferReadyFlag, POT_FLAG, osFlagsWaitAny, 0U);
if (flag == POT_FLAG) {
currentEffect->updateParameterValue(0, potBuffer[0]);
}
flag = osEventFlagsWait(audioBufferReadyFlag, ADC_HALF_FLAG | ADC_FULL_FLAG, osFlagsWaitAny, osWaitForever);
switch(flag) {
case ADC_HALF_FLAG:
currentEffect->processBuffer(&adcBuffer[0], &dacBuffer[HALF_BUFFER_LEN], HALF_BUFFER_LEN);
break;
case ADC_FULL_FLAG:
currentEffect->processBuffer(&adcBuffer[HALF_BUFFER_LEN], &dacBuffer[0], HALF_BUFFER_LEN);
break;
default:
break;
}
}
/* USER CODE END 5 */
delete currentEffect;
osThreadTerminate(NULL);
}
void StartUITask(void *argument)
{
/* USER CODE BEGIN StartUITask */
uint32_t flag;
magna::ILI9341InitStruct lcdInitStruct = {
.CSPort = GPIOC,
.NWEPort = GPIOD,
.RSPort = GPIOD,
.ResetPort = GPIOD,
.CSPin = GPIO_PIN_7,
.NWEPin = GPIO_PIN_5,
.RSPin = GPIO_PIN_13,
.ResetPin = GPIO_PIN_2,
.MemSwap = false
};
magna::ILI9341 lcd(lcdInitStruct);
magna::UIDialStyleSheet dialStyleSheet(2, ILI9341_COLOR_WHITE, ILI9341_COLOR_WHITE, ILI9341_COLOR_RED, ILI9341_COLOR_RED, ILI9341_COLOR_RED, ILI9341_COLOR_RED);
magna::UITextBoxStyleSheet textBoxStyleSheet(ILI9341_COLOR_WHITE, ILI9341_COLOR_BLACK, ILI9341_COLOR_WHITE, ILI9341_COLOR_BLACK);
magna::UITextButtonStyleSheet textButtonStyleSheet(ILI9341_COLOR_WHITE, ILI9341_COLOR_BLACK, ILI9341_COLOR_WHITE, ILI9341_COLOR_BLACK);
magna::EffectsUIStyleSheet volumeUIStyleSheet(dialStyleSheet, textBoxStyleSheet, textButtonStyleSheet);
volumeUIStyleSheet.backgroundColor = ILI9341_COLOR_BLACK;
magna::EffectUserInterface volumeUI(volumeUIStyleSheet, lcd, "VOLUME");
//volumeUI.addDial("Volume", 0.0f, 1.0f);
magna::UIDial dial(volumeUI, dialStyleSheet, "Volume", 0.0f, 1.0f);
dial.updatePosition(0, 160, 240, 160);
volumeUI.drawInitialScreen();
dial.draw(lcd);
/* Infinite loop */
for(;;)
{
flag = osEventFlagsWait(potBufferReadyFlag, POT_FLAG, osFlagsWaitAny, 0U); // crashes if ticks > 0
if (flag == POT_FLAG) {
//volumeUI.setDial(0, potBuffer[0]/4096.0f);
float bufferValue = potBuffer[0]/4096.0f;
if (bufferValue != dial.getValue()) {
dial.setValue(bufferValue);
}
}
flag = osThreadFlagsWait(ANIMATION_FLAG, osFlagsWaitAny, osWaitForever);
if (flag == ANIMATION_FLAG) {
volumeUI.refreshScreen();
}
osDelay(1); // crashes here
}
osThreadTerminate(NULL);
/* USER CODE END StartUITask */
}
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if (htim->Instance == TIM10) {
HAL_IncTick();
}
if (htim->Instance == TIM7) { // animation timer
osThreadFlagsSet(uiTaskHandle, (uint32_t)ANIMATION_FLAG);
}
}
I originally had
flag = osEventFlagsWait(potBufferReadyFlag, POT_FLAG, osFlagsWaitAny, 0U);
set to 10U instead of 0U, and that triggered a hardfault inside xEventGroupWaitBits():
if( xTicksToWait != ( TickType_t ) 0 )
{
if( xAlreadyYielded == pdFALSE )
{
portYIELD_WITHIN_API();
Then the next hardfault happens at osDelay(1) in the loop, in the call to vTaskDelay():
/* Force a reschedule if xTaskResumeAll has not already done so, we may
have put ourselves to sleep. */
if( xAlreadyYielded == pdFALSE )
{
portYIELD_WITHIN_API();
}
osDelay() gets called in the constructor for my LCD class (before the task loop starts) and does not crash.
Someone posted a similar issue here: https://www.freertos.org/FreeRTOS_Support_Forum_Archive/August_2016/freertos_Usage_Fault_hard_fault_within_portYIELD_WITHIN_API_0efed9eej.html
and it seemed like the problem was interrupt configurations, but I checked FreeRTOSConfig.h and everything looks right to me. I also have a pic of my NVIC priorities in CubeMX:
#FreeRTOS #HardFault
2021-12-16 01:29 PM
So I just un-commented all the calls to objects in the task, and now the program is no longer crashing. So maybe it is in fact a class issue. I guess I'll keep trying things.