2021-12-07 12:22 PM
Im having some problems getting DMA to work, none of the interrupt routines are called, Simplified code below, hints appreciated
ADC_HandleTypeDef hadc1;
DMA_HandleTypeDef hdma_adc1;
static uint32_t HAL_RCC_ADC12_CLK_ENABLED = 0;
boolean ADC1_done = false;
uint16_t ADC1ConvertedValue[10240];
void setup() {
Serial.begin(115200);
Serial.println("start");
SCB_DisableICache();
SCB_DisableDCache();
HAL_Init();
Stm32_Clock_Init(120, 1, 2, 2);
MX_DMA_Init();
MX_ADC1_Init();
MY_HAL_ADC_MspInit(&hadc1);
HAL_ADC_Start_DMA(&hadc1,
(uint32_t *)ADC1ConvertedValue,
1024
);
}
void loop() {
if (ADC1_done) {
Serial.println("adc done");
ADC1_done = false;
HAL_ADC_Start_DMA(&hadc1,
(uint32_t *)ADC1ConvertedValue,
1024
);
}
Serial.println(ADC1ConvertedValue[0]);
}
void Stm32_Clock_Init(uint32_t plln, uint32_t pllm, uint32_t pllp, uint32_t pllq)
{
HAL_StatusTypeDef ret = HAL_OK;
RCC_ClkInitTypeDef RCC_ClkInitStruct;
RCC_OscInitTypeDef RCC_OscInitStruct;
MODIFY_REG(PWR->CR3, PWR_CR3_SCUEN, 0);
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
while ((PWR->D3CR & (PWR_D3CR_VOSRDY)) != PWR_D3CR_VOSRDY) {}
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.HSIState = RCC_HSI_OFF;
RCC_OscInitStruct.CSIState = RCC_CSI_OFF;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLN = plln;
RCC_OscInitStruct.PLL.PLLM = pllm;
RCC_OscInitStruct.PLL.PLLP = pllp;
RCC_OscInitStruct.PLL.PLLQ = pllq;
RCC_OscInitStruct.PLL.PLLVCOSEL = RCC_PLL1VCOWIDE;
RCC_OscInitStruct.PLL.PLLRGE = RCC_PLL1VCIRANGE_2;
ret = HAL_RCC_OscConfig(&RCC_OscInitStruct);
RCC_ClkInitStruct.ClockType = (RCC_CLOCKTYPE_SYSCLK | \
RCC_CLOCKTYPE_HCLK | \
RCC_CLOCKTYPE_D1PCLK1 | \
RCC_CLOCKTYPE_PCLK1 | \
RCC_CLOCKTYPE_PCLK2 | \
RCC_CLOCKTYPE_D3PCLK1);
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.SYSCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.AHBCLKDivider = RCC_HCLK_DIV2;
RCC_ClkInitStruct.APB1CLKDivider = RCC_APB1_DIV2;
RCC_ClkInitStruct.APB2CLKDivider = RCC_APB2_DIV2;
RCC_ClkInitStruct.APB3CLKDivider = RCC_APB3_DIV2;
RCC_ClkInitStruct.APB4CLKDivider = RCC_APB4_DIV4;
ret = HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2);
if (ret != HAL_OK) while (1);
__HAL_RCC_CSI_ENABLE() ;
__HAL_RCC_SYSCFG_CLK_ENABLE() ;
HAL_EnableCompensationCell();
RCC_PeriphCLKInitTypeDef PeriphClkInitStruct = {0};
/** Initializes the peripherals clock
*/
PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_ADC;
PeriphClkInitStruct.PLL2.PLL2M = 1;
PeriphClkInitStruct.PLL2.PLL2N = 18;
PeriphClkInitStruct.PLL2.PLL2P = 2;
PeriphClkInitStruct.PLL2.PLL2Q = 2;
PeriphClkInitStruct.PLL2.PLL2R = 2;
PeriphClkInitStruct.PLL2.PLL2RGE = RCC_PLL2VCIRANGE_3;
PeriphClkInitStruct.PLL2.PLL2VCOSEL = RCC_PLL2VCOMEDIUM;
PeriphClkInitStruct.PLL2.PLL2FRACN = 6144;
PeriphClkInitStruct.AdcClockSelection = RCC_ADCCLKSOURCE_PLL2;
if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK)
{
error1();
}
}
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 MX_ADC1_Init(void)
{
ADC_MultiModeTypeDef multimode = {0};
ADC_ChannelConfTypeDef sConfig = {0};
hadc1.Instance = ADC1;
hadc1.Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV2;
hadc1.Init.Resolution = ADC_RESOLUTION_10B;
hadc1.Init.ScanConvMode = ADC_SCAN_DISABLE;
hadc1.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
hadc1.Init.LowPowerAutoWait = DISABLE;
hadc1.Init.ContinuousConvMode = DISABLE;
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_ONESHOT;
//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)
{
error1();
}
/** Configure the ADC multi-mode
*/
multimode.Mode = ADC_MODE_INDEPENDENT;
if (HAL_ADCEx_MultiModeConfigChannel(&hadc1, &multimode) != HAL_OK)
{
error1();
}
sConfig.Channel = ADC_CHANNEL_16;
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)
{
error1();
}
}
void MY_HAL_ADC_MspInit(ADC_HandleTypeDef* adcHandle)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
if (adcHandle->Instance == ADC1)
{
/* ADC1 clock enable */
HAL_RCC_ADC12_CLK_ENABLED++;
if (HAL_RCC_ADC12_CLK_ENABLED == 1) {
__HAL_RCC_ADC12_CLK_ENABLE();
}
__HAL_RCC_GPIOA_CLK_ENABLE();
/**ADC1 GPIO Configuration
PA0 ------> ADC1_INP16
*/
GPIO_InitStruct.Pin = GPIO_PIN_0;
GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOA, &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_HALFWORD;
hdma_adc1.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
hdma_adc1.Init.Mode = DMA_NORMAL;
//hdma_adc1.Init.Mode = DMA_CIRCULAR;
hdma_adc1.Init.Priority = DMA_PRIORITY_VERY_HIGH;
hdma_adc1.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
if (HAL_DMA_Init(&hdma_adc1) != HAL_OK)
{
error1();
}
__HAL_LINKDMA(adcHandle, DMA_Handle, hdma_adc1);
}
}
void DMA1_Stream0_IRQHandler(void)
{
Serial.println("stream0");
ADC1_done = true;
/* USER CODE END DMA1_Stream0_IRQn 0 */
HAL_DMA_IRQHandler(&hdma_adc1);
}
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc) {
Serial.println("call back");
if (hadc->Instance == ADC1) {
ADC1_done = true;
HAL_ADC_Stop_DMA(hadc);
}
}
void HAL_ADC_ConvHalfCpltCallback(ADC_HandleTypeDef* hadc) {
Serial.println("half call back");
if (hadc->Instance == ADC1) {
ADC1_done = true;
HAL_ADC_Stop_DMA(hadc);
}
}
void error1(void) {
Serial.println("error 1");
}
2021-12-07 12:37 PM
maybe a little more info on what i want to achieve... sampling 2 adc channels, say 500 samples each, on command, after completion processing and visualisation, then restart the sampling process.
input frequencies are fixed betwee 20Hz and 5KHz
arduino stm32duino platform
for simplicity i only use 1 channel but none of the interrupt subroutines are called
2021-12-07 05:16 PM
It may be related to default STM32H7xxx_FLASH.ld configuration.
Hint:
MEMORY
{
FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 128K
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 128K // DTCM is inaccessible by DMA!
RAM_D1 (xrw) : ORIGIN = 0x24000000, LENGTH = 512K
RAM_D2 (xrw) : ORIGIN = 0x30000000, LENGTH = 288K
RAM_D3 (xrw) : ORIGIN = 0x38000000, LENGTH = 64K
ITCMRAM (xrw) : ORIGIN = 0x00000000, LENGTH = 64K
}
SECTIONS
{
...
.ram_d2_sram1 (NOLOAD):
{
. = ALIGN(4);
*(.ram_d2_sram1)
} >RAM_D2
...
uint16_t ADC1ConvertedValue[10240] __attribute__((section(".ram_d2_sram1"))); // put array at 0x30000000 instead
From reference manual: "The memory bus allows DMA data transfers between memories. Through the system bus matrices, the memory bus can access all internal memories except ITCM and DTCM, and external memories through the Quad-SPI controller and the FMC."
2021-12-08 05:24 AM
I changed the var according to your tip but no luck, i get the start message on the serial monitor but nothing else, none of the callbacks are triggered but also no errors
2021-12-09 03:51 AM
a little more detail..
if i check the variable address without any changes i get 0x00000078, clearly in the ITCMRAM section.
After applying the changes to program and linker script, check the address again and its 0x00000000 iow not assigned
i tried a few variations, including the solutions offered in DMA is not working on STM32H7 devices
solution 2, same result, tried to enable the ram clock, disable cache etc
the linker recognises the section attributes but does not assign to the D2 ram
no clue to as why this happened
2021-12-10 01:17 AM
ok, i went back to the basics, isolating the variable issue, sorted out now, properly linked to 0x30000... , clk to ram is enabled but still no interrupts or messages from adc or dma, what am i missing here?