Skip to main content
Associate II
August 29, 2025
Question

STM32U585 TrustZone ADC DMA-buffer always 0

  • August 29, 2025
  • 2 replies
  • 484 views

Hi, I'm using 3 channels of ADC4 with GPDMA1 (channel 4) in secure world of a TrustZone-project and the DMA-buffer stays always 0. The same ADC/DMA-configuration with the same application code (all mnus the security aspects) are working fine without TrustZone on the same hardware. I set the DMA-channel and the ADC-channel to secure and privileged, also the SAU-configuration for these peripherals is secure, the DMA-interrupt (circular) is triggered and calling HAL_ADC_ConvCpltCallback but there's nothing inside the DMA-buffer (which is defined as volatile inside a secure and privileged SRAM-area). I've tried different ADC conversion rates, clock rates and clock sources, checked for errors (especially overruns) and secure faults (with GTZC), there's absolutely nothing. I guess it must have something to do with secure/privileged areas or peripherals but since all the parts are secure and privileged I don't know what it could be. I'd be thankful for any suggestions; here is my ADC DMA-initialization code:

void MX_ADC4_Init(void)
{

 /* USER CODE BEGIN ADC4_Init 0 */

 /* USER CODE END ADC4_Init 0 */

 ADC_ChannelConfTypeDef sConfig = {0};

 /* USER CODE BEGIN ADC4_Init 1 */

 /* USER CODE END ADC4_Init 1 */

 /** Common config
 */
 hadc4.Instance = ADC4;
 hadc4.Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV64;
 hadc4.Init.Resolution = ADC_RESOLUTION_12B;
 hadc4.Init.DataAlign = ADC_DATAALIGN_RIGHT;
 hadc4.Init.ScanConvMode = ADC4_SCAN_ENABLE;
 hadc4.Init.EOCSelection = ADC_EOC_SEQ_CONV;
 hadc4.Init.LowPowerAutoPowerOff = ADC_LOW_POWER_NONE;
 hadc4.Init.LowPowerAutoWait = DISABLE;
 hadc4.Init.ContinuousConvMode = ENABLE;
 hadc4.Init.NbrOfConversion = 3;
 hadc4.Init.ExternalTrigConv = ADC_SOFTWARE_START;
 hadc4.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
 hadc4.Init.DMAContinuousRequests = ENABLE;
 hadc4.Init.TriggerFrequencyMode = ADC_TRIGGER_FREQ_HIGH;
 hadc4.Init.Overrun = ADC_OVR_DATA_OVERWRITTEN;
 hadc4.Init.SamplingTimeCommon1 = ADC4_SAMPLETIME_7CYCLES_5;
 hadc4.Init.SamplingTimeCommon2 = ADC4_SAMPLETIME_1CYCLE_5;
 hadc4.Init.OversamplingMode = ENABLE;
 hadc4.Init.Oversampling.Ratio = ADC_OVERSAMPLING_RATIO_2;
 hadc4.Init.Oversampling.RightBitShift = ADC_RIGHTBITSHIFT_1;
 hadc4.Init.Oversampling.TriggeredMode = ADC_TRIGGEREDMODE_SINGLE_TRIGGER;
 if (HAL_ADC_Init(&hadc4) != HAL_OK)
 {
 Error_Handler();
 }

 /** Configure Regular Channel
 */
 sConfig.Channel = ADC_CHANNEL_9;
 sConfig.Rank = ADC4_REGULAR_RANK_1;
 sConfig.SamplingTime = ADC4_SAMPLINGTIME_COMMON_1;
 sConfig.OffsetNumber = ADC_OFFSET_NONE;
 sConfig.Offset = 0;
 if (HAL_ADC_ConfigChannel(&hadc4, &sConfig) != HAL_OK)
 {
 Error_Handler();
 }

 /** Configure Regular Channel
 */
 sConfig.Channel = ADC_CHANNEL_10;
 sConfig.Rank = ADC4_REGULAR_RANK_2;
 if (HAL_ADC_ConfigChannel(&hadc4, &sConfig) != HAL_OK)
 {
 Error_Handler();
 }

 /** Configure Regular Channel
 */
 sConfig.Channel = ADC_CHANNEL_11;
 sConfig.Rank = ADC4_REGULAR_RANK_3;
 if (HAL_ADC_ConfigChannel(&hadc4, &sConfig) != HAL_OK)
 {
 Error_Handler();
 }
 /* USER CODE BEGIN ADC4_Init 2 */

 /* USER CODE END ADC4_Init 2 */

}

