Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ADC support STM32L4xx and STM32G4xx series MCUs #22341

Merged
merged 12 commits into from
Dec 8, 2023
140 changes: 131 additions & 9 deletions platforms/chibios/drivers/analog.c
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/* Copyright 2019 Drew Mills

Check failure on line 1 in platforms/chibios/drivers/analog.c

View workflow job for this annotation

GitHub Actions / lint

Requires Formatting
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
Expand Down Expand Up @@ -31,7 +31,15 @@
#endif

#if STM32_ADCV3_OVERSAMPLING
# error "STM32 ADCV3 Oversampling is not supported at this time."
// Apparently all ADCV3 chips that support oversampling (STM32L4xx, STM32L4xx+,
// STM32G4xx, STM32WB[35]x) have errata like “Wrong ADC result if conversion
// done late after calibration or previous conversion”; the workaround is to
// perform a dummy conversion and discard its result. STM32G4xx chips also
// have the “ADC channel 0 converted instead of the required ADC channel”
// errata, one workaround for which is also to perform a dummy conversion.
# define ADC_DUMMY_CONVERSIONS_AT_START 1
#else
# define ADC_DUMMY_CONVERSIONS_AT_START 0
#endif

// Otherwise assume V3
Expand Down Expand Up @@ -76,8 +84,10 @@
#ifndef ADC_COUNT
# if defined(RP2040) || defined(STM32F0XX) || defined(STM32F1XX) || defined(STM32F4XX) || defined(GD32VF103) || defined(WB32F3G71xx) || defined(WB32FQ95xx)
# define ADC_COUNT 1
# elif defined(STM32F3XX)
# elif defined(STM32F3XX) || defined(STM32G4XX)
# define ADC_COUNT 4
# elif defined(STM32L4XX)
# define ADC_COUNT 3
# else
# error "ADC_COUNT has not been set for this ARM microcontroller."
# endif
Expand All @@ -89,13 +99,24 @@
# error "The ARM ADC implementation currently only supports reading one channel at a time."
#endif

// Add dummy conversions as extra channels (this would work only on chips that
// have multiple channel index fields instead of a channel mask, but all chips
// that need that workaround are like that).
#define ADC_REAL_NUM_CHANNELS (ADC_DUMMY_CONVERSIONS_AT_START + ADC_NUM_CHANNELS)
Cipulot marked this conversation as resolved.
Show resolved Hide resolved

#ifndef ADC_BUFFER_DEPTH
# define ADC_BUFFER_DEPTH 1
#endif

// For more sampling rate options, look at hal_adc_lld.h in ChibiOS
#ifndef ADC_SAMPLING_RATE
# define ADC_SAMPLING_RATE ADC_SMPR_SMP_1P5
# if defined(ADC_SMPR_SMP_1P5)
# define ADC_SAMPLING_RATE ADC_SMPR_SMP_1P5
# elif defined(ADC_SMPR_SMP_2P5) // STM32L4XX, STM32L4XXP, STM32G4XX, STM32WBXX
# define ADC_SAMPLING_RATE ADC_SMPR_SMP_2P5
# else
# error "Cannot determine the default ADC_SAMPLING_RATE for this MCU."
# endif
#endif

// Options are 12, 10, 8, and 6 bit.
Expand All @@ -108,21 +129,21 @@
#endif

static ADCConfig adcCfg = {};
static adcsample_t sampleBuffer[ADC_NUM_CHANNELS * ADC_BUFFER_DEPTH];
static adcsample_t sampleBuffer[ADC_REAL_NUM_CHANNELS * ADC_BUFFER_DEPTH];
Cipulot marked this conversation as resolved.
Show resolved Hide resolved

// Initialize to max number of ADCs, set to empty object to initialize all to false.
static bool adcInitialized[ADC_COUNT] = {};

// TODO: add back TR handling???
static ADCConversionGroup adcConversionGroup = {
.circular = FALSE,
.num_channels = (uint16_t)(ADC_NUM_CHANNELS),
.num_channels = (uint16_t)(ADC_REAL_NUM_CHANNELS),
Cipulot marked this conversation as resolved.
Show resolved Hide resolved
#if defined(USE_ADCV1)
.cfgr1 = ADC_CFGR1_CONT | ADC_RESOLUTION,
.smpr = ADC_SAMPLING_RATE,
#elif defined(USE_ADCV2)
# if !defined(STM32F1XX) && !defined(GD32VF103) && !defined(WB32F3G71xx) && !defined(WB32FQ95xx)
.cr2 = ADC_CR2_SWSTART, // F103 seem very unhappy with, F401 seems very unhappy without...
.cr2 = ADC_CR2_SWSTART, // F103 seem very unhappy with, F401 seems very unhappy without...
# endif
.smpr2 = ADC_SMPR2_SMP_AN0(ADC_SAMPLING_RATE) | ADC_SMPR2_SMP_AN1(ADC_SAMPLING_RATE) | ADC_SMPR2_SMP_AN2(ADC_SAMPLING_RATE) | ADC_SMPR2_SMP_AN3(ADC_SAMPLING_RATE) | ADC_SMPR2_SMP_AN4(ADC_SAMPLING_RATE) | ADC_SMPR2_SMP_AN5(ADC_SAMPLING_RATE) | ADC_SMPR2_SMP_AN6(ADC_SAMPLING_RATE) | ADC_SMPR2_SMP_AN7(ADC_SAMPLING_RATE) | ADC_SMPR2_SMP_AN8(ADC_SAMPLING_RATE) | ADC_SMPR2_SMP_AN9(ADC_SAMPLING_RATE),
.smpr1 = ADC_SMPR1_SMP_AN10(ADC_SAMPLING_RATE) | ADC_SMPR1_SMP_AN11(ADC_SAMPLING_RATE) | ADC_SMPR1_SMP_AN12(ADC_SAMPLING_RATE) | ADC_SMPR1_SMP_AN13(ADC_SAMPLING_RATE) | ADC_SMPR1_SMP_AN14(ADC_SAMPLING_RATE) | ADC_SMPR1_SMP_AN15(ADC_SAMPLING_RATE),
Expand Down Expand Up @@ -240,6 +261,103 @@
case C5: return TO_MUX( ADC_CHANNEL_IN15, 0 );
// STM32F103x[C-G] in 144-pin packages also have analog inputs on F6...F10, but they are on ADC3, and the
// ChibiOS ADC driver for STM32F1xx currently supports only ADC1, therefore these pins are not usable.
#elif defined(STM32L4XX)
case A0: return TO_MUX( ADC_CHANNEL_IN5, 0 ); // Can also be ADC2 in some cases
case A1: return TO_MUX( ADC_CHANNEL_IN6, 0 ); // Can also be ADC2 in some cases
case A2: return TO_MUX( ADC_CHANNEL_IN7, 0 ); // Can also be ADC2
case A3: return TO_MUX( ADC_CHANNEL_IN8, 0 ); // Can also be ADC2
case A4: return TO_MUX( ADC_CHANNEL_IN9, 0 ); // Can also be ADC2
case A5: return TO_MUX( ADC_CHANNEL_IN10, 0 ); // Can also be ADC2
case A6: return TO_MUX( ADC_CHANNEL_IN11, 0 ); // Can also be ADC2
case A7: return TO_MUX( ADC_CHANNEL_IN12, 0 ); // Can also be ADC2
case B0: return TO_MUX( ADC_CHANNEL_IN15, 0 ); // Can also be ADC2
case B1: return TO_MUX( ADC_CHANNEL_IN16, 0 ); // Can also be ADC2
case C0: return TO_MUX( ADC_CHANNEL_IN1, 0 ); // Can also be ADC2 or ADC3
case C1: return TO_MUX( ADC_CHANNEL_IN2, 0 ); // Can also be ADC2 or ADC3
case C2: return TO_MUX( ADC_CHANNEL_IN3, 0 ); // Can also be ADC2 or ADC3
case C3: return TO_MUX( ADC_CHANNEL_IN4, 0 ); // Can also be ADC2 or ADC3
case C4: return TO_MUX( ADC_CHANNEL_IN13, 0 ); // Can also be ADC2
case C5: return TO_MUX( ADC_CHANNEL_IN14, 0 ); // Can also be ADC2
# if STM32_ADC_USE_ADC3
Cipulot marked this conversation as resolved.
Show resolved Hide resolved
case F3: return TO_MUX( ADC_CHANNEL_IN6, 2 );
case F4: return TO_MUX( ADC_CHANNEL_IN7, 2 );
case F5: return TO_MUX( ADC_CHANNEL_IN8, 2 );
case F6: return TO_MUX( ADC_CHANNEL_IN9, 2 );
case F7: return TO_MUX( ADC_CHANNEL_IN10, 2 );
case F8: return TO_MUX( ADC_CHANNEL_IN11, 2 );
case F9: return TO_MUX( ADC_CHANNEL_IN12, 2 );
case F10: return TO_MUX( ADC_CHANNEL_IN13, 2 );
# endif
#elif defined(STM32G4XX)
# if STM32_ADC_USE_ADC1
case A0: return TO_MUX( ADC_CHANNEL_IN1, 0 );
case A1: return TO_MUX( ADC_CHANNEL_IN2, 0 );
case A2: return TO_MUX( ADC_CHANNEL_IN3, 0 );
case A3: return TO_MUX( ADC_CHANNEL_IN4, 0 );
case B0: return TO_MUX( ADC_CHANNEL_IN15, 0 );
case B1: return TO_MUX( ADC_CHANNEL_IN12, 0 );
case B11: return TO_MUX( ADC_CHANNEL_IN14, 0 );
case B12: return TO_MUX( ADC_CHANNEL_IN11, 0 );
case B14: return TO_MUX( ADC_CHANNEL_IN5, 0 );
case C0: return TO_MUX( ADC_CHANNEL_IN6, 0 );
case C1: return TO_MUX( ADC_CHANNEL_IN7, 0 );
case C2: return TO_MUX( ADC_CHANNEL_IN8, 0 );
case C3: return TO_MUX( ADC_CHANNEL_IN9, 0 );
case F0: return TO_MUX( ADC_CHANNEL_IN10, 0 );
# endif
# if STM32_ADC_USE_ADC2
case A0: return TO_MUX( ADC_CHANNEL_IN1, 1 );
case A1: return TO_MUX( ADC_CHANNEL_IN2, 1 );
case A4: return TO_MUX( ADC_CHANNEL_IN17, 1 );
case A5: return TO_MUX( ADC_CHANNEL_IN13, 1 );
Cipulot marked this conversation as resolved.
Show resolved Hide resolved
case A6: return TO_MUX( ADC_CHANNEL_IN3, 1 );
case A7: return TO_MUX( ADC_CHANNEL_IN4, 1 );
case B2: return TO_MUX( ADC_CHANNEL_IN12, 1 );
case B11: return TO_MUX( ADC_CHANNEL_IN14, 1 );
case B15: return TO_MUX( ADC_CHANNEL_IN15, 1 );
case C0: return TO_MUX( ADC_CHANNEL_IN6, 1 );
case C1: return TO_MUX( ADC_CHANNEL_IN7, 1 );
case C2: return TO_MUX( ADC_CHANNEL_IN8, 1 );
case C3: return TO_MUX( ADC_CHANNEL_IN9, 1 );
case C4: return TO_MUX( ADC_CHANNEL_IN5, 1 );
case C5: return TO_MUX( ADC_CHANNEL_IN11, 1 );
case F1: return TO_MUX( ADC_CHANNEL_IN10, 1 );
# endif
# if STM32_ADC_USE_ADC3
case B0: return TO_MUX( ADC_CHANNEL_IN12, 2 );
case B1: return TO_MUX( ADC_CHANNEL_IN1, 2 );
case B13: return TO_MUX( ADC_CHANNEL_IN5, 2 );
case D10: return TO_MUX( ADC_CHANNEL_IN7, 2 );
case D11: return TO_MUX( ADC_CHANNEL_IN8, 2 );
case D12: return TO_MUX( ADC_CHANNEL_IN9, 2 );
case D13: return TO_MUX( ADC_CHANNEL_IN10, 2 );
case D14: return TO_MUX( ADC_CHANNEL_IN11, 2 );
case E7: return TO_MUX( ADC_CHANNEL_IN4, 2 );
case E8: return TO_MUX( ADC_CHANNEL_IN6, 2 );
case E9: return TO_MUX( ADC_CHANNEL_IN2, 2 );
case E10: return TO_MUX( ADC_CHANNEL_IN14, 2 );
case E11: return TO_MUX( ADC_CHANNEL_IN15, 2 );
case E12: return TO_MUX( ADC_CHANNEL_IN16, 2 );
case E13: return TO_MUX( ADC_CHANNEL_IN3, 2 );
# endif
# if STM32_ADC_USE_ADC4
case B12: return TO_MUX( ADC_CHANNEL_IN3, 3 );
case B14: return TO_MUX( ADC_CHANNEL_IN4, 3 );
case B15: return TO_MUX( ADC_CHANNEL_IN5, 3 );
case D8: return TO_MUX( ADC_CHANNEL_IN12, 3 );
case D9: return TO_MUX( ADC_CHANNEL_IN13, 3 );
case D10: return TO_MUX( ADC_CHANNEL_IN7, 3 );
case D11: return TO_MUX( ADC_CHANNEL_IN8, 3 );
case D12: return TO_MUX( ADC_CHANNEL_IN9, 3 );
case D13: return TO_MUX( ADC_CHANNEL_IN10, 3 );
case D14: return TO_MUX( ADC_CHANNEL_IN11, 3 );
case E5: return TO_MUX( ADC_CHANNEL_IN2, 3 );
case E8: return TO_MUX( ADC_CHANNEL_IN6, 3 );
case E10: return TO_MUX( ADC_CHANNEL_IN14, 3 );
case E11: return TO_MUX( ADC_CHANNEL_IN15, 3 );
case E12: return TO_MUX( ADC_CHANNEL_IN16, 3 );
case E14: return TO_MUX( ADC_CHANNEL_IN1, 3 );
# endif
#elif defined(RP2040)
case 26U: return TO_MUX(0, 0);
case 27U: return TO_MUX(1, 0);
Expand Down Expand Up @@ -306,7 +424,11 @@
#elif defined(RP2040)
adcConversionGroup.channel_mask = 1 << mux.input;
#else
adcConversionGroup.sqr[0] = ADC_SQR1_SQ1_N(mux.input);
adcConversionGroup.sqr[0] = ADC_SQR1_SQ1_N(mux.input)
# if ADC_DUMMY_CONVERSIONS_AT_START >= 1
| ADC_SQR1_SQ2_N(mux.input)
# endif
;
#endif

ADCDriver* targetDriver = intToADCDriver(mux.adc);
Expand All @@ -321,9 +443,9 @@

#if defined(USE_ADCV2) || defined(RP2040)
// fake 12-bit -> N-bit scale
return (*sampleBuffer) >> (12 - ADC_RESOLUTION);
return (sampleBuffer[ADC_DUMMY_CONVERSIONS_AT_START]) >> (12 - ADC_RESOLUTION);
#else
// already handled as part of adcConvert
return *sampleBuffer;
return sampleBuffer[ADC_DUMMY_CONVERSIONS_AT_START];
#endif
}
Loading