cancel
Showing results for 
Search instead for 
Did you mean: 

Problem on SCB_InvalidateDCache_by_Addr

SEng.1
Associate II

First time try ADC Dual Interleaved on STM32H750VB.

The problem is when I try to split the 32bit result from DMABuff into 16bit master and slave, some of the reading is zero and it's random. Can anyone show me anything wrong on my code?

If disable DCache and allocate DMABuff on RAM_D1.

Without calling the SCB_InvalidateDCache_by_Addr, then there is no issue.

0693W00000D2FMwQAN.jpg0693W00000D2FNLQA3.jpg0693W00000D2FNuQAN.jpgBelow is my code:

__IO uint32_t DMABuf[BuffSize];
__IO uint16_t Master[BuffSize];
__IO uint16_t Slave[BuffSize];
 
int main(void)
{
  /* USER CODE BEGIN 1 */
 
  /* USER CODE END 1 */
 
  /* Enable I-Cache---------------------------------------------------------*/
  SCB_EnableICache();
 
  /* Enable D-Cache---------------------------------------------------------*/
  SCB_EnableDCache();
 
  /* 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();
 
/* Configure the peripherals common clocks */
  PeriphCommonClock_Config();
 
  /* USER CODE BEGIN SysInit */
 
  /* USER CODE END SysInit */
 
  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_DMA_Init();
  MX_ADC1_Init();
  MX_ADC2_Init();
  /* USER CODE BEGIN 2 */
  HAL_ADCEx_Calibration_Start(&hadc1, ADC_CALIB_OFFSET, ADC_SINGLE_ENDED);
  HAL_ADCEx_Calibration_Start(&hadc2, ADC_CALIB_OFFSET, ADC_SINGLE_ENDED);
  HAL_ADC_Start(&hadc2);
  HAL_ADCEx_MultiModeStart_DMA(&hadc1, (uint32_t *)DMABuf, BuffSize);
 
  /* USER CODE END 2 */
 
  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */
 
    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}
 
static void MX_ADC1_Init(void)
{
 
  /* USER CODE BEGIN ADC1_Init 0 */
 
  /* USER CODE END ADC1_Init 0 */
 
  ADC_MultiModeTypeDef multimode = {0};
  ADC_ChannelConfTypeDef sConfig = {0};
 
  /* USER CODE BEGIN ADC1_Init 1 */
 
  /* USER CODE END ADC1_Init 1 */
  /** Common config
  */
  hadc1.Instance = ADC1;
  hadc1.Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV1;
  hadc1.Init.Resolution = ADC_RESOLUTION_16B;
  hadc1.Init.ScanConvMode = ADC_SCAN_DISABLE;
  hadc1.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
  hadc1.Init.LowPowerAutoWait = DISABLE;
  hadc1.Init.ContinuousConvMode = ENABLE;
  hadc1.Init.NbrOfConversion = 1;
  hadc1.Init.DiscontinuousConvMode = DISABLE;
  hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
  hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
  hadc1.Init.ConversionDataManagement = ADC_CONVERSIONDATA_DMA_CIRCULAR;
  hadc1.Init.Overrun = ADC_OVR_DATA_OVERWRITTEN;
  hadc1.Init.LeftBitShift = ADC_LEFTBITSHIFT_NONE;
  hadc1.Init.OversamplingMode = DISABLE;
  if (HAL_ADC_Init(&hadc1) != HAL_OK)
  {
    Error_Handler();
  }
  /** Configure the ADC multi-mode
  */
  multimode.Mode = ADC_DUALMODE_INTERL;
  multimode.DualModeData = ADC_DUALMODEDATAFORMAT_32_10_BITS;
  multimode.TwoSamplingDelay = ADC_TWOSAMPLINGDELAY_1CYCLE;
  if (HAL_ADCEx_MultiModeConfigChannel(&hadc1, &multimode) != HAL_OK)
  {
    Error_Handler();
  }
  /** Configure Regular Channel
  */
  sConfig.Channel = ADC_CHANNEL_10;
  sConfig.Rank = ADC_REGULAR_RANK_1;
  sConfig.SamplingTime = ADC_SAMPLETIME_1CYCLE_5;
  sConfig.SingleDiff = ADC_SINGLE_ENDED;
  sConfig.OffsetNumber = ADC_OFFSET_NONE;
  sConfig.Offset = 0;
  sConfig.OffsetSignedSaturation = DISABLE;
  if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN ADC1_Init 2 */
 
  /* USER CODE END ADC1_Init 2 */
 
}
 
