STM32L071 ADC + DMA + Multichannels Problems
Hi all,
I am working with a custum made PCB which has a STM32L071 micro and I am facing some troubles to read multiple adc inputs via DMA (because HAL IT dondoesn't work because ADC interrupts faster than ISR can excecute).
The think is the output from the DMA is beyond 4096 values. I'd tried a lot of combinations in config without luck. I want to use HSE with 8MHz crystal PLL to 32MHz.
General struct
&sharppragma pack(push, 1)typedef struct {
uint16_t PresionAire;
uint16_t SensorHumo; uint16_t CAL_IS1; uint16_t CAL_IS2; uint16_t CAL_HUMO; uint16_t CAL_AIRE; uint16_t I_Extractor; uint16_t I_Compresor;} Sensores;
typedef struct { uint16_t Systick; uint16_t EstadoEntradas; uint8_t ExtractorEncendido; uint8_t CompresorEncendido; uint16_t CompresorHabilitado; // Variable de tiempo para apagar el compresoruint8_t Error;
uint16_t ConversorADC[8];
Sensores Analog; } General;&sharppragma pack(pop)
__IO General Gen;
int main(void){
memset((General *) &Gen, 0x00, sizeof(Gen));
HAL_Init();
Setup();
while (1){
LecturaADCs((General *) &Gen); }}void Setup(void){
ConfiguroOscilador();
HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK);
SysTick_Config(SystemCoreClock/1000);
ConfiguroIOs();
ConfiguroADC();
}void ConfiguroOscilador(void){
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
RCC_OscInitTypeDef RCC_OscInitStruct = {0};/* -2- Enable HSE Oscillator, select it as PLL source and finally activate the PLL */
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE; RCC_OscInitStruct.HSEState = RCC_HSE_ON; RCC_OscInitStruct.LSEState = RCC_LSE_OFF; RCC_OscInitStruct.HSIState = RCC_HSI_OFF; RCC_OscInitStruct.LSIState = RCC_LSI_OFF;RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL8; RCC_OscInitStruct.PLL.PLLDIV = RCC_PLL_DIV2;if (HAL_RCC_OscConfig(&RCC_OscInitStruct)!= HAL_OK){
while(1);
}/* -3- Select the PLL as system clock source and configure the HCLK, PCLK1 and PCLK2 clocks dividers */
RCC_ClkInitStruct.ClockType = (RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2); RCC_ClkInitStruct.SYSCLKSource = RCC_CFGR_SW_PLL; RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1; RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1; if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_1) != HAL_OK){ /* Initialization Error */ while(1); }__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE(); __HAL_RCC_GPIOC_CLK_ENABLE(); __HAL_RCC_ADC1_CLK_ENABLE();}
void ConfiguroIOs(void){GPIO_InitTypeDef GPIO_InitStruct;
__HAL_RCC_ADC1_CLK_ENABLE();
//********* GPIOA
GPIO_InitStruct.Pin = PIN_SENSOR_PRESION | PIN_SENSOR_HUMO | PIN_CAL_IS1 | PIN_CAL_IS2 | PIN_CAL_HUMO | PIN_CAL_AIRE; GPIO_InitStruct.Mode = GPIO_MODE_ANALOG; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);GPIO_InitStruct.Pin = PIN_I_EXTRACTOR | PIN_I_COMPRESOR;
GPIO_InitStruct.Mode = GPIO_MODE_ANALOG; HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);}
void HAL_ADC_MspInit(ADC_HandleTypeDef* hadc){
static DMA_HandleTypeDef DmaHandle;
__HAL_RCC_DMA1_CLK_ENABLE();
DmaHandle.Instance = DMA1_Channel1;
DmaHandle.Init.Direction = DMA_PERIPH_TO_MEMORY; DmaHandle.Init.PeriphInc = DMA_PINC_DISABLE; DmaHandle.Init.MemInc = DMA_MINC_ENABLE; DmaHandle.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD; DmaHandle.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD; DmaHandle.Init.Mode = DMA_NORMAL; DmaHandle.Init.Priority = DMA_PRIORITY_VERY_HIGH; DmaHandle.Init.Request = DMA_REQUEST_0; HAL_DMA_Init(&DmaHandle);/* Associate the DMA handle */
__HAL_LINKDMA(&AdcHandle, DMA_Handle, DmaHandle);/* NVIC configuration for DMA Input data interrupt */
HAL_NVIC_SetPriority(DMA1_Channel1_IRQn, 0, 0); HAL_NVIC_EnableIRQ(DMA1_Channel1_IRQn);}void ConfiguroADC(void){
AdcHandle.Instance = ADC1;if (HAL_ADC_DeInit(&AdcHandle) != HAL_OK){
HAL_Delay(100);
}AdcHandle.Init.OversamplingMode = DISABLE;
AdcHandle.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV1;
AdcHandle.Init.LowPowerAutoPowerOff = DISABLE; AdcHandle.Init.LowPowerFrequencyMode = DISABLE; AdcHandle.Init.LowPowerAutoWait = DISABLE;AdcHandle.Init.Resolution = ADC_RESOLUTION_12B;
AdcHandle.Init.SamplingTime = ADC_SAMPLETIME_12CYCLES_5; AdcHandle.Init.ScanConvMode = ADC_SCAN_DIRECTION_FORWARD; AdcHandle.Init.DataAlign = ADC_DATAALIGN_RIGHT; AdcHandle.Init.ContinuousConvMode = ENABLE; AdcHandle.Init.DiscontinuousConvMode = DISABLE; AdcHandle.Init.ExternalTrigConv = ADC_SOFTWARE_START; AdcHandle.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE; AdcHandle.Init.EOCSelection = ADC_EOC_SINGLE_SEQ_CONV; AdcHandle.Init.DMAContinuousRequests = ENABLE; if (HAL_ADC_Init(&AdcHandle) != HAL_OK){HAL_Delay(100);
} if (HAL_ADCEx_Calibration_Start(&AdcHandle, ADC_SINGLE_ENDED) != HAL_OK){HAL_Delay(100);
} sConfig.Channel = (ADC_CHANNEL_2 | ADC_CHANNEL_3 | ADC_CHANNEL_4 | ADC_CHANNEL_5 | ADC_CHANNEL_6 | ADC_CHANNEL_7 | ADC_CHANNEL_8 | ADC_CHANNEL_9);if (HAL_ADC_ConfigChannel(&AdcHandle, &sConfig) != HAL_OK){
HAL_Delay(100);
} if(HAL_ADC_Start_DMA(&AdcHandle, (uint32_t *) Gen.ConversorADC, 8) != HAL_OK){HAL_Delay(100);
}}void LecturaADCs(General *Genb){
if (!(Gen.ConversorADC[0] & 0x8000)) // Si el bit mas significativo esta en 1 hay dato
return; // Sino me voyGen.ConversorADC[0] &= 0x7FFF; // Borro flag de conversion disponible
memcpy(&Gen.Analog, Gen.ConversorADC, sizeof(Sensores));
memset(Gen.ConversorADC, 0x00, sizeof(Gen.ConversorADC));if(HAL_ADC_Start_DMA(&AdcHandle, (uint32_t *) Gen.ConversorADC, 8) != HAL_OK){
HAL_Delay(100);
NVIC_SystemReset(); }}void DMA1_Channel1_IRQHandler(void){HAL_DMA_IRQHandler(AdcHandle.DMA_Handle);
}void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* AdcHandle){
HAL_ADC_Stop_DMA(AdcHandle);
Gen.ConversorADC[0] |= 0x8000;}The values given by the DMA are out of ranges and oscillates on each conversion.Hope someone can help me.
Best regards,
Bruno
#stm-mcu #stm32l0-adc-dma #stm32l071 #stm-32lo ##stm32l0