cancel
Showing results for 
Search instead for 
Did you mean: 

FreeRTOS portYIELD_WITHIN_API() causes a hardfault, interrupt priorities look correct to me

NNagy.1
Senior

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:

0693W00000Houx7QAB.png#FreeRTOS​ #HardFault​

1 REPLY 1
NNagy.1
Senior

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.