2024-07-16 07:08 AM
Processor: STM32H753
I am attempting to continuously read an ADC, and transfer the data into a circular data buffer with the ADC. I configured everything in CubeMX. No matter what I try, I get a transfer error from the DMA the first time it reads. I tried both DMA1 and DMA2 with different streams thinking maybe there is a limitation on which stream I can use to read ADC2. I extracted the configuration code for testing and example purposes, which gets run at startup.
Init():
// void MX_ADC2_Init(void)
hadc2.Instance = ADC2;
hadc2.Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV256; // ADC clock = 62.5 MHz / 256 = 244 kHz
hadc2.Init.Resolution = ADC_RESOLUTION_12B;
hadc2.Init.ScanConvMode = ADC_SCAN_DISABLE;
hadc2.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
hadc2.Init.LowPowerAutoWait = DISABLE;
hadc2.Init.ContinuousConvMode = ENABLE; // Enable continuous conversion mode
hadc2.Init.NbrOfConversion = 1;
hadc2.Init.DiscontinuousConvMode = DISABLE;
hadc2.Init.ExternalTrigConv = ADC_SOFTWARE_START;
hadc2.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
hadc2.Init.ConversionDataManagement = ADC_CONVERSIONDATA_DMA_CIRCULAR;
hadc2.Init.Overrun = ADC_OVR_DATA_OVERWRITTEN;
hadc2.Init.LeftBitShift = ADC_LEFTBITSHIFT_NONE;
hadc2.Init.OversamplingMode = DISABLE;
if (HAL_ADC_Init(&hadc2) != HAL_OK) {
LOG(LOG_LEVEL_ERROR, "HAL_ADC_Init Error");
}
ADC_ChannelConfTypeDef sConfig = {0};
sConfig.Channel = ADC_CHANNEL_8;
sConfig.Rank = ADC_REGULAR_RANK_1;
sConfig.SamplingTime = ADC_SAMPLETIME_16CYCLES_5; // Sampling time = 16.5 cycles
sConfig.SingleDiff = ADC_SINGLE_ENDED;
sConfig.OffsetNumber = ADC_OFFSET_NONE;
sConfig.Offset = 0;
sConfig.OffsetRightShift = DISABLE;
sConfig.OffsetSignedSaturation = DISABLE;
if (HAL_ADC_ConfigChannel(&hadc2, &sConfig) != HAL_OK) {
LOG(LOG_LEVEL_ERROR, "HAL_ADC_ConfigChannel Error");
}
hdma_adc2.Instance = DMA2_Stream0;
hdma_adc2.Init.Request = DMA_REQUEST_ADC2;
hdma_adc2.Init.Direction = DMA_PERIPH_TO_MEMORY;
hdma_adc2.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_adc2.Init.MemInc = DMA_MINC_ENABLE;
hdma_adc2.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
hdma_adc2.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
hdma_adc2.Init.Mode = DMA_CIRCULAR; // Enable circular mode
hdma_adc2.Init.Priority = DMA_PRIORITY_HIGH;
hdma_adc2.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
if (HAL_DMA_Init(&hdma_adc2) != HAL_OK)
{
LOG(LOG_LEVEL_ERROR, "HAL_DMA_Init Error");
}
__HAL_LINKDMA(&hadc2, DMA_Handle, hdma_adc2);
// MX_DMA_Init()
__HAL_RCC_DMA2_CLK_ENABLE();
HAL_NVIC_SetPriority(DMA2_Stream0_IRQn, 12, 0);
HAL_NVIC_EnableIRQ(DMA2_Stream0_IRQn);
I then start the DMA a little later in the Init routine:
rtems_task_wake_after(RTEMS_MILLISECONDS_TO_TICKS(100));
// Motor current ADC DMA
_ARMV7M_Set_exception_priority_and_handler(
ARMV7M_VECTOR_IRQ(DMA2_Stream0_IRQn),
(14 << 4),
TestIRQHandler);
LOG(LOG_LEVEL_DEBUG, YELLOW("hdma_adc2.Init.Request=%lu hdma_adc2.Init.Mode=%lu DMA_CIRCULAR=%lu"),
hdma_adc2.Init.Request, hdma_adc2.Init.Mode, DMA_CIRCULAR);
LOG(LOG_LEVEL_DEBUG, YELLOW("&hdma_adc2=%p hadc2.DMA_Handle=%p"), &hdma_adc2, hadc2.DMA_Handle);
LOG(LOG_LEVEL_DEBUG, YELLOW("&hadc2=%p hdma_adc2.Parent=%p"),
&hadc2, hdma_adc2.Parent);
LOG(LOG_LEVEL_DEBUG, YELLOW("hdma_adc2.DMAmuxChannel->CCR=0x%lx hdma_adc2.DMAmuxRequestGen->RGCR=0x%lx"),
hdma_adc2.DMAmuxChannel->CCR, hdma_adc2.DMAmuxRequestGen->RGCR);
LOG(LOG_LEVEL_DEBUG, BLUE("HWIO::init hadc2.State=0x%lx hadc2.ErrorCode=0x%lx"), hadc2.State, hadc2.ErrorCode);
LOG(LOG_LEVEL_DEBUG, BLUE("HWIO::init hdma_adc2.State=0x%x hdma_adc2.ErrorCode=0x%lx"), hdma_adc2.State, hdma_adc2.ErrorCode);
LOG(LOG_LEVEL_DEBUG, BLUE("hdma_adc2.DMAmuxChannelStatus->CSR=0x%lx hdma_adc2.DMAmuxRequestGenStatus->RGSR=0x%lx"),
hdma_adc2.DMAmuxChannelStatus->CSR, hdma_adc2.DMAmuxRequestGenStatus->RGSR);
HAL_StatusTypeDef halStatus = HAL_ADC_Start_DMA(&hadc2, motorCurrentBuffer, MOTOR_CURRENT_BUFFER_SIZE);
if (halStatus == HAL_OK)
{
LOG(LOG_LEVEL_DEBUG, "HWIO::init DMA started");
}
else
{
LOG(LOG_LEVEL_ERROR, "HWIO::init DMA failed to start");
}
LOG(LOG_LEVEL_DEBUG, GREEN("HWIO::init hadc2.State=0x%lx hadc2.ErrorCode=0x%lx"), hadc2.State, hadc2.ErrorCode);
LOG(LOG_LEVEL_DEBUG, GREEN("HWIO::init hdma_adc2.State=0x%x hdma_adc2.ErrorCode=0x%lx"), hdma_adc2.State, hdma_adc2.ErrorCode);
LOG(LOG_LEVEL_DEBUG, GREEN("hdma_adc2.DMAmuxChannelStatus->CSR=0x%lx hdma_adc2.DMAmuxRequestGenStatus->RGSR=0x%lx"),
hdma_adc2.DMAmuxChannelStatus->CSR, hdma_adc2.DMAmuxRequestGenStatus->RGSR);
rtems_task_wake_after(RTEMS_MILLISECONDS_TO_TICKS(100));
LOG(LOG_LEVEL_DEBUG, MAGENTA("HWIO::init hadc2.State=0x%lx hadc2.ErrorCode=0x%lx"), hadc2.State, hadc2.ErrorCode);
LOG(LOG_LEVEL_DEBUG, MAGENTA("HWIO::init hdma_adc2.State=0x%x hdma_adc2.ErrorCode=0x%lx"), hdma_adc2.State, hdma_adc2.ErrorCode);
LOG(LOG_LEVEL_DEBUG, MAGENTA("hdma_adc2.DMAmuxChannelStatus->CSR=0x%lx hdma_adc2.DMAmuxRequestGenStatus->RGSR=0x%lx"),
hdma_adc2.DMAmuxChannelStatus->CSR, hdma_adc2.DMAmuxRequestGenStatus->RGSR);
LOG(LOG_LEVEL_DEBUG, MAGENTA("HWIO::init [0]=%lu [1]=%lu [2]=%lu [3]=%lu dmaIRQCalls=%d"),
motorCurrentBuffer[0], motorCurrentBuffer[1], motorCurrentBuffer[2], motorCurrentBuffer[3], dmaIRQCalls);
dmaIRQCalls = 0;
Here is the output of the debug prints above:
DEBUG> hdma_adc2.Init.Request=10 hdma_adc2.Init.Mode=256 DMA_CIRCULAR=256
DEBUG> &hdma_adc2=0x2001c87c hadc2.DMA_Handle=0x2001c87c
DEBUG> &hadc2=0x2001c940 hdma_adc2.Parent=0x2001c940
DEBUG> hdma_adc2.DMAmuxChannel->CCR=0xa hdma_adc2.DMAmuxRequestGen->RGCR=0x3
DEBUG> HWIO::init hadc2.State=0x1 hadc2.ErrorCode=0x0
DEBUG> HWIO::init hdma_adc2.State=0x1 hdma_adc2.ErrorCode=0x0
DEBUG> hdma_adc2.DMAmuxChannelStatus->CSR=0x0 hdma_adc2.DMAmuxRequestGenStatus->RGSR=0x3
DEBUG> HWIO::init DMA started
DEBUG> HWIO::init hadc2.State=0x100 hadc2.ErrorCode=0x0
DEBUG> HWIO::init hdma_adc2.State=0x2 hdma_adc2.ErrorCode=0x0
DEBUG> hdma_adc2.DMAmuxChannelStatus->CSR=0x0 hdma_adc2.DMAmuxRequestGenStatus->RGSR=0x3
ERROR> ADC Error Callback
ERROR> HAL_ADC_ErrorCallback hadc->State=0x140 hadc->ErrorCode=0x4
ERROR> HAL_ADC_ErrorCallback hadc->DMA_Handle->StreamIndex=0x0
DEBUG> HWIO::init hadc2.State=0x140 hadc2.ErrorCode=0x4
DEBUG> HWIO::init hdma_adc2.State=0x1 hdma_adc2.ErrorCode=0x1
DEBUG> hdma_adc2.DMAmuxChannelStatus->CSR=0x0 hdma_adc2.DMAmuxRequestGenStatus->RGSR=0x3
DEBUG> HWIO::init [0]=0 [1]=0 [2]=0 [3]=0 dmaIRQCalls=1
I've verified nothing else is using ADC2. I am completely out of ideas.
Any idea what I am doing wrong?
2024-07-16 07:41 AM
Read out and check/post content of given DMA Stream's registers.
JW
2024-07-16 07:51 AM
DMA2_Stream0 CR=0x0000001a NDTR=0x000003ff PAR=0x40022140 M0AR=0x20009d84 FCR=0x00000021
2024-07-16 08:15 AM - edited 2024-07-16 08:18 AM
The registers I posted above were after the DMA threw a transfer error. Here is a bit more info:
Before Starting:
DMA2_Stream0 CR=0x00000000 NDTR=0x00000000 PAR=0x00000000 M0AR=0x00000000 FCR=0x00000021
After Starting:
DMA2_Stream0 CR=0x0000001f NDTR=0x00000400 PAR=0x40022140 M0AR=0x20009d84 FCR=0x00000021
After Transfer Error:
DMA2_Stream0 CR=0x0000001a NDTR=0x000003ff PAR=0x40022140 M0AR=0x20009d84 FCR=0x00000021
M0AR matches the buffer address. Buffer size is 1024, so NDTR is correct. The CR doesn't seem to match the configuration.
2024-07-16 08:30 AM
0x20009d84 is in DTCM
In 'H753, there's no route from DMA1/DMA2 to DTCM:
JW