cancel
Showing results for 
Search instead for 
Did you mean: 

ADC DMA HAL Libraries STM32F0

engenharia2
Associate II
Posted on January 21, 2016 at 19:41

Hello everybody!

I'm trying to read two ADC channels in STM32F042 microcontroller with DMA without interruption. I expected the DMA reads channel 0 then channel 1 filling five samples of each channel in my vector. But the vector I created only updates the first value. The complete projectare attached. Does anyone know of anything that can help?

/* Includes ------------------------------------------------------------------*/
#include ''stm32f0xx_hal.h''
/* USER CODE BEGIN Includes */
/* USER CODE END Includes */
/* Private variables ---------------------------------------------------------*/
ADC_HandleTypeDef hadc;
DMA_HandleTypeDef hdma_adc;
UART_HandleTypeDef huart2;
/* USER CODE BEGIN PV */
/* Private variables ---------------------------------------------------------*/
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_DMA_Init(void);
static void MX_ADC_Init(void);
static void MX_USART2_UART_Init(void);
/* USER CODE BEGIN PFP */
/* Private function prototypes -----------------------------------------------*/
/* USER CODE END PFP */
/* USER CODE BEGIN 0 */
uint32_t adcBuffer[20];
uint32_t *pADC = &adcBuffer[0];
void readAdc(void) {
HAL_ADC_Stop_DMA(&hadc);
memset(pADC, 0, strlen(pADC));
HAL_ADC_Start_DMA(&hadc, pADC, 10);
}
/* USER CODE END 0 */
int main(void)
{
/* USER CODE BEGIN 1 */
char str[10];
char *separator = ''**********************\r\n'';
/* USER CODE END 1 */
/* MCU Configuration----------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* Configure the system clock */
SystemClock_Config();
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_DMA_Init();
MX_ADC_Init();
MX_USART2_UART_Init();
/* USER CODE BEGIN 2 */
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
readAdc();
HAL_Delay(10);
for(int i = 0; i<10; i++) {
sprintf(str, ''%10d\r\n'', adcBuffer[i]);
HAL_UART_Transmit(&huart2, str, strlen(str), 100);
HAL_Delay(30);
HAL_GPIO_TogglePin(LED_STS_GPIO_Port, LED_STS_Pin);
}
HAL_UART_Transmit(&huart2, ''**********-**********\r\n'', strlen(''**********-**********\r\n''), 100);
HAL_Delay(1000);
}
/* USER CODE END 3 */
}
/** System Clock Configuration
*/
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct;
RCC_ClkInitTypeDef RCC_ClkInitStruct;
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI|RCC_OSCILLATORTYPE_HSI14;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.HSI14State = RCC_HSI14_ON;
RCC_OscInitStruct.HSICalibrationValue = 16;
RCC_OscInitStruct.HSI14CalibrationValue = 16;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
HAL_RCC_OscConfig(&RCC_OscInitStruct);
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_SYSCLK;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0);
HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq()/1000);
HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK);
/* SysTick_IRQn interrupt configuration */
HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0);
}
/* ADC init function */
void MX_ADC_Init(void)
{
ADC_ChannelConfTypeDef sConfig;
/**Configure the global features of the ADC (Clock, Resolution, Data Alignment and number of conversion) 
*/
hadc.Instance = ADC1;
hadc.Init.ClockPrescaler = ADC_CLOCK_ASYNC;
hadc.Init.Resolution = ADC_RESOLUTION12b;
hadc.Init.DataAlign = ADC_DATAALIGN_RIGHT;
hadc.Init.ScanConvMode = ADC_SCAN_DIRECTION_FORWARD;
hadc.Init.EOCSelection = EOC_SEQ_CONV;
hadc.Init.LowPowerAutoWait = DISABLE;
hadc.Init.LowPowerAutoPowerOff = DISABLE;
hadc.Init.ContinuousConvMode = DISABLE;
hadc.Init.DiscontinuousConvMode = DISABLE;
hadc.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
hadc.Init.DMAContinuousRequests = DISABLE;
hadc.Init.Overrun = OVR_DATA_PRESERVED;
HAL_ADC_Init(&hadc);
/**Configure for the selected ADC regular channel to be converted. 
*/
sConfig.Channel = ADC_CHANNEL_1;
sConfig.Rank = ADC_RANK_CHANNEL_NUMBER;
sConfig.SamplingTime = ADC_SAMPLETIME_1CYCLE_5;
HAL_ADC_ConfigChannel(&hadc, &sConfig);
}
/* USART2 init function */
void MX_USART2_UART_Init(void)
{
huart2.Instance = USART2;
huart2.Init.BaudRate = 115200;
huart2.Init.WordLength = UART_WORDLENGTH_8B;
huart2.Init.StopBits = UART_STOPBITS_1;
huart2.Init.Parity = UART_PARITY_NONE;
huart2.Init.Mode = UART_MODE_TX_RX;
huart2.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart2.Init.OverSampling = UART_OVERSAMPLING_16;
huart2.Init.OneBitSampling = UART_ONEBIT_SAMPLING_DISABLED ;
huart2.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
HAL_UART_Init(&huart2);
}
/** 
* Enable DMA controller clock
*/
void MX_DMA_Init(void) 
{
/* DMA controller clock enable */
__DMA1_CLK_ENABLE();
/* DMA interrupt init */
HAL_NVIC_SetPriority(DMA1_Channel1_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(DMA1_Channel1_IRQn);
}

8 REPLIES 8
engenharia2
Associate II
Posted on January 21, 2016 at 21:28

Hello guys, I solve this problem. Now I can read 2 analog inputs in sequence with DMA. Below can be seen the result. The channel 0 has a resistive divider and channel 1 are tied to ground.

********** - ********** CH0: 2043 CH1: 0 CH0: 2045 CH1: 0 CH0: 2045 CH1: 0 CH0: 2045 CH1: 0 CH0: 2048 CH1: 0 ********** - ********** The change I made was in hadc.Init.ClockPrescaler which by default is ADC_CLOCK_ASYNC and there is no change in STM32CubeMX because the options in dropdown list are blocked. I add the second channel to read on sConfig too, because STM32CubeMX doesn't do this even if the channels are selected on graphical interface of Cube. Here is the code that works for me:

/* Includes ------------------------------------------------------------------*/
#include ''stm32f0xx_hal.h''
/* USER CODE BEGIN Includes */
/* USER CODE END Includes */
/* Private variables ---------------------------------------------------------*/
ADC_HandleTypeDef hadc;
DMA_HandleTypeDef hdma_adc;
UART_HandleTypeDef huart2;
/* USER CODE BEGIN PV */
/* Private variables ---------------------------------------------------------*/
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_DMA_Init(void);
static void MX_ADC_Init(void);
static void MX_USART2_UART_Init(void);
/* USER CODE BEGIN PFP */
/* Private function prototypes -----------------------------------------------*/
/* USER CODE END PFP */
/* USER CODE BEGIN 0 */
uint32_t adcBuffer[10];
uint32_t *pADC = &adcBuffer[0];
void readAdc(void) {
HAL_ADC_Stop_DMA(&hadc);
for(int i=0; i<10; i++) {
adcBuffer[i] = 0x00;
}
HAL_ADC_Start_DMA(&hadc, pADC, 10);
HAL_ADC_Start(&hadc);
}
/* USER CODE END 0 */
int main(void)
{
/* USER CODE BEGIN 1 */
char str[10];
/* USER CODE END 1 */
/* MCU Configuration----------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* Configure the system clock */
SystemClock_Config();
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_DMA_Init();
MX_ADC_Init();
MX_USART2_UART_Init();
/* USER CODE BEGIN 2 */
HAL_ADCEx_Calibration_Start(&hadc);
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
readAdc();
HAL_Delay(20);
for(int i = 0; i<10; ) {
sprintf(str, ''CH0: %4d

CH1: %4d

'', adcBuffer[i], adcBuffer[i+1]);
HAL_UART_Transmit(&huart2, str, strlen(str), 100);
HAL_Delay(30);
HAL_GPIO_TogglePin(LED_STS_GPIO_Port, LED_STS_Pin);
i+=2;
}
HAL_UART_Transmit(&huart2, ''**********-**********

'', strlen(''**********-**********

''), 100);
HAL_Delay(1000);
}
/* USER CODE END 3 */
}
/** System Clock Configuration
*/
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct;
RCC_ClkInitTypeDef RCC_ClkInitStruct;
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI|RCC_OSCILLATORTYPE_HSI14;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.HSI14State = RCC_HSI14_ON;
RCC_OscInitStruct.HSICalibrationValue = 16;
RCC_OscInitStruct.HSI14CalibrationValue = 16;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
HAL_RCC_OscConfig(&RCC_OscInitStruct);
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_SYSCLK;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0);
HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq()/1000);
HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK);
/* SysTick_IRQn interrupt configuration */
HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0);
}
/* ADC init function */
void MX_ADC_Init(void)
{
ADC_ChannelConfTypeDef sConfig;
/**Configure the global features of the ADC (Clock, Resolution, Data Alignment and number of conversion) 
*/
hadc.Instance = ADC1;
hadc.Init.ClockPrescaler = ADC_CLOCKPRESCALER_PCLK_DIV4; // <--- CHANGED MANUALLY BECAUSE STM32CUBEMX OPTIONS FOR CLOCK ARE BLOCKED
hadc.Init.Resolution = ADC_RESOLUTION12b;
hadc.Init.DataAlign = ADC_DATAALIGN_RIGHT;
hadc.Init.ScanConvMode = ADC_SCAN_DIRECTION_FORWARD;
hadc.Init.EOCSelection = EOC_SEQ_CONV;
hadc.Init.LowPowerAutoWait = DISABLE;
hadc.Init.LowPowerAutoPowerOff = DISABLE;
hadc.Init.ContinuousConvMode = ENABLE;
hadc.Init.DiscontinuousConvMode = DISABLE;
hadc.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
hadc.Init.DMAContinuousRequests = DISABLE;
hadc.Init.Overrun = OVR_DATA_PRESERVED;
HAL_ADC_Init(&hadc);
/**Configure for the selected ADC regular channel to be converted. 
*/
sConfig.Channel = ADC_CHANNEL_0;
sConfig.Rank = ADC_RANK_CHANNEL_NUMBER;
sConfig.SamplingTime = ADC_SAMPLETIME_1CYCLE_5;
HAL_ADC_ConfigChannel(&hadc, &sConfig);
// <--- ADD THE SECOND CHANNEL TO READ. STM32CUBEMX DOESN'T DO THIS...
sConfig.Channel = ADC_CHANNEL_1;
sConfig.Rank = ADC_RANK_CHANNEL_NUMBER;
sConfig.SamplingTime = ADC_SAMPLETIME_1CYCLE_5;
HAL_ADC_ConfigChannel(&hadc, &sConfig);
}
/* USART2 init function */
void MX_USART2_UART_Init(void)
{
huart2.Instance = USART2;
huart2.Init.BaudRate = 115200;
huart2.Init.WordLength = UART_WORDLENGTH_8B;
huart2.Init.StopBits = UART_STOPBITS_1;
huart2.Init.Parity = UART_PARITY_NONE;
huart2.Init.Mode = UART_MODE_TX_RX;
huart2.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart2.Init.OverSampling = UART_OVERSAMPLING_16;
huart2.Init.OneBitSampling = UART_ONEBIT_SAMPLING_DISABLED ;
huart2.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
HAL_UART_Init(&huart2);
}
/** 
* Enable DMA controller clock
*/
void MX_DMA_Init(void) 
{
/* DMA controller clock enable */
__DMA1_CLK_ENABLE();
/* DMA interrupt init */
HAL_NVIC_SetPriority(DMA1_Channel1_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(DMA1_Channel1_IRQn);
}
/** Configure pins as 
* Analog 
* Input 
* Output
* EVENT_OUT
* EXTI
* Free pins are configured automatically as Analog (this feature is enabled through 
* the Code Generation settings)
*/
void MX_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
/* GPIO Ports Clock Enable */
__GPIOB_CLK_ENABLE();
__GPIOF_CLK_ENABLE();
__GPIOA_CLK_ENABLE();
/*Configure GPIO pins : PB8 PB1 */
GPIO_InitStruct.Pin = GPIO_PIN_8|GPIO_PIN_1;
GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
/*Configure GPIO pins : PF0 PF1 */
GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_1;
GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOF, &GPIO_InitStruct);
/*Configure GPIO pin : LED_STS_Pin */
GPIO_InitStruct.Pin = LED_STS_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_LOW;
HAL_GPIO_Init(LED_STS_GPIO_Port, &GPIO_InitStruct);
/*Configure GPIO pins : PA5 PA6 PA7 PA9 
PA10 */
GPIO_InitStruct.Pin = GPIO_PIN_5|GPIO_PIN_6|GPIO_PIN_7|GPIO_PIN_9 
|GPIO_PIN_10;
GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
}

