2023-01-27 02:06 PM
The code works fine on STM32G474 and I can get 1Msampe/second.
I redid the same project on STM32H7A3ZIT6Q with the changes indicated
https://community.st.com/s/article/FAQ-DMA-is-not-working-on-STM32H7-devices
I went to the option having a dma section. The link above linker is different. Mine is down below.
It does not start. I d not get the callbacks.
Then I used this project
https://github.com/moggiozzi/stm32h7_adc_dma
Is the same I have no ADC DMA callbacks called.
The DMA1_Stream0_IRQHandler is not called
The ADC_IRQHandler is called and fails here
if (hadc->Init.Overrun == ADC_OVR_DATA_PRESERVED)
{
overrun_error = 1UL;
}
Tweaking the
sConfig.SamplingTime = ADC_SAMPLETIME_64CYCLES_5; //ADC_SAMPLETIME_1CYCLE_5; up to 65C5 did not help.
Thank you
my ld file looks like:
MEMORY
{
ITCMRAM (xrw) : ORIGIN = 0x00000000, LENGTH = 64K
FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 2048K
DTCMRAM1 (xrw) : ORIGIN = 0x20000000, LENGTH = 64K
DTCMRAM2 (xrw) : ORIGIN = 0x20010000, LENGTH = 64K
RAM (xrw) : ORIGIN = 0x24000000, LENGTH = 1024K
RAM_CD (xrw) : ORIGIN = 0x30000000, LENGTH = 128K
RAM_SRD (xrw) : ORIGIN = 0x38000000, LENGTH = 32K
}
...
.data :
{
. = ALIGN(4);
_sdata = .; /* create a global symbol at data start */
*(.data) /* .data sections */
*(.data*) /* .data* sections */
*(.RamFunc) /* .RamFunc sections */
*(.RamFunc*) /* .RamFunc* sections */
. = ALIGN(4);
_edata = .; /* define a global symbol at data end */
} >RAM AT> FLASH
/* dma buffer */
.ram_d1 ORIGIN(DTCMRAM1) (NOLOAD):
{
*(.adc_dma_buf)
} >DTCMRAM1
Then in my main I have
//////////////////////////////////////////////////////////
#define ADC_BUF_SIZE ((1024 + 0x1f) & ~0x1f)
// adc_buf[ADC_BUF_SIZE];
static __attribute__((section(".adc_dma_buf"))) \
__attribute__((aligned(0x20))) \
uint32_t adc_buf[ADC_BUF_SIZE];
//////////////////////////////////////////////////////////
/* omiytted for clarity */
////////////////////////////////////////////////////////// the callbacks
void HAL_ADC_ConvHalfCpltCallback(ADC_HandleTypeDef* hadc)
{
Half=1;
}
// Called when buffer is completely filled
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
{
Half=2;
}
////////////////////////////////////////////////// then main
int main(void)
{
/* USER CODE BEGIN 1 */
int Togle = 0;
int Count = 0;
int ret = 0;
uint32_t tnow;
/* 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();
/* USER CODE BEGIN SysInit */
//__HAL_RCC_DMAMUX1_CLK_ENABLE(); // mco from other example
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_DMA_Init();
MX_ADC1_Init();
MX_UART5_Init();
/* USER CODE BEGIN 2 */
printf("Starting AD\r\n");
memset(&adc_buf[0], 0xff, sizeof(adc_buf));
SCB_InvalidateDCache_by_Addr((uint32_t*)&adc_buf[0], sizeof(adc_buf));
HAL_ADC_Start_DMA(&hadc1, (uint32_t*)adc_buf, ADC_BUF_SIZE);
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
if(Half==1)
{
Half=0;
}
else if(Half==2)
{
Half=0;
Bytes += (ADC_BUF_SIZE);
}
tnow = HAL_GetTick();
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
if(tnow-Now>1000)
{
char rec[1];
Now=tnow;
if(Count++%3==0)
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_9, Togle=!Togle);
rec[0]=0;
if(HAL_OK==HAL_UART_Receive(&huart5,rec,sizeof(rec),1000))
{
if(atoi(rec)!=0)
{
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_8, 1);
}
else
{
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_8, 0);
}
}
printf("PIN=%s,USB=%d: %d=SPS at[0]=%d at[1023]=%d \r\n",
rec,ret, Bytes,
adc_buf[0], adc_buf[ADC_BUF_SIZE-2]);
Bytes=0;
}
}
/* USER CODE END 3 */
}
/////////////////////
Then the ADC and DMA settings
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_DR;
hadc1.Init.Overrun = ADC_OVR_DATA_PRESERVED;
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_MODE_INDEPENDENT;
if (HAL_ADCEx_MultiModeConfigChannel(&hadc1, &multimode) != HAL_OK)
{
Error_Handler();
}
/** Configure Regular Channel
*/
sConfig.Channel = ADC_CHANNEL_2;
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_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_MspInit(void)
{
/* USER CODE BEGIN MspInit 0 */
/* USER CODE END MspInit 0 */
__HAL_RCC_SYSCFG_CLK_ENABLE();
/* System interrupt init*/
/* USER CODE BEGIN MspInit 1 */
/* USER CODE END MspInit 1 */
}
void HAL_ADC_MspInit(ADC_HandleTypeDef* hadc)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
RCC_PeriphCLKInitTypeDef PeriphClkInitStruct = {0};
if(hadc->Instance==ADC1)
{
/* USER CODE BEGIN ADC1_MspInit 0 */
/* USER CODE END ADC1_MspInit 0 */
/** Initializes the peripherals clock
*/
PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_ADC;
PeriphClkInitStruct.PLL2.PLL2M = 32;
PeriphClkInitStruct.PLL2.PLL2N = 129;
PeriphClkInitStruct.PLL2.PLL2P = 2;
PeriphClkInitStruct.PLL2.PLL2Q = 2;
PeriphClkInitStruct.PLL2.PLL2R = 2;
PeriphClkInitStruct.PLL2.PLL2RGE = RCC_PLL2VCIRANGE_1;
PeriphClkInitStruct.PLL2.PLL2VCOSEL = RCC_PLL2VCOWIDE;
PeriphClkInitStruct.PLL2.PLL2FRACN = 0;
PeriphClkInitStruct.AdcClockSelection = RCC_ADCCLKSOURCE_PLL2;
if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK)
{
Error_Handler();
}
/* Peripheral clock enable */
__HAL_RCC_ADC12_CLK_ENABLE();
__HAL_RCC_GPIOF_CLK_ENABLE();
/**ADC1 GPIO Configuration
PF11 ------> ADC1_INP2
*/
GPIO_InitStruct.Pin = GPIO_PIN_11;
GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOF, &GPIO_InitStruct);
/* ADC1 DMA Init */
/* ADC1 Init */
hdma_adc1.Instance = DMA1_Stream0;
hdma_adc1.Init.Request = DMA_REQUEST_ADC1;
hdma_adc1.Init.Direction = DMA_PERIPH_TO_MEMORY;
hdma_adc1.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_adc1.Init.MemInc = DMA_MINC_ENABLE;
hdma_adc1.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
hdma_adc1.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;
hdma_adc1.Init.Mode = DMA_NORMAL;
hdma_adc1.Init.Priority = DMA_PRIORITY_LOW;
hdma_adc1.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
if (HAL_DMA_Init(&hdma_adc1) != HAL_OK)
{
Error_Handler();
}
__HAL_LINKDMA(hadc,DMA_Handle,hdma_adc1);
/* ADC1 interrupt Init */
HAL_NVIC_SetPriority(ADC_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(ADC_IRQn);
/* USER CODE BEGIN ADC1_MspInit 1 */
/* USER CODE END ADC1_MspInit 1 */
}
}
2023-01-28 07:18 PM
I think is something wrong with the adc buffer.
Either on stack either on __attribute__((section(".adc_dma_buf")))
did not work.
Anyone can help where to place it in ld file ?
If I change the DMA buffer to heap and disable
// SCB_EnableICache();
// SCB_EnableDCache();
adc_buf = (uint32_t*)malloc(4096*sizeof(uint32_t));
Works: I get 2 Mbps with ADC_CLOCK_ASYNC_DIV4,
Down is 1 second report printing in the loop. (/ second)
SPS are samples/second, one sample is 32 bit long.
GOTS are halfs+wholes completion calls.
math is good 977(callbacks) * 4096(buffer) /2(2 callbacks half and whole)=2000896(SPS)
The 64's/4096 values are 1 ADC reads from a gpio I toggle at index 0,1 Half/2+/-1 and
end-1 and end to check if the buffer is valid (just debug).
PIN=,USB=0: SPS=2000896 SND=1 GOTS=977 63 63 64 64 | 63 63 63 63
PIN=,USB=0: SPS=1998848 SND=1 GOTS=976 65 64 64 64 | 64 64 64 64
PIN=,USB=0: SPS=2000896 SND=1 GOTS=977 4095 4095 4095 4095 | 4095 4095 4095 4095
PIN=,USB=0: SPS=2000896 SND=1 GOTS=977 4095 4095 4095 4095 | 4095 4095 4095 4095