void HAL_ADC_MspInit(ADC_HandleTypeDef* adcHandle)
{

 GPIO_InitTypeDef GPIO_InitStruct = {0};
 DMA_NodeConfTypeDef NodeConfig= {0};
 RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};
 if(adcHandle->Instance==ADC4)
 {
 /* USER CODE BEGIN ADC4_MspInit 0 */

 /* USER CODE END ADC4_MspInit 0 */

 /** Initializes the peripherals clock
 */
 PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_ADCDAC;
 PeriphClkInit.AdcDacClockSelection = RCC_ADCDACCLKSOURCE_HCLK;
 if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
 {
 Error_Handler();
 }

 /* ADC4 clock enable */
 __HAL_RCC_ADC4_CLK_ENABLE();

 __HAL_RCC_GPIOA_CLK_ENABLE();
 /**ADC4 GPIO Configuration
 PA4 ------> ADC4_IN9
 PA5 ------> ADC4_IN10
 PA6 ------> ADC4_IN11
 */
 GPIO_InitStruct.Pin = GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_6;
 GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
 GPIO_InitStruct.Pull = GPIO_NOPULL;
 HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

 /* ADC4 DMA Init */
 /* GPDMA1_REQUEST_ADC4 Init */
 NodeConfig.NodeType = DMA_GPDMA_LINEAR_NODE;
 NodeConfig.SrcSecure = DMA_CHANNEL_SRC_SEC;
 NodeConfig.DestSecure = DMA_CHANNEL_DEST_SEC;
 NodeConfig.Init.Request = GPDMA1_REQUEST_ADC4;
 NodeConfig.Init.BlkHWRequest = DMA_BREQ_SINGLE_BURST;
 NodeConfig.Init.Direction = DMA_PERIPH_TO_MEMORY;
 NodeConfig.Init.SrcInc = DMA_SINC_FIXED;
 NodeConfig.Init.DestInc = DMA_DINC_INCREMENTED;
 NodeConfig.Init.SrcDataWidth = DMA_SRC_DATAWIDTH_HALFWORD;
 NodeConfig.Init.DestDataWidth = DMA_DEST_DATAWIDTH_HALFWORD;
 NodeConfig.Init.SrcBurstLength = 1;
 NodeConfig.Init.DestBurstLength = 1;
 NodeConfig.Init.TransferAllocatedPort = DMA_SRC_ALLOCATED_PORT0|DMA_DEST_ALLOCATED_PORT0;
 NodeConfig.Init.TransferEventMode = DMA_TCEM_BLOCK_TRANSFER;
 NodeConfig.Init.Mode = DMA_NORMAL;
 NodeConfig.TriggerConfig.TriggerPolarity = DMA_TRIG_POLARITY_MASKED;
 NodeConfig.DataHandlingConfig.DataExchange = DMA_EXCHANGE_NONE;
 NodeConfig.DataHandlingConfig.DataAlignment = DMA_DATA_RIGHTALIGN_ZEROPADDED;
 NodeConfig.SrcSecure = DMA_CHANNEL_SRC_SEC;
 NodeConfig.DestSecure = DMA_CHANNEL_DEST_SEC;
 if (HAL_DMAEx_List_BuildNode(&NodeConfig, &Node_GPDMA1_Channel4) != HAL_OK)
 {
 Error_Handler();
 }

 if (HAL_DMAEx_List_InsertNode(&List_GPDMA1_Channel4, NULL, &Node_GPDMA1_Channel4) != HAL_OK)
 {
 Error_Handler();
 }

 if (HAL_DMAEx_List_SetCircularMode(&List_GPDMA1_Channel4) != HAL_OK)
 {
 Error_Handler();
 }

 handle_GPDMA1_Channel4.Instance = GPDMA1_Channel4;
 handle_GPDMA1_Channel4.InitLinkedList.Priority = DMA_LOW_PRIORITY_LOW_WEIGHT;
 handle_GPDMA1_Channel4.InitLinkedList.LinkStepMode = DMA_LSM_FULL_EXECUTION;
 handle_GPDMA1_Channel4.InitLinkedList.LinkAllocatedPort = DMA_LINK_ALLOCATED_PORT0;
 handle_GPDMA1_Channel4.InitLinkedList.TransferEventMode = DMA_TCEM_BLOCK_TRANSFER;
 handle_GPDMA1_Channel4.InitLinkedList.LinkedListMode = DMA_LINKEDLIST_CIRCULAR;
 if (HAL_DMAEx_List_Init(&handle_GPDMA1_Channel4) != HAL_OK)
 {
 Error_Handler();
 }

 if (HAL_DMAEx_List_LinkQ(&handle_GPDMA1_Channel4, &List_GPDMA1_Channel4) != HAL_OK)
 {
 Error_Handler();
 }

 __HAL_LINKDMA(adcHandle, DMA_Handle, handle_GPDMA1_Channel4);

 if (HAL_DMA_ConfigChannelAttributes(&handle_GPDMA1_Channel4, DMA_CHANNEL_PRIV|DMA_CHANNEL_SEC) != HAL_OK)
 {
 Error_Handler();
 }

 /* ADC4 interrupt Init */
 HAL_NVIC_SetPriority(ADC4_IRQn, 5, 0);
 HAL_NVIC_EnableIRQ(ADC4_IRQn);
 /* USER CODE BEGIN ADC4_MspInit 1 */

 /* USER CODE END ADC4_MspInit 1 */
 }
}
void MX_GPDMA1_Init(void)
{
 /* Peripheral clock enable */
 __HAL_RCC_GPDMA1_CLK_ENABLE();

 /* GPDMA1 interrupt Init */
 HAL_NVIC_SetPriority(GPDMA1_Channel4_IRQn, 4, 0);
 HAL_NVIC_EnableIRQ(GPDMA1_Channel4_IRQn);
}

