summaryrefslogtreecommitdiffstatshomepage
path: root/ports/stm32/adc.c
diff options
context:
space:
mode:
Diffstat (limited to 'ports/stm32/adc.c')
-rw-r--r--ports/stm32/adc.c93
1 files changed, 56 insertions, 37 deletions
diff --git a/ports/stm32/adc.c b/ports/stm32/adc.c
index 3549fc29a9..f47e9eaad7 100644
--- a/ports/stm32/adc.c
+++ b/ports/stm32/adc.c
@@ -51,7 +51,7 @@
/// val = adc.read_core_vref() # read MCU VREF
/* ADC definitions */
-#if defined(STM32H5)
+#if defined(STM32H5) || defined(STM32N6)
// STM32H5 features two ADC instances, ADCx and pin_adc_table are set dynamically
#define PIN_ADC_MASK (PIN_ADC1 | PIN_ADC2)
#else
@@ -107,12 +107,12 @@
#define ADC_CAL2 ((uint16_t *)(ADC_CAL_ADDRESS + 4))
#define ADC_CAL_BITS (12)
-#elif defined(STM32G0) || defined(STM32G4) || defined(STM32H5)
+#elif defined(STM32G0) || defined(STM32G4) || defined(STM32H5) || defined(STM32L1) || defined(STM32L4) || defined(STM32N6) || defined(STM32WB)
#define ADC_SCALE_V (((float)VREFINT_CAL_VREF) / 1000.0f)
-#define ADC_CAL_ADDRESS VREFINT_CAL_ADDR
-#define ADC_CAL1 TEMPSENSOR_CAL1_ADDR
-#define ADC_CAL2 TEMPSENSOR_CAL2_ADDR
+#define ADC_CAL_ADDRESS (VREFINT_CAL_ADDR)
+#define ADC_CAL1 (TEMPSENSOR_CAL1_ADDR)
+#define ADC_CAL2 (TEMPSENSOR_CAL2_ADDR)
#define ADC_CAL_BITS (12) // UM2319/UM2570, __HAL_ADC_CALC_TEMPERATURE: 'corresponds to a resolution of 12 bits'
#elif defined(STM32H7)
@@ -123,22 +123,6 @@
#define ADC_CAL2 ((uint16_t *)(0x1FF1E840))
#define ADC_CAL_BITS (16)
-#elif defined(STM32L1)
-
-#define ADC_SCALE_V (VREFINT_CAL_VREF / 1000.0f)
-#define ADC_CAL_ADDRESS (VREFINT_CAL_ADDR)
-#define ADC_CAL1 (TEMPSENSOR_CAL1_ADDR)
-#define ADC_CAL2 (TEMPSENSOR_CAL2_ADDR)
-#define ADC_CAL_BITS (12)
-
-#elif defined(STM32L4) || defined(STM32WB)
-
-#define ADC_SCALE_V (VREFINT_CAL_VREF / 1000.0f)
-#define ADC_CAL_ADDRESS (VREFINT_CAL_ADDR)
-#define ADC_CAL1 (TEMPSENSOR_CAL1_ADDR)
-#define ADC_CAL2 (TEMPSENSOR_CAL2_ADDR)
-#define ADC_CAL_BITS (12)
-
#else
#error Unsupported processor
@@ -182,6 +166,9 @@
#define VBAT_DIV (3)
#elif defined(STM32L152xE)
// STM32L152xE does not have vbat.
+#elif defined(STM32N6)
+// ADC2 VINP 16
+#define VBAT_DIV (4)
#else
#error Unsupported processor
#endif
@@ -263,7 +250,7 @@ static bool is_adcx_channel(int channel) {
handle.Instance = ADCx;
return __HAL_ADC_IS_CHANNEL_INTERNAL(channel)
|| IS_ADC_CHANNEL(&handle, __HAL_ADC_DECIMAL_NB_TO_CHANNEL(channel));
- #elif defined(STM32H5)
+ #elif defined(STM32H5) || defined(STM32N6)
// The first argument to the IS_ADC_CHANNEL macro is unused.
return __HAL_ADC_IS_CHANNEL_INTERNAL(channel)
|| IS_ADC_CHANNEL(NULL, __HAL_ADC_DECIMAL_NB_TO_CHANNEL(channel));
@@ -276,7 +263,7 @@ static void adc_wait_for_eoc_or_timeout(ADC_HandleTypeDef *adcHandle, int32_t ti
uint32_t tickstart = HAL_GetTick();
#if defined(STM32F4) || defined(STM32F7) || defined(STM32L1)
while ((adcHandle->Instance->SR & ADC_FLAG_EOC) != ADC_FLAG_EOC) {
- #elif defined(STM32F0) || defined(STM32G0) || defined(STM32G4) || defined(STM32H5) || defined(STM32H7) || defined(STM32L4) || defined(STM32WB)
+ #elif defined(STM32F0) || defined(STM32G0) || defined(STM32G4) || defined(STM32H5) || defined(STM32H7) || defined(STM32L4) || defined(STM32N6) || defined(STM32WB)
while (READ_BIT(adcHandle->Instance->ISR, ADC_FLAG_EOC) != ADC_FLAG_EOC) {
#else
#error Unsupported processor
@@ -295,7 +282,7 @@ static void adcx_clock_enable(ADC_HandleTypeDef *adch) {
__HAL_RCC_ADC_CONFIG(RCC_ADCCLKSOURCE_CLKP);
#elif defined(STM32G0)
__HAL_RCC_ADC_CLK_ENABLE();
- #elif defined(STM32G4)
+ #elif defined(STM32G4) || defined(STM32N6)
__HAL_RCC_ADC12_CLK_ENABLE();
#elif defined(STM32H5)
__HAL_RCC_ADC_CLK_ENABLE();
@@ -368,6 +355,15 @@ static void adcx_init_periph(ADC_HandleTypeDef *adch, uint32_t resolution) {
adch->Init.OversamplingMode = DISABLE;
adch->Init.DataAlign = ADC_DATAALIGN_RIGHT;
adch->Init.DMAContinuousRequests = DISABLE;
+ #elif defined(STM32N6)
+ adch->Init.GainCompensation = 0;
+ adch->Init.ScanConvMode = ADC_SCAN_DISABLE;
+ adch->Init.LowPowerAutoWait = DISABLE;
+ adch->Init.SamplingMode = ADC_SAMPLING_MODE_NORMAL;
+ adch->Init.ConversionDataManagement = ADC_CONVERSIONDATA_DR;
+ adch->Init.Overrun = ADC_OVR_DATA_OVERWRITTEN;
+ adch->Init.LeftBitShift = ADC_LEFTBITSHIFT_NONE;
+ adch->Init.OversamplingMode = DISABLE;
#else
#error Unsupported processor
#endif
@@ -400,7 +396,7 @@ static void adc_init_single(pyb_obj_adc_t *adc_obj, ADC_TypeDef *adc) {
static void adc_config_channel(ADC_HandleTypeDef *adc_handle, uint32_t channel) {
ADC_ChannelConfTypeDef sConfig;
- #if defined(STM32G0) || defined(STM32G4) || defined(STM32H5) || defined(STM32H7) || defined(STM32L4) || defined(STM32WB)
+ #if defined(STM32G0) || defined(STM32G4) || defined(STM32H5) || defined(STM32H7) || defined(STM32L4) || defined(STM32N6) || defined(STM32WB)
sConfig.Rank = ADC_REGULAR_RANK_1;
if (__HAL_ADC_IS_CHANNEL_INTERNAL(channel) == 0) {
channel = __HAL_ADC_DECIMAL_NB_TO_CHANNEL(channel);
@@ -432,7 +428,7 @@ static void adc_config_channel(ADC_HandleTypeDef *adc_handle, uint32_t channel)
if (__HAL_ADC_IS_CHANNEL_INTERNAL(channel)) {
sConfig.SamplingTime = ADC_SAMPLETIME_384CYCLES;
} else {
- sConfig.SamplingTime = ADC_SAMPLETIME_384CYCLES;
+ sConfig.SamplingTime = ADC_SAMPLETIME_16CYCLES;
}
#elif defined(STM32G0)
if (__HAL_ADC_IS_CHANNEL_INTERNAL(channel)) {
@@ -449,6 +445,18 @@ static void adc_config_channel(ADC_HandleTypeDef *adc_handle, uint32_t channel)
sConfig.SingleDiff = ADC_SINGLE_ENDED;
sConfig.OffsetNumber = ADC_OFFSET_NONE;
sConfig.Offset = 0;
+ #elif defined(STM32N6)
+ if (__HAL_ADC_IS_CHANNEL_INTERNAL(channel)) {
+ sConfig.SamplingTime = ADC_SAMPLETIME_246CYCLES_5;
+ } else {
+ sConfig.SamplingTime = ADC_SAMPLETIME_11CYCLES_5;
+ }
+ sConfig.SingleDiff = ADC_SINGLE_ENDED;
+ sConfig.OffsetNumber = ADC_OFFSET_NONE;
+ sConfig.Offset = 0;
+ sConfig.OffsetSignedSaturation = DISABLE;
+ sConfig.OffsetSaturation = DISABLE;
+ sConfig.OffsetSign = ADC_OFFSET_SIGN_POSITIVE;
#else
#error Unsupported processor
#endif
@@ -464,10 +472,13 @@ static void adc_config_channel(ADC_HandleTypeDef *adc_handle, uint32_t channel)
static uint32_t adc_read_channel(ADC_HandleTypeDef *adcHandle) {
uint32_t value;
- #if defined(STM32G4)
- // For STM32G4 there is errata 2.7.7, "Wrong ADC result if conversion done late after
- // calibration or previous conversion". According to the errata, this can be avoided
- // by performing two consecutive ADC conversions and keeping the second result.
+ #if defined(STM32G4) || defined(STM32WB)
+ // For STM32G4 errata 2.7.7 / STM32WB errata 2.7.1:
+ // "Wrong ADC result if conversion done late after calibration or previous conversion"
+ // states an incorrect reading is returned if more than 1ms has elapsed since the last
+ // reading or calibration. According to the errata, this can be avoided by performing
+ // two consecutive ADC conversions and keeping the second result.
+ // Note: On STM32WB55 @ 64Mhz each ADC read takes ~ 3us.
for (uint8_t i = 0; i < 2; i++)
#endif
{
@@ -523,7 +534,7 @@ static mp_obj_t adc_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_
// 1st argument is the pin name
mp_obj_t pin_obj = args[0];
- #if defined(STM32H5)
+ #if defined(STM32H5) || defined(STM32N6)
// STM32H5 has two ADC instances where some pins are only available on ADC1 or ADC2 (but not both).
// Assume we're using a channel of ADC1. Can be overridden for ADC2 later in this function.
ADC_TypeDef *adc = ADC1;
@@ -540,7 +551,7 @@ static mp_obj_t adc_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_
// No ADC function on the given pin.
mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("Pin(%q) doesn't have ADC capabilities"), pin->name);
}
- #if defined(STM32H5)
+ #if defined(STM32H5) || defined(STM32N6)
if ((pin->adc_num & PIN_ADC2) == PIN_ADC2) {
adc = ADC2;
pin_adc_table = pin_adc2;
@@ -555,7 +566,7 @@ static mp_obj_t adc_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_
}
// If this channel corresponds to a pin then configure the pin in ADC mode.
- #if defined(STM32H5)
+ #if defined(STM32H5) || defined(STM32N6)
if (channel < num_adc_pins) {
const machine_pin_obj_t *pin = pin_adc_table[channel];
if (pin != NULL) {
@@ -576,7 +587,7 @@ static mp_obj_t adc_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_
o->base.type = &pyb_adc_type;
o->pin_name = pin_obj;
o->channel = channel;
- #if defined(STM32H5)
+ #if defined(STM32H5) || defined(STM32N6)
adc_init_single(o, adc);
#else
adc_init_single(o, ADCx);
@@ -667,7 +678,7 @@ static mp_obj_t adc_read_timed(mp_obj_t self_in, mp_obj_t buf_in, mp_obj_t freq_
// for subsequent samples we can just set the "start sample" bit
#if defined(STM32F4) || defined(STM32F7) || defined(STM32L1)
self->handle.Instance->CR2 |= (uint32_t)ADC_CR2_SWSTART;
- #elif defined(STM32F0) || defined(STM32G0) || defined(STM32G4) || defined(STM32H5) || defined(STM32H7) || defined(STM32L4) || defined(STM32WB)
+ #elif defined(STM32F0) || defined(STM32G0) || defined(STM32G4) || defined(STM32H5) || defined(STM32H7) || defined(STM32L4) || defined(STM32N6) || defined(STM32WB)
SET_BIT(self->handle.Instance->CR, ADC_CR_ADSTART);
#else
#error Unsupported processor
@@ -777,7 +788,7 @@ static mp_obj_t adc_read_timed_multi(mp_obj_t adc_array_in, mp_obj_t buf_array_i
// ADC is started: set the "start sample" bit
#if defined(STM32F4) || defined(STM32F7) || defined(STM32L1)
adc->handle.Instance->CR2 |= (uint32_t)ADC_CR2_SWSTART;
- #elif defined(STM32F0) || defined(STM32G0) || defined(STM32G4) || defined(STM32H5) || defined(STM32H7) || defined(STM32L4) || defined(STM32WB)
+ #elif defined(STM32F0) || defined(STM32G0) || defined(STM32G4) || defined(STM32H5) || defined(STM32H7) || defined(STM32L4) || defined(STM32N6) || defined(STM32WB)
SET_BIT(adc->handle.Instance->CR, ADC_CR_ADSTART);
#else
#error Unsupported processor
@@ -911,6 +922,8 @@ int adc_read_core_temp(ADC_HandleTypeDef *adcHandle) {
} else {
return 0;
}
+ #elif defined(STM32N6)
+ int32_t raw_value = 0; // TODO
#else
int32_t raw_value = adc_config_and_read_ref(adcHandle, ADC_CHANNEL_TEMPSENSOR);
#endif
@@ -922,6 +935,10 @@ int adc_read_core_temp(ADC_HandleTypeDef *adcHandle) {
static volatile float adc_refcor = 1.0f;
float adc_read_core_temp_float(ADC_HandleTypeDef *adcHandle) {
+ #if defined(STM32N6)
+ return 0.0f; // TODO
+ #else
+
#if defined(STM32G4) || defined(STM32L1) || defined(STM32L4)
// Update the reference correction factor before reading tempsensor
// because TS_CAL1 and TS_CAL2 of STM32G4,L1/L4 are at VDDA=3.0V
@@ -936,7 +953,7 @@ float adc_read_core_temp_float(ADC_HandleTypeDef *adcHandle) {
return 0;
}
float core_temp_avg_slope = (*ADC_CAL2 - *ADC_CAL1) / 100.0f;
- #elif defined(STM32H5)
+ #elif defined(STM32H5) || defined(STM32WB)
int32_t raw_value = adc_config_and_read_ref(adcHandle, ADC_CHANNEL_TEMPSENSOR);
float core_temp_avg_slope = (*ADC_CAL2 - *ADC_CAL1) / 100.0f;
#else
@@ -944,6 +961,8 @@ float adc_read_core_temp_float(ADC_HandleTypeDef *adcHandle) {
float core_temp_avg_slope = (*ADC_CAL2 - *ADC_CAL1) / 80.0f;
#endif
return (((float)raw_value * adc_refcor - *ADC_CAL1) / core_temp_avg_slope) + 30.0f;
+
+ #endif
}
float adc_read_core_vbat(ADC_HandleTypeDef *adcHandle) {