Walid FTITI_O
Senior II
Posted on March 10, 2016 at 15:35

Hi jeremy_cis,

Have you tried with the last version of STM32CubeMx 4.13.0 ?

-Hannibal-
engenharia2
Associate II
Posted on March 10, 2016 at 18:32

Yes Hannibal, now I can choose ADC_CLOCKPRESCALER_PCLK_DIV2 or ADC_CLOCKPRESCALER_PCLK_DIV4 in STM32CubeMX and ''sConfig.Channel'' section is configured correctly for the selected channels.

Walid FTITI_O
Senior II
Posted on March 10, 2016 at 18:54

Hi jeremy_cis, 

That's good. Thank you for your contribution.

-Hannibal-

cassianofachin
Associate
Posted on March 18, 2016 at 21:02

The original post was too long to process during our migration. Please click on the provided URL to read the original post. https://st--c.eu10.content.force.com/sfc/dist/version/download/?oid=00Db0000000YtG6&ids=0680X000006I6WS&d=%2Fa%2F0X0000000bps%2FuNMuASmoe2_AuDFedBU56JdnSn0DnKIhvKOUne3oVA8&asPdf=false
Posted on March 18, 2016 at 21:18

The Rank# enumeration must increment for each channel you add.

Tips, buy me a coffee, or three.. PayPal Venmo Up vote any posts that you find helpful, it shows what's working..
Posted on March 18, 2016 at 22:00

