cancel
Showing results for 
Search instead for 
Did you mean: 

Puzzling operation / error with DAC and DMA on STM32F334K8 and STM32F334C8

declareupdate
Associate III

I'm running into something very odd and wondering if anyone has any insight!

I'm developing an audio project, and have implemented double buffering using HAL_DAC_ConvCpltCallbackCh1 and HAL_DAC_ConvHalfCpltCallbackCh1. I started developing this on an older project with a 32 pin STM32F334K8T6. I got it all working well. Using this sort of code for configuration:

DAC_HandleTypeDef hdac1;
DMA_HandleTypeDef hdma_dac1_ch1;
 
void MX_DAC1_Init(void)
{
  DAC_ChannelConfTypeDef sConfig = {0};
 
  /** DAC Initialization
  */
  hdac1.Instance = DAC1;
  if (HAL_DAC_Init(&hdac1) != HAL_OK)
  {
    Error_Handler();
  }
  /** DAC channel OUT1 config
  */
  sConfig.DAC_Trigger = DAC_TRIGGER_T2_TRGO;
  sConfig.DAC_OutputBuffer = DAC_OUTPUTBUFFER_ENABLE;
  if (HAL_DAC_ConfigChannel(&hdac1, &sConfig, DAC_CHANNEL_1) != HAL_OK)
  {
    Error_Handler();
  }
 
}
 
void MX_DMA_Init(void)
{
 
  /* DMA controller clock enable */
  __HAL_RCC_DMA1_CLK_ENABLE();
 
  /* DMA interrupt init */
  /* DMA1_Channel1_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(DMA1_Channel1_IRQn, 0, 0);
  HAL_NVIC_EnableIRQ(DMA1_Channel1_IRQn);
  /* DMA1_Channel3_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(DMA1_Channel3_IRQn, 1, 0);
  HAL_NVIC_EnableIRQ(DMA1_Channel3_IRQn);
 
}
 
 
int main(void) {
	/* USER CODE BEGIN 1 */
 
	/* USER CODE END 1 */
 
	/* MCU Configuration--------------------------------------------------------*/
 
	/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
	HAL_Init();
 
	/* USER CODE BEGIN Init */
 
	/* USER CODE END Init */
 
	/* Configure the system clock */
	SystemClock_Config();
 
	/* USER CODE BEGIN SysInit */
 
	/* USER CODE END SysInit */
 
	/* Initialize all configured peripherals */
	MX_GPIO_Init();
	MX_DMA_Init();
	MX_ADC1_Init();
	MX_DAC1_Init();
	MX_TIM2_Init();
	MX_TIM3_Init();
	/* USER CODE BEGIN 2 */
	HAL_DAC_Start_DMA(&hdac1, DAC_CHANNEL_1, (uint32_t*) out_buffer, BUFFER_LENGTH, DAC_ALIGN_12B_R);
	HAL_TIM_Base_Start(&htim2);
	HAL_TIM_Base_Start_IT(&htim3);
	ADC_start();
 
	/* USER CODE END 2 */
 
	/* Infinite loop */
	/* USER CODE BEGIN WHILE */
	setup();
	while (1) {
		loop();
		/* USER CODE END WHILE */
 
		/* USER CODE BEGIN 3 */
	}
	/* USER CODE END 3 */
}
 
/**
 * @brief System Clock Configuration
 * @retval None
 */
void SystemClock_Config(void) {
	RCC_OscInitTypeDef RCC_OscInitStruct = { 0 };
	RCC_ClkInitTypeDef RCC_ClkInitStruct = { 0 };
	RCC_PeriphCLKInitTypeDef PeriphClkInit = { 0 };
 
	/** Initializes the RCC Oscillators according to the specified parameters
	 * in the RCC_OscInitTypeDef structure.
	 */
	RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
	RCC_OscInitStruct.HSIState = RCC_HSI_ON;
	RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
	RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
	RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;
	RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL16;
	if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) {
		Error_Handler();
	}
	/** Initializes the CPU, AHB and APB buses clocks
	 */
	RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2;
	RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
	RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
	RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
	RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
 
	if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK) {
		Error_Handler();
	}
	PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_TIM1 | RCC_PERIPHCLK_ADC12;
	PeriphClkInit.Adc12ClockSelection = RCC_ADC12PLLCLK_DIV1;
	PeriphClkInit.Tim1ClockSelection = RCC_TIM1CLK_HCLK;
	if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK) {
		Error_Handler();
	}
}
 
/* USER CODE BEGIN 4 */
 
//fill the first half of the buffer while dma transfers the second half
__attribute__((section(".ccmram")))
void HAL_DAC_ConvHalfCpltCallbackCh1(DAC_HandleTypeDef *hdac) {
	GPIOA->BSRR = GPIO_PIN_7;
	for (int i = 0; i < (BUFFER_LENGTH / 2); i++) {
		output_mix = 0.0f;
		for (int j = 0; j < NUM_VOICES; j++) {
			voices[j].run();
			output_mix += voices[j].OP1.output;
		}
		out_buffer[i] = (uint16_t) (output_mix + 2047.0f);
	}
	GPIOA->BRR = GPIO_PIN_7;
}
 
//fill the second half of the buffer while dma transfers the first half
__attribute__((section(".ccmram")))
void HAL_DAC_ConvCpltCallbackCh1(DAC_HandleTypeDef *hdac) {
	GPIOA->BSRR = GPIO_PIN_7;
	for (int i = (BUFFER_LENGTH / 2); i < BUFFER_LENGTH; i++) {
		output_mix = 0.0f;
		for (int j = 0; j < NUM_VOICES; j++) {
			voices[j].run();
			output_mix += voices[j].OP1.output;
		}
		out_buffer[i] = (uint16_t) (output_mix + 2047.0f);
	}
	GPIOA->BRR = GPIO_PIN_7;
}

I have TIM2 triggering the DMA transfer from out_buffer to DAC1, and TIM3 triggering DMA transfer from ADC1 to adc_data (not shown here, happy to if it helps but I don't believe these issues are related)

The issue started when I began porting this code over to the STM32F334C8T6. I got everything working great until I started on the DAC and DMA. The initial problem was that HAL_DAC_ConvCpltCallbackCh1 was never called. HalfCplt was called, but it was executing slowly, and completely blocking all other code. Here is a scope shot of PA7 (you can see it set and reset in the callbacks in the code snippet)

0693W000008wSD1QAM.jpg 

I tried checking the flags in the DMA1_Channel3 IRQ handler and indeed, I always had TC, HT, and GL flags set for both DMA1_Channel3 and DMA1_Channel1 (set up for the ADC transfer). I'm not sure what to make of this.

Then, sort of as a fluke, I tried uploading the working code from my STM32F334K8 project and the audio started working! Both ConvCplt and HalfCplt get called, at the right rate. But, some mysterious GPIO related bugs appeared too, and I noticed eventually that there was some gnarly noise in the DAC output signal, correlated with the DMA activity...

0693W000008wSCrQAM.jpg 

I went on to copy every .c, .cpp, and .h file between the two projects to make them identical, found that they compile to two different sizes (~17k for the K6, ~19k for the C8) and still exhibit the differences in behavior. Unfortunately, neither is currently usable, as I either have inconsistent GPIO behavior, or only half of my DMA callbacks happening. I know there are a ton of question marks here for someone reading this post, but does anyone have any insight at all into what might be happening? I was not able to find any reason for the two file sizes to be different, nor actually any setting or code that would distinguish the two targets!

Any help is appreciated, I'm happy to post lots more code in the comments if it helps :)

0 REPLIES 0