2 replies

Jocelyn RICARD
ST Employee
October 8, 2025

Hello @AAArdvark ,

the GPDMA is unsecure by default.

You can see GPDMA_SECCFGR that defaults 0, meaning all channels are unsecure.

Same for GPDMA_PRIVCFGR that default value is 0 meaning all channels are unprivileged.

In your code I can see that channels are set secure but privileged is not set. This is probably the reason it fails

Best regards

Jocelyn

AAArdvarkAuthor
Associate II
October 9, 2025

Hello Jocelyn,

Thank you for your answer; in the code I posted there are these lines:

 if (HAL_DMA_ConfigChannelAttributes(&handle_GPDMA1_Channel4, DMA_CHANNEL_PRIV|DMA_CHANNEL_SEC) != HAL_OK)
 {
 Error_Handler();
 }

I guess that should set the DMA-channel to secure as well as privileged or am I overseeing something?

Best regards 

Jocelyn RICARD
ST Employee
October 9, 2025

Hello @AAArdvark ,

yes my bad, I missed that.

You say in your post that you set everything secure. So, you confirm that ADC and SRAM are both secure/privilege and GPIOs are also secure ?

I guess you are also using secure alias for buffer address.

Last point, did you enable cache ? But as you say it is working in non secure, this is unlikely the issue.

I would need to reproduce this issue to try finding what happens.

If you can share a code, this would help

Best regards

Jocelyn