static void MX_ADC2_Init(void)
{
 
  /* USER CODE BEGIN ADC2_Init 0 */
 
  /* USER CODE END ADC2_Init 0 */
 
  ADC_ChannelConfTypeDef sConfig = {0};
 
  /* USER CODE BEGIN ADC2_Init 1 */
 
  /* USER CODE END ADC2_Init 1 */
  /** Common config
  */
  hadc2.Instance = ADC2;
  hadc2.Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV1;
  hadc2.Init.Resolution = ADC_RESOLUTION_16B;
  hadc2.Init.ScanConvMode = ADC_SCAN_DISABLE;
  hadc2.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
  hadc2.Init.LowPowerAutoWait = DISABLE;
  hadc2.Init.ContinuousConvMode = ENABLE;
  hadc2.Init.NbrOfConversion = 1;
  hadc2.Init.DiscontinuousConvMode = DISABLE;
  hadc2.Init.ConversionDataManagement = ADC_CONVERSIONDATA_DR;
  hadc2.Init.Overrun = ADC_OVR_DATA_PRESERVED;
  hadc2.Init.LeftBitShift = ADC_LEFTBITSHIFT_NONE;
  hadc2.Init.OversamplingMode = DISABLE;
  if (HAL_ADC_Init(&hadc2) != HAL_OK)
  {
    Error_Handler();
  }
  /** Configure Regular Channel
  */
  sConfig.Channel = ADC_CHANNEL_10;
  sConfig.Rank = ADC_REGULAR_RANK_1;
  sConfig.SamplingTime = ADC_SAMPLETIME_1CYCLE_5;
  sConfig.SingleDiff = ADC_SINGLE_ENDED;
  sConfig.OffsetNumber = ADC_OFFSET_NONE;
  sConfig.Offset = 0;
  sConfig.OffsetSignedSaturation = DISABLE;
  if (HAL_ADC_ConfigChannel(&hadc2, &sConfig) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN ADC2_Init 2 */
 
  /* USER CODE END ADC2_Init 2 */
 
}
 
static void MX_DMA_Init(void)
{
 
  /* DMA controller clock enable */
  __HAL_RCC_DMA1_CLK_ENABLE();
 
  /* DMA interrupt init */
  /* DMA1_Stream0_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(DMA1_Stream0_IRQn, 0, 0);
  HAL_NVIC_EnableIRQ(DMA1_Stream0_IRQn);
 
}
 
void HAL_ADC_ConvHalfCpltCallback(ADC_HandleTypeDef* hadc)
{
	SCB_InvalidateDCache_by_Addr((uint32_t*) &DMABuf[0], BuffSize);
	for (uint32_t i = 0; i < (BuffSize/2); i++)
	{
		Master[i] = (uint16_t) (DMABuf[i] & 0x0000FFFF);
		Slave[i] = (uint16_t) (DMABuf[i] >> 16);
	}
}
 
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
{
	HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin);
	SCB_InvalidateDCache_by_Addr((uint32_t*) &DMABuf[BuffSize/2], BuffSize);
	for (uint32_t i = (BuffSize/2); i < BuffSize; i++)
	{
		Master[i] = (uint16_t) (DMABuf[i] & 0x0000FFFF);
		Slave[i] = (uint16_t) (DMABuf[i] >> 16);
	}
}

1 ACCEPTED SOLUTION

Accepted Solutions
SStor
Senior

Your DMA buffersize is 64Byte (4x16). Therefore you have to invalidate half buffersize of 32Bytes (2*BuffSize).

And take care to align the DMABuf to 32 Byte boundary because this is the data cache size. Otherwise you invalidate also parts of unwritten cached memory before or behind DMABuf, e.g. Master or Slave (depending on your memory layout).

View solution in original post

3 REPLIES 3
SStor
Senior

Your DMA buffersize is 64Byte (4x16). Therefore you have to invalidate half buffersize of 32Bytes (2*BuffSize).

And take care to align the DMABuf to 32 Byte boundary because this is the data cache size. Otherwise you invalidate also parts of unwritten cached memory before or behind DMABuf, e.g. Master or Slave (depending on your memory layout).

alister
Lead

Firstly, DMABuf's size is BuffSize * sizeof(uint32_t) bytes. So your length parameter to SCB_InvalidateDCache_by_Addr is incorrect.

Secondlythe M7 cache lines are 32-bytes and if DMABuf isn't cache-line aligned or BuffSize * sizeof(uint32_t) is not divisible by 32, your SCB_InvalidateDCache_by_Addr is also invalidating variables below and and above DMABuf in memory.

Check DMABuf in your link map file to confirm.

The __IO (volatile) on your DMABuf is unnecessary.

SEng.1
Associate II

Thanks all, Now I know where is the problem.

As for the cache alignment, saw there is no align_32byte on the example in stm32cubeide.

they only show :

__IO uint32_t   aADCDualConvertedValues[ADCCONVERTEDVALUES_BUFFER_SIZE];