Be aware that editing posts changes the chronology, see earlier response to your question.

Tips, buy me a coffee, or three.. PayPal Venmo Up vote any posts that you find helpful, it shows what's working..
engenharia2
Associate II
Posted on March 29, 2016 at 21:00

Hello, I'm sorry for the delay! We did not get a notification of your question in my email. These problems and ''solutions'' that we applied have been fixed in the new version of STM32CubeMX. Please try STM32CubeMx v4.0 and Firmware Package for Family STM32F0 v1.5.0.

My read function:

void readAdcDma(TYPEDEF_ADC_CH channel) {
ADC_ChannelConfTypeDef sConfig;
HAL_ADC_Stop_DMA(&ADC_Handle);
while(HAL_ADC_DeInit(&hadc) != HAL_OK);
for(int i=0; i<ADC_BUFFER_SIZE; i++) {
adcBuffer[i] = 0x00;
}
HAL_ADC_Init(&hadc);
if(channel == ADC_CH0) {
sConfig.Channel = ADC_CHANNEL_0;
sConfig.Rank = ADC_RANK_CHANNEL_NUMBER;
sConfig.SamplingTime = ADC_SAMPLETIME_71CYCLES_5;
HAL_ADC_ConfigChannel(&hadc, &sConfig);
}
else if(channel == ADC_CH1) {
sConfig.Channel = ADC_CHANNEL_1;
sConfig.Rank = ADC_RANK_CHANNEL_NUMBER;
sConfig.SamplingTime = ADC_SAMPLETIME_71CYCLES_5;
HAL_ADC_ConfigChannel(&hadc, &sConfig);
}
else if (channel == ADC_CH2) {
sConfig.Channel = ADC_CHANNEL_2;
sConfig.Rank = ADC_RANK_CHANNEL_NUMBER;
sConfig.SamplingTime = ADC_SAMPLETIME_71CYCLES_5;
HAL_ADC_ConfigChannel(&hadc, &sConfig);
}
HAL_ADC_Start_DMA(&ADC_Handle, pADC, ADC_BUFFER_SIZE);
HAL_ADC_Start(&ADC_Handle);
//Wait for DMA copy data...
HAL_Delay(20); //Delay (((1/60Hz)/400)*500) ~= 20ms
}

