From a554fc7a095c41f20884a28d6f86b0f970d1fdcd Mon Sep 17 00:00:00 2001 From: jflyper Date: Sun, 28 Jul 2019 01:36:21 +0900 Subject: [PATCH] [G4] ADC support --- src/main/drivers/adc.h | 17 +- src/main/drivers/adc_impl.h | 16 +- src/main/drivers/adc_stm32g4xx.c | 529 +++++++++++++++++++++++++++++++ 3 files changed, 551 insertions(+), 11 deletions(-) create mode 100644 src/main/drivers/adc_stm32g4xx.c diff --git a/src/main/drivers/adc.h b/src/main/drivers/adc.h index 081b136ba..943026b9f 100644 --- a/src/main/drivers/adc.h +++ b/src/main/drivers/adc.h @@ -46,12 +46,15 @@ typedef enum ADCDevice { ADCINVALID = -1, ADCDEV_1 = 0, -#if defined(STM32F3) || defined(STM32F4) || defined(STM32F7) || defined(STM32H7) +#if defined(STM32F3) || defined(STM32F4) || defined(STM32F7) || defined(STM32H7) || defined(STM32G4) ADCDEV_2, ADCDEV_3, #endif -#if defined(STM32F3) +#if defined(STM32F3) || defined(STM32G4) ADCDEV_4, +#endif +#if defined(STM32G4) + ADCDEV_5, #endif ADCDEV_COUNT } ADCDevice; @@ -64,8 +67,8 @@ typedef enum { ADC_CURRENT = 1, ADC_EXTERNAL1 = 2, ADC_RSSI = 3, -#ifdef STM32H7 - // On STM32H7, internal sensors are treated in the similar fashion as regular ADC inputs +#if defined(STM32H7) || defined(STM32G4) + // On H7 and G4, internal sensors are treated in the similar fashion as regular ADC inputs ADC_CHANNEL_INTERNAL = 4, ADC_TEMPSENSOR = 4, ADC_VREFINT = 5, @@ -75,11 +78,11 @@ typedef enum { typedef struct adcOperatingConfig_s { ioTag_t tag; -#ifdef STM32H7 +#if defined(STM32H7) || defined(STM32G4) ADCDevice adcDevice; // ADCDEV_x for this input - uint32_t adcChannel; // ADCy_INxx channel ID for this input + uint32_t adcChannel; // Channel number for this input. Note that H7 and G4 HAL requires this to be 32-bit encoded number. #else - uint8_t adcChannel; // ADCy_INxx channel number for this input + uint8_t adcChannel; // ADCy_INxx channel number for this input (XXX May be consolidated with uint32_t case) #endif uint8_t dmaIndex; // index into DMA buffer in case of sparse channels bool enabled; diff --git a/src/main/drivers/adc_impl.h b/src/main/drivers/adc_impl.h index c5bb25701..22c3614f6 100644 --- a/src/main/drivers/adc_impl.h +++ b/src/main/drivers/adc_impl.h @@ -33,6 +33,12 @@ #else #define ADC_TAG_MAP_COUNT 28 #endif +#elif defined(STM32G4) +#ifdef USE_ADC_INTERNAL +#define ADC_TAG_MAP_COUNT 49 +#else +#define ADC_TAG_MAP_COUNT 47 +#endif #elif defined(STM32F3) #define ADC_TAG_MAP_COUNT 39 #else @@ -45,7 +51,7 @@ typedef struct adcTagMap_s { uint8_t devices; #endif uint32_t channel; -#if defined(STM32H7) +#if defined(STM32H7) || defined(STM32G4) uint8_t channelOrdinal; #endif } adcTagMap_t; @@ -56,24 +62,26 @@ typedef struct adcTagMap_s { #define ADC_DEVICES_2 (1 << ADCDEV_2) #define ADC_DEVICES_3 (1 << ADCDEV_3) #define ADC_DEVICES_4 (1 << ADCDEV_4) +#define ADC_DEVICES_5 (1 << ADCDEV_5) #define ADC_DEVICES_12 ((1 << ADCDEV_1)|(1 << ADCDEV_2)) #define ADC_DEVICES_34 ((1 << ADCDEV_3)|(1 << ADCDEV_4)) #define ADC_DEVICES_123 ((1 << ADCDEV_1)|(1 << ADCDEV_2)|(1 << ADCDEV_3)) +#define ADC_DEVICES_345 ((1 << ADCDEV_3)|(1 << ADCDEV_4)|(1 << ADCDEV_5)) typedef struct adcDevice_s { ADC_TypeDef* ADCx; rccPeriphTag_t rccADC; #if !defined(USE_DMA_SPEC) dmaResource_t* dmaResource; -#if defined(STM32F4) || defined(STM32F7) || defined(STM32H7) +#if defined(STM32F4) || defined(STM32F7) || defined(STM32H7) || defined(STM32G4) uint32_t channel; #endif #endif // !defined(USE_DMA_SPEC) -#if defined(STM32F7) || defined(STM32H7) +#if defined(STM32F7) || defined(STM32H7) || defined(STM32G4) ADC_HandleTypeDef ADCHandle; DMA_HandleTypeDef DmaHandle; #endif -#if defined(STM32H7) +#if defined(STM32H7) || defined(STM32G4) uint8_t irq; uint32_t channelBits; #endif diff --git a/src/main/drivers/adc_stm32g4xx.c b/src/main/drivers/adc_stm32g4xx.c new file mode 100644 index 000000000..b0fa63624 --- /dev/null +++ b/src/main/drivers/adc_stm32g4xx.c @@ -0,0 +1,529 @@ +/* + * This file is part of Cleanflight and Betaflight. + * + * Cleanflight and Betaflight are free software. You can redistribute + * this software and/or modify this software under the terms of the + * GNU General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) + * any later version. + * + * Cleanflight and Betaflight are distributed in the hope that they + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software. + * + * If not, see . + */ + +#include +#include +#include + +#include "platform.h" + +#ifdef USE_ADC + +#include "build/debug.h" + +#include "drivers/dma_reqmap.h" +#include "drivers/io.h" +#include "drivers/io_impl.h" +#include "drivers/rcc.h" +#include "drivers/resource.h" +#include "drivers/dma.h" + +#include "drivers/sensor.h" + +#include "drivers/adc.h" +#include "drivers/adc_impl.h" + +#include "pg/adc.h" + +#ifndef ADC1_DMA_CHANNEL +#define ADC1_DMA_CHANNEL NULL +#endif +#ifndef ADC2_DMA_CHANNEL +#define ADC2_DMA_CHANNEL NULL +#endif +#ifndef ADC3_DMA_CHANNEL +#define ADC3_DMA_CHANNEL NULL +#endif +#ifndef ADC4_DMA_CHANNEL +#define ADC4_DMA_CHANNEL NULL +#endif +#ifndef ADC5_DMA_CHANNEL +#define ADC5_DMA_CHANNEL NULL +#endif + +const adcDevice_t adcHardware[ADCDEV_COUNT] = { + { + .ADCx = ADC1, + .rccADC = RCC_AHB2(ADC12), +#if !defined(USE_DMA_SPEC) + .dmaResource = (dmaResource_t *)ADC1_DMA_CHANNEL, + .channel = DMA_REQUEST_ADC1, +#endif + }, + { + .ADCx = ADC2, + .rccADC = RCC_AHB2(ADC12), +#if !defined(USE_DMA_SPEC) + .dmaResource = (dmaResource_t *)ADC2_DMA_CHANNEL, + .channel = DMA_REQUEST_ADC2, +#endif + }, + { + .ADCx = ADC3, + .rccADC = RCC_AHB2(ADC345), +#if !defined(USE_DMA_SPEC) + .dmaResource = (dmaResource_t *)ADC3_DMA_CHANNEL, + .channel = DMA_REQUEST_ADC3, +#endif + }, + { + .ADCx = ADC4, + .rccADC = RCC_AHB2(ADC345), +#if !defined(USE_DMA_SPEC) + .dmaResource = (dmaResource_t *)ADC3_DMA_CHANNEL, + .channel = DMA_REQUEST_ADC4, +#endif + }, + { + .ADCx = ADC5, + .rccADC = RCC_AHB2(ADC345), +#if !defined(USE_DMA_SPEC) + .dmaResource = (dmaResource_t *)ADC5_DMA_CHANNEL, + .channel = DMA_REQUEST_ADC5, +#endif + } +}; + +adcDevice_t adcDevice[ADCDEV_COUNT]; + +/* note these could be packed up for saving space */ +const adcTagMap_t adcTagMap[] = { +#ifdef USE_ADC_INTERNAL + // Pseudo entries for internal sensor. + // Keep these at the beginning for easy indexing by ADC_TAG_MAP_{VREFINT,TEMPSENSOR} +#define ADC_TAG_MAP_VREFINT 0 +#define ADC_TAG_MAP_TEMPSENSOR 1 + // VREFINT is available on all ADC instances except ADC2 + // Here, for simplicity, we force VREFINT on ADC1. + { DEFIO_TAG_E__NONE, ADC_DEVICES_1, ADC_CHANNEL_VREFINT, 18 }, + // TEMPSENSOR is available on ADC1 or ADC5 + // Here, for simplicity, we force TEMPSENSOR on ADC1. + { DEFIO_TAG_E__NONE, ADC_DEVICES_1, ADC_CHANNEL_TEMPSENSOR_ADC1, 16 }, +#endif + // Inputs available for all packages under 100 pin or smaller + + { DEFIO_TAG_E__PA0, ADC_DEVICES_12, ADC_CHANNEL_1, 1 }, + { DEFIO_TAG_E__PA1, ADC_DEVICES_12, ADC_CHANNEL_2, 2 }, + { DEFIO_TAG_E__PA2, ADC_DEVICES_1, ADC_CHANNEL_3, 3 }, + { DEFIO_TAG_E__PA3, ADC_DEVICES_1, ADC_CHANNEL_4, 4 }, + { DEFIO_TAG_E__PA4, ADC_DEVICES_2, ADC_CHANNEL_17, 17 }, + { DEFIO_TAG_E__PA5, ADC_DEVICES_2, ADC_CHANNEL_13, 13 }, + { DEFIO_TAG_E__PA6, ADC_DEVICES_2, ADC_CHANNEL_3, 3 }, + { DEFIO_TAG_E__PA7, ADC_DEVICES_2, ADC_CHANNEL_4, 4 }, + { DEFIO_TAG_E__PA8, ADC_DEVICES_5, ADC_CHANNEL_1, 1 }, + { DEFIO_TAG_E__PA9, ADC_DEVICES_5, ADC_CHANNEL_2, 2 }, + + { DEFIO_TAG_E__PB0, ADC_DEVICES_1, ADC_CHANNEL_15, 15 }, + { DEFIO_TAG_E__PB0, ADC_DEVICES_3, ADC_CHANNEL_12, 12 }, // 2nd entry + { DEFIO_TAG_E__PB1, ADC_DEVICES_1, ADC_CHANNEL_12, 12 }, + { DEFIO_TAG_E__PB1, ADC_DEVICES_3, ADC_CHANNEL_1, 1 }, // 2nd entry + { DEFIO_TAG_E__PB2, ADC_DEVICES_2, ADC_CHANNEL_12, 12 }, + { DEFIO_TAG_E__PB11, ADC_DEVICES_12, ADC_CHANNEL_14, 14 }, + { DEFIO_TAG_E__PB12, ADC_DEVICES_1, ADC_CHANNEL_11, 11 }, + { DEFIO_TAG_E__PB12, ADC_DEVICES_4, ADC_CHANNEL_3, 3 }, // 2nd entry + { DEFIO_TAG_E__PB13, ADC_DEVICES_5, ADC_CHANNEL_3, 3 }, + { DEFIO_TAG_E__PB14, ADC_DEVICES_1, ADC_CHANNEL_5, 5 }, + { DEFIO_TAG_E__PB14, ADC_DEVICES_4, ADC_CHANNEL_4, 4 }, // 2nd entry + { DEFIO_TAG_E__PB15, ADC_DEVICES_2, ADC_CHANNEL_15, 15 }, + { DEFIO_TAG_E__PB15, ADC_DEVICES_4, ADC_CHANNEL_5, 5 }, // 2nd entry + + { DEFIO_TAG_E__PC0, ADC_DEVICES_12, ADC_CHANNEL_6, 6 }, + { DEFIO_TAG_E__PC1, ADC_DEVICES_12, ADC_CHANNEL_7, 7 }, + { DEFIO_TAG_E__PC2, ADC_DEVICES_12, ADC_CHANNEL_8, 8 }, + { DEFIO_TAG_E__PC3, ADC_DEVICES_12, ADC_CHANNEL_9, 9 }, + { DEFIO_TAG_E__PC4, ADC_DEVICES_2, ADC_CHANNEL_5, 5 }, + { DEFIO_TAG_E__PC5, ADC_DEVICES_2, ADC_CHANNEL_11, 11 }, + + { DEFIO_TAG_E__PD8, ADC_DEVICES_2, ADC_CHANNEL_15, 15 }, + { DEFIO_TAG_E__PD8, ADC_DEVICES_4, ADC_CHANNEL_12, 12 }, // 2nd entry + { DEFIO_TAG_E__PD9, ADC_DEVICES_4, ADC_CHANNEL_12, 12 }, + { DEFIO_TAG_E__PD9, ADC_DEVICES_5, ADC_CHANNEL_13, 13 }, // 2nd entry + { DEFIO_TAG_E__PD10, ADC_DEVICES_345, ADC_CHANNEL_7, 7 }, + { DEFIO_TAG_E__PD11, ADC_DEVICES_345, ADC_CHANNEL_8, 8 }, + { DEFIO_TAG_E__PD12, ADC_DEVICES_345, ADC_CHANNEL_9, 9 }, + { DEFIO_TAG_E__PD13, ADC_DEVICES_345, ADC_CHANNEL_10, 10 }, + { DEFIO_TAG_E__PD14, ADC_DEVICES_345, ADC_CHANNEL_11, 11 }, + + { DEFIO_TAG_E__PE7, ADC_DEVICES_3, ADC_CHANNEL_4, 4 }, + { DEFIO_TAG_E__PE8, ADC_DEVICES_345, ADC_CHANNEL_6, 6 }, + { DEFIO_TAG_E__PE9, ADC_DEVICES_3, ADC_CHANNEL_2, 2 }, + { DEFIO_TAG_E__PE10, ADC_DEVICES_345, ADC_CHANNEL_14, 14,}, + { DEFIO_TAG_E__PE11, ADC_DEVICES_345, ADC_CHANNEL_15, 15,}, + { DEFIO_TAG_E__PE12, ADC_DEVICES_345, ADC_CHANNEL_16, 16,}, + { DEFIO_TAG_E__PE13, ADC_DEVICES_3, ADC_CHANNEL_3, 3,}, + { DEFIO_TAG_E__PE14, ADC_DEVICES_4, ADC_CHANNEL_1, 1,}, + { DEFIO_TAG_E__PE15, ADC_DEVICES_4, ADC_CHANNEL_2, 2,}, + + // Inputs available for packages larger than 100-pin are not listed +}; + +// An array to convert rank number to encoded rank code for HAL. +// Note that the table only list possible values, as rank for any single conversion +// will not exceed maximum number of input sources (ADC_CHANNEL_COUNT). +static uint32_t adcRegularRank[] = { + 0, // ranks is counted by 1-origin; dodge zero. + ADC_REGULAR_RANK_1, + ADC_REGULAR_RANK_2, + ADC_REGULAR_RANK_3, + ADC_REGULAR_RANK_4, +#ifdef USE_ADC_INTERNAL + ADC_REGULAR_RANK_5, + ADC_REGULAR_RANK_6, +#endif +}; + +static void handleError(void) +{ + while (true) { + } +} + +// Note on sampling time. +// Temperature sensor has minimum sample time of 9us. +// With prescaler = 4 at 200MHz (AHB1), fADC = 50MHz (tcycle = 0.02us), 9us = 450cycles < 810 + +void adcInitDevice(adcDevice_t *adcdev, int channelCount) +{ + ADC_HandleTypeDef *hadc = &adcdev->ADCHandle; // For clarity + + hadc->Instance = adcdev->ADCx; + + if (HAL_ADC_DeInit(hadc) != HAL_OK) + { + // ADC de-initialization Error + handleError(); + } + + hadc->Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV4; + hadc->Init.Resolution = ADC_RESOLUTION_12B; + hadc->Init.DataAlign = ADC_DATAALIGN_RIGHT; + hadc->Init.GainCompensation = 0; + hadc->Init.ScanConvMode = ADC_SCAN_ENABLE; + hadc->Init.EOCSelection = ADC_EOC_SEQ_CONV; + hadc->Init.LowPowerAutoWait = DISABLE; + hadc->Init.ContinuousConvMode = ENABLE; + hadc->Init.NbrOfConversion = channelCount; + hadc->Init.DiscontinuousConvMode = DISABLE; + hadc->Init.ExternalTrigConv = ADC_SOFTWARE_START; + hadc->Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE; + hadc->Init.DMAContinuousRequests = ENABLE; + hadc->Init.Overrun = ADC_OVR_DATA_OVERWRITTEN; + hadc->Init.OversamplingMode = DISABLE; + + if (HAL_ADC_Init(hadc) != HAL_OK) { + handleError(); + } + + // Configure the ADC multi-mode + ADC_MultiModeTypeDef multimode = { 0 }; + multimode.Mode = ADC_MODE_INDEPENDENT; + if (HAL_ADCEx_MultiModeConfigChannel(hadc, &multimode) != HAL_OK) { + handleError(); + } + + ADC_AnalogWDGConfTypeDef AnalogWDGConfig = { 0 }; + AnalogWDGConfig.Channel = ADC_CHANNEL_1; + if (HAL_ADC_AnalogWDGConfig(hadc, &AnalogWDGConfig) != HAL_OK) { + handleError(); + } + + if (HAL_ADCEx_Calibration_Start(hadc, ADC_SINGLE_ENDED) != HAL_OK) { + handleError(); + } +} + +int adcFindTagMapEntry(ioTag_t tag) +{ + for (int i = 0; i < ADC_TAG_MAP_COUNT; i++) { + if (adcTagMap[i].tag == tag) { + return i; + } + } + return -1; +} + +void adcInitCalibrationValues(void) +{ + adcVREFINTCAL = *(uint16_t *)VREFINT_CAL_ADDR; + adcTSCAL1 = *TEMPSENSOR_CAL1_ADDR; + adcTSCAL2 = *TEMPSENSOR_CAL2_ADDR; + adcTSSlopeK = (TEMPSENSOR_CAL2_TEMP - TEMPSENSOR_CAL1_TEMP) * 1000 / (adcTSCAL2 - adcTSCAL1); +} + +// ADC conversion result DMA buffer +// Need this separate from the main adcValue[] array, because channels are numbered +// by ADC instance order that is different from ADC_xxx numbering. + +volatile DMA_RAM_R uint16_t adcConversionBuffer[ADC_CHANNEL_COUNT] __attribute__((aligned(32))); + +void adcInit(const adcConfig_t *config) +{ + memset(adcOperatingConfig, 0, sizeof(adcOperatingConfig)); + memcpy(adcDevice, adcHardware, sizeof(adcDevice)); + + if (config->vbat.enabled) { + adcOperatingConfig[ADC_BATTERY].tag = config->vbat.ioTag; + } + + if (config->rssi.enabled) { + adcOperatingConfig[ADC_RSSI].tag = config->rssi.ioTag; //RSSI_ADC_CHANNEL; + } + + if (config->external1.enabled) { + adcOperatingConfig[ADC_EXTERNAL1].tag = config->external1.ioTag; //EXTERNAL1_ADC_CHANNEL; + } + + if (config->current.enabled) { + adcOperatingConfig[ADC_CURRENT].tag = config->current.ioTag; //CURRENT_METER_ADC_CHANNEL; + } + +#ifdef USE_ADC_INTERNAL + adcInitCalibrationValues(); +#endif + + for (int i = 0; i < ADC_CHANNEL_COUNT; i++) { + int map; + int dev; + + if (i == ADC_TEMPSENSOR) { + map = ADC_TAG_MAP_TEMPSENSOR; + dev = ADCDEV_1; + } else if (i == ADC_VREFINT) { + map = ADC_TAG_MAP_VREFINT; + dev = ADCDEV_1; + } else { + if (!adcOperatingConfig[i].tag) { + continue; + } + + map = adcFindTagMapEntry(adcOperatingConfig[i].tag); + if (map < 0) { + continue; + } + + // Found a tag map entry for this input pin + // Find an ADC device that can handle this input pin + + for (dev = 0; dev < ADCDEV_COUNT; dev++) { + if (!adcDevice[dev].ADCx +#ifndef USE_DMA_SPEC + || !adcDevice[dev].dmaResource +#endif + ) { + // Instance not activated + continue; + } + if (adcTagMap[map].devices & (1 << dev)) { + // Found an activated ADC instance for this input pin + break; + } + } + + if (dev == ADCDEV_COUNT) { + // No valid device found, go next channel. + continue; + } + } + + // At this point, map is an entry for the input pin and dev is a valid ADCx for the pin for input i + + adcOperatingConfig[i].adcDevice = dev; + adcOperatingConfig[i].adcChannel = adcTagMap[map].channel; + adcOperatingConfig[i].sampleTime = ADC_SAMPLETIME_640CYCLES_5; + adcOperatingConfig[i].enabled = true; + + adcDevice[dev].channelBits |= (1 << adcTagMap[map].channelOrdinal); + + // Configure a pin for ADC + if (adcOperatingConfig[i].tag) { + IOInit(IOGetByTag(adcOperatingConfig[i].tag), OWNER_ADC_BATT + i, 0); + IOConfigGPIO(IOGetByTag(adcOperatingConfig[i].tag), IO_CONFIG(GPIO_MODE_ANALOG, 0, GPIO_NOPULL)); + } + } + + // Configure ADCx with inputs + + int dmaBufferIndex = 0; + + for (int dev = 0; dev < ADCDEV_COUNT; dev++) { + adcDevice_t *adc = &adcDevice[dev]; + + if (!(adc->ADCx && adc->channelBits)) { + continue; + } + + RCC_ClockCmd(adc->rccADC, ENABLE); + + int configuredAdcChannels = BITCOUNT(adc->channelBits); + + adcInitDevice(adc, configuredAdcChannels); + + // Configure channels + + int rank = 1; + + for (int adcChan = 0; adcChan < ADC_CHANNEL_COUNT; adcChan++) { + + if (!adcOperatingConfig[adcChan].enabled) { + continue; + } + + if (adcOperatingConfig[adcChan].adcDevice != dev) { + continue; + } + + adcOperatingConfig[adcChan].dmaIndex = dmaBufferIndex++; + + ADC_ChannelConfTypeDef sConfig; + + sConfig.Channel = adcOperatingConfig[adcChan].adcChannel; /* Sampled channel number */ + sConfig.Rank = adcRegularRank[rank++]; /* Rank of sampled channel number ADCx_CHANNEL */ + sConfig.SamplingTime = ADC_SAMPLETIME_640CYCLES_5; /* Sampling time (number of clock cycles unit) */ + sConfig.SingleDiff = ADC_SINGLE_ENDED; /* Single-ended input channel */ + sConfig.OffsetNumber = ADC_OFFSET_NONE; /* No offset subtraction */ + sConfig.Offset = 0; /* Parameter discarded because offset correction is disabled */ + + if (HAL_ADC_ConfigChannel(&adc->ADCHandle, &sConfig) != HAL_OK) { + handleError(); + } + } + + // Configure DMA for this ADC peripheral + + dmaIdentifier_e dmaIdentifier; +#ifdef USE_DMA_SPEC + const dmaChannelSpec_t *dmaSpec = dmaGetChannelSpecByPeripheral(DMA_PERIPH_ADC, dev, config->dmaopt[dev]); + + if (!dmaSpec) { + return; + } + + adc->DmaHandle.Instance = (DMA_ARCH_TYPE *)dmaSpec->ref; + adc->DmaHandle.Init.Request = dmaSpec->channel; + dmaIdentifier = dmaGetIdentifier(dmaSpec->ref); +#else + dmaIdentifier = dmaGetIdentifier(adc->dmaResource); + adc->DmaHandle.Instance = (DMA_ARCH_TYPE *)adc->dmaResource; + adc->DmaHandle.Init.Request = adc->channel; +#endif + adc->DmaHandle.Init.Direction = DMA_PERIPH_TO_MEMORY; + adc->DmaHandle.Init.PeriphInc = DMA_PINC_DISABLE; + adc->DmaHandle.Init.MemInc = DMA_MINC_ENABLE; + adc->DmaHandle.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD; + adc->DmaHandle.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD; + adc->DmaHandle.Init.Mode = DMA_CIRCULAR; + adc->DmaHandle.Init.Priority = DMA_PRIORITY_MEDIUM; + + // Deinitialize & Initialize the DMA for new transfer + + HAL_DMA_DeInit(&adc->DmaHandle); + HAL_DMA_Init(&adc->DmaHandle); + + dmaInit(dmaIdentifier, OWNER_ADC, RESOURCE_INDEX(dev)); + + // Associate the DMA handle + + __HAL_LINKDMA(&adc->ADCHandle, DMA_Handle, adc->DmaHandle); + +#ifdef USE_ADC_INTERRUPT + // XXX No interrupt used, so we can skip this. + // If interrupt is needed in any case, use dmaXXX facility instead, + // using dmaIdentifier obtained above. + + // NVIC configuration for DMA Input data interrupt + + HAL_NVIC_SetPriority(DMA1_Stream1_IRQn, 1, 0); + HAL_NVIC_EnableIRQ(DMA1_Stream1_IRQn); +#endif + } + + // Start channels. + // This must be done after channel configuration is complete, as HAL_ADC_ConfigChannel + // throws an error when configuring internal channels if ADC1 or ADC2 are already enabled. + + dmaBufferIndex = 0; + + for (int dev = 0; dev < ADCDEV_COUNT; dev++) { + + adcDevice_t *adc = &adcDevice[dev]; + + if (!(adc->ADCx && adc->channelBits)) { + continue; + } + + // Start conversion in DMA mode + + if (HAL_ADC_Start_DMA(&adc->ADCHandle, (uint32_t *)&adcConversionBuffer[dmaBufferIndex], BITCOUNT(adc->channelBits)) != HAL_OK) { + handleError(); + } + + dmaBufferIndex += BITCOUNT(adc->channelBits); + } +} + +void adcGetChannelValues(void) +{ + // Transfer values in conversion buffer into adcValues[] + // Cache coherency should be maintained by MPU facility + + for (int i = 0; i < ADC_CHANNEL_INTERNAL; i++) { + if (adcOperatingConfig[i].enabled) { + adcValues[adcOperatingConfig[i].dmaIndex] = adcConversionBuffer[adcOperatingConfig[i].dmaIndex]; + } + } +} + +#ifdef USE_ADC_INTERNAL + +bool adcInternalIsBusy(void) +{ + return false; +} + +void adcInternalStartConversion(void) +{ + return; +} + +uint16_t adcInternalRead(int channel) +{ + int dmaIndex = adcOperatingConfig[channel].dmaIndex; + + return adcConversionBuffer[dmaIndex]; +} + +int adcPrivateVref = -1; +int adcPrivateTemp = -1; + +uint16_t adcInternalReadVrefint(void) +{ + uint16_t value = adcInternalRead(ADC_VREFINT); +adcPrivateVref = __HAL_ADC_CALC_VREFANALOG_VOLTAGE(value, ADC_RESOLUTION_12B); + return value; +} + +uint16_t adcInternalReadTempsensor(void) +{ + uint16_t value = adcInternalRead(ADC_TEMPSENSOR); +adcPrivateTemp = __HAL_ADC_CALC_TEMPERATURE(adcPrivateVref, value, ADC_RESOLUTION_12B); + return value; +} +#endif // USE_ADC_INTERNAL +#endif // USE_ADC