My ADC init function created by STM32CubeMx 4.0:

/* ADC init function */
void MX_ADC_Init(void)
{
ADC_ChannelConfTypeDef sConfig;
/**Configure the global features of the ADC (Clock, Resolution, Data Alignment and number of conversion) 
*/
hadc.Instance = ADC1;
hadc.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4;
hadc.Init.Resolution = ADC_RESOLUTION12b;
hadc.Init.DataAlign = ADC_DATAALIGN_RIGHT;
hadc.Init.ScanConvMode = ADC_SCAN_DIRECTION_FORWARD;
hadc.Init.EOCSelection = EOC_SINGLE_CONV;
hadc.Init.LowPowerAutoWait = DISABLE;
hadc.Init.LowPowerAutoPowerOff = DISABLE;
hadc.Init.ContinuousConvMode = ENABLE;
hadc.Init.DiscontinuousConvMode = DISABLE;
hadc.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
hadc.Init.DMAContinuousRequests = DISABLE;
hadc.Init.Overrun = OVR_DATA_PRESERVED;
HAL_ADC_Init(&hadc);
/**Configure for the selected ADC regular channel to be converted. 
*/
sConfig.Channel = ADC_CHANNEL_0;
sConfig.Rank = ADC_RANK_CHANNEL_NUMBER;
sConfig.SamplingTime = ADC_SAMPLETIME_55CYCLES_5;
HAL_ADC_ConfigChannel(&hadc, &sConfig);
/**Configure for the selected ADC regular channel to be converted. 
*/
sConfig.Channel = ADC_CHANNEL_1;
HAL_ADC_ConfigChannel(&hadc, &sConfig);
/**Configure for the selected ADC regular channel to be converted. 
*/
sConfig.Channel = ADC_CHANNEL_2;
HAL_ADC_ConfigChannel(&hadc, &sConfig);
}