adc.c 28.0 KB
Newer Older
1
/*
2
 * This file is part of the MicroPython project, http://micropython.org/
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
 *
 * The MIT License (MIT)
 *
 * Copyright (c) 2013, 2014 Damien P. George
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

D
Dave Hylands 已提交
27 28 29
#include <stdio.h>
#include <string.h>

30 31
#include "py/runtime.h"
#include "py/binary.h"
32
#include "py/mphal.h"
D
Dave Hylands 已提交
33 34
#include "adc.h"
#include "pin.h"
35
#include "timer.h"
D
Dave Hylands 已提交
36

37 38
#if MICROPY_HW_ENABLE_ADC

39 40 41 42 43 44 45 46 47 48 49 50 51
/// \moduleref pyb
/// \class ADC - analog to digital conversion: read analog values on a pin
///
/// Usage:
///
///     adc = pyb.ADC(pin)              # create an analog object from a pin
///     val = adc.read()                # read an analog value
///
///     adc = pyb.ADCAll(resolution)    # creale an ADCAll object
///     val = adc.read_channel(channel) # read the given channel
///     val = adc.read_core_temp()      # read MCU temperature
///     val = adc.read_core_vbat()      # read MCU VBAT
///     val = adc.read_core_vref()      # read MCU VREF
D
Dave Hylands 已提交
52 53

/* ADC defintions */
54 55 56
#if defined(STM32H7)
#define ADCx                    (ADC3)
#else
D
Dave Hylands 已提交
57
#define ADCx                    (ADC1)
58
#endif
59
#define ADCx_CLK_ENABLE         __HAL_RCC_ADC1_CLK_ENABLE
D
Dave Hylands 已提交
60
#define ADC_NUM_CHANNELS        (19)
61

62
#if defined(STM32F4)
63 64 65 66

#define ADC_FIRST_GPIO_CHANNEL  (0)
#define ADC_LAST_GPIO_CHANNEL   (15)
#define ADC_CAL_ADDRESS         (0x1fff7a2a)
67 68
#define ADC_CAL1                ((uint16_t*)(ADC_CAL_ADDRESS + 2))
#define ADC_CAL2                ((uint16_t*)(ADC_CAL_ADDRESS + 4))
69

70
#elif defined(STM32F7)
71

72 73
#define ADC_FIRST_GPIO_CHANNEL  (0)
#define ADC_LAST_GPIO_CHANNEL   (15)
74 75 76 77
#if defined(STM32F722xx) || defined(STM32F723xx) || \
    defined(STM32F732xx) || defined(STM32F733xx)
#define ADC_CAL_ADDRESS         (0x1ff07a2a)
#else
78
#define ADC_CAL_ADDRESS         (0x1ff0f44a)
79 80
#endif

81 82
#define ADC_CAL1                ((uint16_t*)(ADC_CAL_ADDRESS + 2))
#define ADC_CAL2                ((uint16_t*)(ADC_CAL_ADDRESS + 4))
83

84 85 86 87 88 89 90 91 92
#elif defined(STM32H7)

#define ADC_FIRST_GPIO_CHANNEL  (0)
#define ADC_LAST_GPIO_CHANNEL   (16)
#define ADC_CAL_ADDRESS         (0x1FF1E860)
#define ADC_CAL1                ((uint16_t*)(0x1FF1E820))
#define ADC_CAL2                ((uint16_t*)(0x1FF1E840))
#define ADC_CHANNEL_VBAT        ADC_CHANNEL_VBAT_DIV4

93
#elif defined(STM32L4)
94

95 96
#define ADC_FIRST_GPIO_CHANNEL  (1)
#define ADC_LAST_GPIO_CHANNEL   (16)
97
#define ADC_CAL_ADDRESS         (0x1fff75aa)
98 99
#define ADC_CAL1                ((uint16_t*)(ADC_CAL_ADDRESS - 2))
#define ADC_CAL2                ((uint16_t*)(ADC_CAL_ADDRESS + 0x20))
100

101
#else
102

103
#error Unsupported processor
104

105
#endif
D
Dave Hylands 已提交
106 107 108

#if defined(STM32F405xx) || defined(STM32F415xx) || \
    defined(STM32F407xx) || defined(STM32F417xx) || \
109 110
    defined(STM32F401xC) || defined(STM32F401xE) || \
    defined(STM32F411xE)
D
Dave Hylands 已提交
111 112
#define VBAT_DIV (2)
#elif defined(STM32F427xx) || defined(STM32F429xx) || \
113
      defined(STM32F437xx) || defined(STM32F439xx) || \
114 115
      defined(STM32F722xx) || defined(STM32F723xx) || \
      defined(STM32F732xx) || defined(STM32F733xx) || \
R
Rami Ali 已提交
116
      defined(STM32F746xx) || defined(STM32F767xx) || \
117
      defined(STM32F769xx) || defined(STM32F446xx)
D
Dave Hylands 已提交
118
#define VBAT_DIV (4)
119 120
#elif defined(STM32H743xx)
#define VBAT_DIV (4)
121
#elif defined(STM32L475xx) || defined(STM32L476xx)
122
#define VBAT_DIV (3)
123 124
#else
#error Unsupported processor
D
Dave Hylands 已提交
125 126
#endif

127 128 129
// Timeout for waiting for end-of-conversion, in ms
#define EOC_TIMEOUT (10)

D
Dave Hylands 已提交
130 131 132 133
/* Core temperature sensor definitions */
#define CORE_TEMP_V25          (943)  /* (0.76v/3.3v)*(2^ADC resoultion) */
#define CORE_TEMP_AVG_SLOPE    (3)    /* (2.5mv/3.3v)*(2^ADC resoultion) */

134 135 136 137
// scale and calibration values for VBAT and VREF
#define ADC_SCALE (3.3f / 4095)
#define VREFIN_CAL ((uint16_t *)ADC_CAL_ADDRESS)

D
Dave Hylands 已提交
138 139 140 141 142 143 144
typedef struct _pyb_obj_adc_t {
    mp_obj_base_t base;
    mp_obj_t pin_name;
    int channel;
    ADC_HandleTypeDef handle;
} pyb_obj_adc_t;

145 146
// convert user-facing channel number into internal channel number
static inline uint32_t adc_get_internal_channel(uint32_t channel) {
147
    #if defined(STM32F4) || defined(STM32F7)
148 149 150 151 152 153 154 155 156
    // on F4 and F7 MCUs we want channel 16 to always be the TEMPSENSOR
    // (on some MCUs ADC_CHANNEL_TEMPSENSOR=16, on others it doesn't)
    if (channel == 16) {
        channel = ADC_CHANNEL_TEMPSENSOR;
    }
    #endif
    return channel;
}

157
STATIC bool is_adcx_channel(int channel) {
158 159 160
#if defined(STM32F411xE)
    // The HAL has an incorrect IS_ADC_CHANNEL macro for the F411 so we check for temp
    return IS_ADC_CHANNEL(channel) || channel == ADC_CHANNEL_TEMPSENSOR;
161
#elif defined(STM32F4) || defined(STM32F7) || defined(STM32H7)
162
    return IS_ADC_CHANNEL(channel);
163
#elif defined(STM32L4)
164 165 166 167 168 169 170 171 172 173
    ADC_HandleTypeDef handle;
    handle.Instance = ADCx;
    return IS_ADC_CHANNEL(&handle, channel);
#else
    #error Unsupported processor
#endif
}

STATIC void adc_wait_for_eoc_or_timeout(int32_t timeout) {
    uint32_t tickstart = HAL_GetTick();
174
#if defined(STM32F4) || defined(STM32F7)
175
    while ((ADCx->SR & ADC_FLAG_EOC) != ADC_FLAG_EOC) {
176
#elif defined(STM32H7) || defined(STM32L4)
177 178 179 180 181 182 183 184 185 186 187
    while (READ_BIT(ADCx->ISR, ADC_FLAG_EOC) != ADC_FLAG_EOC) {
#else
    #error Unsupported processor
#endif
        if (((HAL_GetTick() - tickstart ) > timeout)) {
            break; // timeout
        }
    }
}

STATIC void adcx_clock_enable(void) {
188
#if defined(STM32F4) || defined(STM32F7)
189
    ADCx_CLK_ENABLE();
190 191 192
#elif defined(STM32H7)
    __HAL_RCC_ADC3_CLK_ENABLE();
    __HAL_RCC_ADC_CONFIG(RCC_ADCCLKSOURCE_CLKP);
193
#elif defined(STM32L4)
194 195 196 197 198 199
    __HAL_RCC_ADC_CLK_ENABLE();
#else
    #error Unsupported processor
#endif
}

200 201 202 203 204 205 206 207 208 209 210 211 212 213 214
STATIC void adcx_init_periph(ADC_HandleTypeDef *adch, uint32_t resolution) {
    adcx_clock_enable();

    adch->Instance                   = ADCx;
    adch->Init.Resolution            = resolution;
    adch->Init.ContinuousConvMode    = DISABLE;
    adch->Init.DiscontinuousConvMode = DISABLE;
    adch->Init.NbrOfDiscConversion   = 0;
    adch->Init.NbrOfConversion       = 1;
    adch->Init.EOCSelection          = ADC_EOC_SINGLE_CONV;
    adch->Init.ExternalTrigConv      = ADC_SOFTWARE_START;
    adch->Init.ExternalTrigConvEdge  = ADC_EXTERNALTRIGCONVEDGE_NONE;
    #if defined(STM32F4) || defined(STM32F7)
    adch->Init.ClockPrescaler        = ADC_CLOCK_SYNC_PCLK_DIV2;
    adch->Init.ScanConvMode          = DISABLE;
215 216 217 218 219 220 221 222 223 224 225
    adch->Init.DataAlign             = ADC_DATAALIGN_RIGHT;
    adch->Init.DMAContinuousRequests = DISABLE;
    #elif defined(STM32H7)
    adch->Init.ClockPrescaler        = ADC_CLOCK_SYNC_PCLK_DIV4;
    adch->Init.BoostMode             = ENABLE;
    adch->Init.ScanConvMode          = DISABLE;
    adch->Init.LowPowerAutoWait      = DISABLE;
    adch->Init.Overrun               = ADC_OVR_DATA_OVERWRITTEN;
    adch->Init.OversamplingMode      = DISABLE;
    adch->Init.LeftBitShift          = ADC_LEFTBITSHIFT_NONE;
    adch->Init.ConversionDataManagement = ADC_CONVERSIONDATA_DR;
226 227 228 229 230 231
    #elif defined(STM32L4)
    adch->Init.ClockPrescaler        = ADC_CLOCK_ASYNC_DIV1;
    adch->Init.ScanConvMode          = ADC_SCAN_DISABLE;
    adch->Init.LowPowerAutoWait      = DISABLE;
    adch->Init.Overrun               = ADC_OVR_DATA_PRESERVED;
    adch->Init.OversamplingMode      = DISABLE;
232 233
    adch->Init.DataAlign             = ADC_DATAALIGN_RIGHT;
    adch->Init.DMAContinuousRequests = DISABLE;
234 235 236 237 238
    #else
    #error Unsupported processor
    #endif

    HAL_ADC_Init(adch);
239 240 241 242

    #if defined(STM32H7)
    HAL_ADCEx_Calibration_Start(adch, ADC_CALIB_OFFSET, ADC_SINGLE_ENDED);
    #endif
243 244
}

245
STATIC void adc_init_single(pyb_obj_adc_t *adc_obj) {
246
    if (!is_adcx_channel(adc_obj->channel)) {
D
Dave Hylands 已提交
247 248 249
        return;
    }

250
    if (ADC_FIRST_GPIO_CHANNEL <= adc_obj->channel && adc_obj->channel <= ADC_LAST_GPIO_CHANNEL) {
251 252 253
        // Channels 0-16 correspond to real pins. Configure the GPIO pin in ADC mode.
        const pin_obj_t *pin = pin_adc1[adc_obj->channel];
        mp_hal_pin_config(pin, MP_HAL_PIN_MODE_ADC, MP_HAL_PIN_PULL_NONE, 0);
D
Dave Hylands 已提交
254 255
    }

256
    adcx_init_periph(&adc_obj->handle, ADC_RESOLUTION_12B);
257

258
#if defined(STM32L4)
259 260
    ADC_MultiModeTypeDef multimode;
    multimode.Mode = ADC_MODE_INDEPENDENT;
261
    if (HAL_ADCEx_MultiModeConfigChannel(&adc_obj->handle, &multimode) != HAL_OK)
262 263 264 265
    {
        nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "Can not set multimode on ADC1 channel: %d", adc_obj->channel));
    }
#endif
266
}
D
Dave Hylands 已提交
267

268
STATIC void adc_config_channel(ADC_HandleTypeDef *adc_handle, uint32_t channel) {
D
Dave Hylands 已提交
269 270
    ADC_ChannelConfTypeDef sConfig;

271
    sConfig.Channel = channel;
D
Dave Hylands 已提交
272
    sConfig.Rank = 1;
273
#if defined(STM32F4) || defined(STM32F7)
D
Dave Hylands 已提交
274
    sConfig.SamplingTime = ADC_SAMPLETIME_15CYCLES;
275 276 277 278 279 280
#elif defined(STM32H7)
    sConfig.SamplingTime = ADC_SAMPLETIME_8CYCLES_5;
    sConfig.SingleDiff = ADC_SINGLE_ENDED;
    sConfig.OffsetNumber = ADC_OFFSET_NONE;
    sConfig.OffsetRightShift = DISABLE;
    sConfig.OffsetSignedSaturation = DISABLE;
281
#elif defined(STM32L4)
282
    sConfig.SamplingTime = ADC_SAMPLETIME_12CYCLES_5;
283 284
    sConfig.SingleDiff = ADC_SINGLE_ENDED;
    sConfig.OffsetNumber = ADC_OFFSET_NONE;
285 286 287
#else
    #error Unsupported processor
#endif
D
Dave Hylands 已提交
288 289
    sConfig.Offset = 0;

290
    HAL_ADC_ConfigChannel(adc_handle, &sConfig);
D
Dave Hylands 已提交
291 292
}

293
STATIC uint32_t adc_read_channel(ADC_HandleTypeDef *adcHandle) {
D
Dave Hylands 已提交
294
    HAL_ADC_Start(adcHandle);
295 296
    adc_wait_for_eoc_or_timeout(EOC_TIMEOUT);
    uint32_t value = ADCx->DR;
D
Dave Hylands 已提交
297
    HAL_ADC_Stop(adcHandle);
298 299
    return value;
}
D
Dave Hylands 已提交
300

301 302 303
STATIC uint32_t adc_config_and_read_channel(ADC_HandleTypeDef *adcHandle, uint32_t channel) {
    adc_config_channel(adcHandle, channel);
    return adc_read_channel(adcHandle);
D
Dave Hylands 已提交
304 305 306
}

/******************************************************************************/
307
/* MicroPython bindings : adc object (single channel)                         */
D
Dave Hylands 已提交
308

309
STATIC void adc_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
D
Dave Hylands 已提交
310
    pyb_obj_adc_t *self = self_in;
311 312 313
    mp_print_str(print, "<ADC on ");
    mp_obj_print_helper(print, self->pin_name, PRINT_STR);
    mp_printf(print, " channel=%lu>", self->channel);
D
Dave Hylands 已提交
314 315
}

316 317 318
/// \classmethod \constructor(pin)
/// Create an ADC object associated with the given pin.
/// This allows you to then read analog values on that pin.
319
STATIC mp_obj_t adc_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
320
    // check number of arguments
D
Damien George 已提交
321
    mp_arg_check_num(n_args, n_kw, 1, 1, false);
D
Dave Hylands 已提交
322

323 324
    // 1st argument is the pin name
    mp_obj_t pin_obj = args[0];
D
Dave Hylands 已提交
325 326 327 328

    uint32_t channel;

    if (MP_OBJ_IS_INT(pin_obj)) {
329
        channel = adc_get_internal_channel(mp_obj_get_int(pin_obj));
D
Dave Hylands 已提交
330
    } else {
331
        const pin_obj_t *pin = pin_find(pin_obj);
D
Dave Hylands 已提交
332 333
        if ((pin->adc_num & PIN_ADC1) == 0) {
            // No ADC1 function on that pin
334
            nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "pin %q does not have ADC capabilities", pin->name));
D
Dave Hylands 已提交
335 336 337 338
        }
        channel = pin->adc_channel;
    }

339
    if (!is_adcx_channel(channel)) {
340
        nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "not a valid ADC Channel: %d", channel));
D
Dave Hylands 已提交
341
    }
342 343 344 345 346 347 348 349


    if (ADC_FIRST_GPIO_CHANNEL <= channel && channel <= ADC_LAST_GPIO_CHANNEL) {
        // these channels correspond to physical GPIO ports so make sure they exist
        if (pin_adc1[channel] == NULL) {
            nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError,
                "channel %d not available on this board", channel));
        }
D
Dave Hylands 已提交
350 351 352 353
    }

    pyb_obj_adc_t *o = m_new_obj(pyb_obj_adc_t);
    memset(o, 0, sizeof(*o));
354
    o->base.type = &pyb_adc_type;
D
Dave Hylands 已提交
355 356 357 358 359 360 361
    o->pin_name = pin_obj;
    o->channel = channel;
    adc_init_single(o);

    return o;
}

362 363 364
/// \method read()
/// Read the value on the analog pin and return it.  The returned value
/// will be between 0 and 4095.
365 366
STATIC mp_obj_t adc_read(mp_obj_t self_in) {
    pyb_obj_adc_t *self = self_in;
367
    return mp_obj_new_int(adc_config_and_read_channel(&self->handle, self->channel));
368 369 370
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(adc_read_obj, adc_read);

371
/// \method read_timed(buf, timer)
372
///
373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395
/// Read analog values into `buf` at a rate set by the `timer` object.
///
/// `buf` can be bytearray or array.array for example.  The ADC values have
/// 12-bit resolution and are stored directly into `buf` if its element size is
/// 16 bits or greater.  If `buf` has only 8-bit elements (eg a bytearray) then
/// the sample resolution will be reduced to 8 bits.
///
/// `timer` should be a Timer object, and a sample is read each time the timer
/// triggers.  The timer must already be initialised and running at the desired
/// sampling frequency.
///
/// To support previous behaviour of this function, `timer` can also be an
/// integer which specifies the frequency (in Hz) to sample at.  In this case
/// Timer(6) will be automatically configured to run at the given frequency.
///
/// Example using a Timer object (preferred way):
///
///     adc = pyb.ADC(pyb.Pin.board.X19)    # create an ADC on pin X19
///     tim = pyb.Timer(6, freq=10)         # create a timer running at 10Hz
///     buf = bytearray(100)                # creat a buffer to store the samples
///     adc.read_timed(buf, tim)            # sample 100 values, taking 10s
///
/// Example using an integer for the frequency:
396 397 398 399 400 401 402 403 404
///
///     adc = pyb.ADC(pyb.Pin.board.X19)    # create an ADC on pin X19
///     buf = bytearray(100)                # create a buffer of 100 bytes
///     adc.read_timed(buf, 10)             # read analog values into buf at 10Hz
///                                         #   this will take 10 seconds to finish
///     for val in buf:                     # loop over all values
///         print(val)                      # print the value out
///
/// This function does not allocate any memory.
405 406 407
STATIC mp_obj_t adc_read_timed(mp_obj_t self_in, mp_obj_t buf_in, mp_obj_t freq_in) {
    pyb_obj_adc_t *self = self_in;

408 409
    mp_buffer_info_t bufinfo;
    mp_get_buffer_raise(buf_in, &bufinfo, MP_BUFFER_WRITE);
410
    size_t typesize = mp_binary_get_size('@', bufinfo.typecode, NULL);
411

412 413 414 415 416 417 418 419 420 421 422 423
    TIM_HandleTypeDef *tim;
    #if defined(TIM6)
    if (mp_obj_is_integer(freq_in)) {
        // freq in Hz given so init TIM6 (legacy behaviour)
        tim = timer_tim6_init(mp_obj_get_int(freq_in));
        HAL_TIM_Base_Start(tim);
    } else
    #endif
    {
        // use the supplied timer object as the sampling time base
        tim = pyb_timer_get_handle(freq_in);
    }
424

425
    // configure the ADC channel
426
    adc_config_channel(&self->handle, self->channel);
427 428 429 430

    // This uses the timer in polling mode to do the sampling
    // TODO use DMA

431 432
    uint nelems = bufinfo.len / typesize;
    for (uint index = 0; index < nelems; index++) {
433
        // Wait for the timer to trigger so we sample at the correct frequency
434
        while (__HAL_TIM_GET_FLAG(tim, TIM_FLAG_UPDATE) == RESET) {
435
        }
436
        __HAL_TIM_CLEAR_FLAG(tim, TIM_FLAG_UPDATE);
437 438 439 440 441 442

        if (index == 0) {
            // for the first sample we need to turn the ADC on
            HAL_ADC_Start(&self->handle);
        } else {
            // for subsequent samples we can just set the "start sample" bit
443
#if defined(STM32F4) || defined(STM32F7)
444
            ADCx->CR2 |= (uint32_t)ADC_CR2_SWSTART;
445
#elif defined(STM32H7) || defined(STM32L4)
446 447 448 449
            SET_BIT(ADCx->CR, ADC_CR_ADSTART);
#else
            #error Unsupported processor
#endif
450 451 452
        }

        // wait for sample to complete
453
        adc_wait_for_eoc_or_timeout(EOC_TIMEOUT);
454 455 456 457 458

        // read value
        uint value = ADCx->DR;

        // store value in buffer
459 460 461 462
        if (typesize == 1) {
            value >>= 4;
        }
        mp_binary_set_val_array_from_int(bufinfo.typecode, bufinfo.buf, index, value);
463 464
    }

465 466 467
    // turn the ADC off
    HAL_ADC_Stop(&self->handle);

468 469 470 471 472 473
    #if defined(TIM6)
    if (mp_obj_is_integer(freq_in)) {
        // stop timer if we initialised TIM6 in this function (legacy behaviour)
        HAL_TIM_Base_Stop(tim);
    }
    #endif
474 475 476 477 478

    return mp_obj_new_int(bufinfo.len);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_3(adc_read_timed_obj, adc_read_timed);

479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503
// read_timed_multi((adcx, adcy, ...), (bufx, bufy, ...), timer)
//
// Read analog values from multiple ADC's into buffers at a rate set by the
// timer.  The ADC values have 12-bit resolution and are stored directly into
// the corresponding buffer if its element size is 16 bits or greater, otherwise
// the sample resolution will be reduced to 8 bits.
//
// This function should not allocate any heap memory.
STATIC mp_obj_t adc_read_timed_multi(mp_obj_t adc_array_in, mp_obj_t buf_array_in, mp_obj_t tim_in) {
    size_t nadcs, nbufs;
    mp_obj_t *adc_array, *buf_array;
    mp_obj_get_array(adc_array_in, &nadcs, &adc_array);
    mp_obj_get_array(buf_array_in, &nbufs, &buf_array);

    if (nadcs < 1) {
        mp_raise_ValueError("need at least 1 ADC");
    }
    if (nadcs != nbufs) {
        mp_raise_ValueError("length of ADC and buffer lists differ");
    }

    // Get buf for first ADC, get word size, check other buffers match in type
    mp_buffer_info_t bufinfo;
    mp_get_buffer_raise(buf_array[0], &bufinfo, MP_BUFFER_WRITE);
    size_t typesize = mp_binary_get_size('@', bufinfo.typecode, NULL);
504
    void *bufptrs[nbufs];
505 506 507 508 509 510
    for (uint array_index = 0; array_index < nbufs; array_index++) {
        mp_buffer_info_t bufinfo_curr;
        mp_get_buffer_raise(buf_array[array_index], &bufinfo_curr, MP_BUFFER_WRITE);
        if ((bufinfo.len != bufinfo_curr.len) || (bufinfo.typecode != bufinfo_curr.typecode)) {
            mp_raise_ValueError("size and type of buffers must match");
        }
511
        bufptrs[array_index] = bufinfo_curr.buf;
512 513 514 515 516 517 518 519 520 521 522
    }

    // Use the supplied timer object as the sampling time base
    TIM_HandleTypeDef *tim;
    tim = pyb_timer_get_handle(tim_in);

    // Start adc; this is slow so wait for it to start
    pyb_obj_adc_t *adc0 = adc_array[0];
    adc_config_channel(&adc0->handle, adc0->channel);
    HAL_ADC_Start(&adc0->handle);
    // Wait for sample to complete and discard
523
    adc_wait_for_eoc_or_timeout(EOC_TIMEOUT);
524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554
    // Read (and discard) value
    uint value = ADCx->DR;

    // Ensure first sample is on a timer tick
    __HAL_TIM_CLEAR_FLAG(tim, TIM_FLAG_UPDATE);
    while (__HAL_TIM_GET_FLAG(tim, TIM_FLAG_UPDATE) == RESET) {
    }
    __HAL_TIM_CLEAR_FLAG(tim, TIM_FLAG_UPDATE);

    // Overrun check: assume success
    bool success = true;
    size_t nelems = bufinfo.len / typesize;
    for (size_t elem_index = 0; elem_index < nelems; elem_index++) {
        if (__HAL_TIM_GET_FLAG(tim, TIM_FLAG_UPDATE) != RESET) {
            // Timer has already triggered
            success = false;
        } else {
            // Wait for the timer to trigger so we sample at the correct frequency
            while (__HAL_TIM_GET_FLAG(tim, TIM_FLAG_UPDATE) == RESET) {
            }
        }
        __HAL_TIM_CLEAR_FLAG(tim, TIM_FLAG_UPDATE);

        for (size_t array_index = 0; array_index < nadcs; array_index++) {
            pyb_obj_adc_t *adc = adc_array[array_index];
            // configure the ADC channel
            adc_config_channel(&adc->handle, adc->channel);
            // for the first sample we need to turn the ADC on
            // ADC is started: set the "start sample" bit
            #if defined(STM32F4) || defined(STM32F7)
            ADCx->CR2 |= (uint32_t)ADC_CR2_SWSTART;
555
            #elif defined(STM32H7) || defined(STM32L4)
556 557 558 559 560
            SET_BIT(ADCx->CR, ADC_CR_ADSTART);
            #else
            #error Unsupported processor
            #endif
            // wait for sample to complete
561
            adc_wait_for_eoc_or_timeout(EOC_TIMEOUT);
562 563 564 565 566 567 568 569

            // read value
            value = ADCx->DR;

            // store values in buffer
            if (typesize == 1) {
                value >>= 4;
            }
570
            mp_binary_set_val_array_from_int(bufinfo.typecode, bufptrs[array_index], elem_index, value);
571 572 573 574 575 576 577 578 579 580 581 582
        }
    }

    // Turn the ADC off
    adc0 = adc_array[0];
    HAL_ADC_Stop(&adc0->handle);

    return mp_obj_new_bool(success);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_3(adc_read_timed_multi_fun_obj, adc_read_timed_multi);
STATIC MP_DEFINE_CONST_STATICMETHOD_OBJ(adc_read_timed_multi_obj, MP_ROM_PTR(&adc_read_timed_multi_fun_obj));

583 584 585
STATIC const mp_rom_map_elem_t adc_locals_dict_table[] = {
    { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&adc_read_obj) },
    { MP_ROM_QSTR(MP_QSTR_read_timed), MP_ROM_PTR(&adc_read_timed_obj) },
586
    { MP_ROM_QSTR(MP_QSTR_read_timed_multi), MP_ROM_PTR(&adc_read_timed_multi_obj) },
587 588
};

589 590
STATIC MP_DEFINE_CONST_DICT(adc_locals_dict, adc_locals_dict_table);

591 592 593 594 595
const mp_obj_type_t pyb_adc_type = {
    { &mp_type_type },
    .name = MP_QSTR_ADC,
    .print = adc_print,
    .make_new = adc_make_new,
596
    .locals_dict = (mp_obj_dict_t*)&adc_locals_dict,
597
};
D
Dave Hylands 已提交
598 599 600 601

/******************************************************************************/
/* adc all object                                                             */

602
typedef struct _pyb_adc_all_obj_t {
D
Dave Hylands 已提交
603 604
    mp_obj_base_t base;
    ADC_HandleTypeDef handle;
605
} pyb_adc_all_obj_t;
D
Dave Hylands 已提交
606

607
void adc_init_all(pyb_adc_all_obj_t *adc_all, uint32_t resolution, uint32_t en_mask) {
D
Dave Hylands 已提交
608 609

    switch (resolution) {
610
        #if !defined(STM32H7)
611
        case 6:  resolution = ADC_RESOLUTION_6B;  break;
612
        #endif
613 614 615
        case 8:  resolution = ADC_RESOLUTION_8B;  break;
        case 10: resolution = ADC_RESOLUTION_10B; break;
        case 12: resolution = ADC_RESOLUTION_12B; break;
D
Dave Hylands 已提交
616
        default:
617
            nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError,
D
Dave Hylands 已提交
618 619 620
                "resolution %d not supported", resolution));
    }

621
    for (uint32_t channel = ADC_FIRST_GPIO_CHANNEL; channel <= ADC_LAST_GPIO_CHANNEL; ++channel) {
622 623 624 625 626 627
        // only initialise those channels that are selected with the en_mask
        if (en_mask & (1 << channel)) {
            // Channels 0-16 correspond to real pins. Configure the GPIO pin in
            // ADC mode.
            const pin_obj_t *pin = pin_adc1[channel];
            if (pin) {
628
                mp_hal_pin_config(pin, MP_HAL_PIN_MODE_ADC, MP_HAL_PIN_PULL_NONE, 0);
629 630
            }
        }
D
Dave Hylands 已提交
631 632
    }

633
    adcx_init_periph(&adc_all->handle, resolution);
D
Dave Hylands 已提交
634 635
}

D
Dave Hylands 已提交
636
int adc_get_resolution(ADC_HandleTypeDef *adcHandle) {
637
    uint32_t res_reg = ADC_GET_RESOLUTION(adcHandle);
D
Dave Hylands 已提交
638 639

    switch (res_reg) {
640
       #if !defined(STM32H7)
641
        case ADC_RESOLUTION_6B:  return 6;
642
        #endif
643 644
        case ADC_RESOLUTION_8B:  return 8;
        case ADC_RESOLUTION_10B: return 10;
D
Dave Hylands 已提交
645 646 647 648
    }
    return 12;
}

649
int adc_read_core_temp(ADC_HandleTypeDef *adcHandle) {
D
Dave Hylands 已提交
650
    int32_t raw_value = adc_config_and_read_channel(adcHandle, ADC_CHANNEL_TEMPSENSOR);
D
Dave Hylands 已提交
651 652 653 654 655

    // Note: constants assume 12-bit resolution, so we scale the raw value to
    //       be 12-bits.
    raw_value <<= (12 - adc_get_resolution(adcHandle));

D
Dave Hylands 已提交
656 657 658
    return ((raw_value - CORE_TEMP_V25) / CORE_TEMP_AVG_SLOPE) + 25;
}

D
Dave Hylands 已提交
659
#if MICROPY_PY_BUILTINS_FLOAT
660 661 662
// correction factor for reference value
STATIC volatile float adc_refcor = 1.0f;

663 664 665 666 667 668 669 670 671 672
float adc_read_core_temp_float(ADC_HandleTypeDef *adcHandle) {
    int32_t raw_value = adc_config_and_read_channel(adcHandle, ADC_CHANNEL_TEMPSENSOR);

    // constants assume 12-bit resolution so we scale the raw value to 12-bits
    raw_value <<= (12 - adc_get_resolution(adcHandle));

    float core_temp_avg_slope = (*ADC_CAL2 - *ADC_CAL1) / 80.0;
    return (((float)raw_value * adc_refcor - *ADC_CAL1) / core_temp_avg_slope) + 30.0f;
}

673
float adc_read_core_vbat(ADC_HandleTypeDef *adcHandle) {
D
Dave Hylands 已提交
674
    uint32_t raw_value = adc_config_and_read_channel(adcHandle, ADC_CHANNEL_VBAT);
D
Dave Hylands 已提交
675 676 677 678 679

    // Note: constants assume 12-bit resolution, so we scale the raw value to
    //       be 12-bits.
    raw_value <<= (12 - adc_get_resolution(adcHandle));

680
    #if defined(STM32F4) || defined(STM32F7)
681 682 683 684 685 686 687 688 689
    // ST docs say that (at least on STM32F42x and STM32F43x), VBATE must
    // be disabled when TSVREFE is enabled for TEMPSENSOR and VREFINT
    // conversions to work.  VBATE is enabled by the above call to read
    // the channel, and here we disable VBATE so a subsequent call for
    // TEMPSENSOR or VREFINT works correctly.
    ADC->CCR &= ~ADC_CCR_VBATE;
    #endif

    return raw_value * VBAT_DIV * ADC_SCALE * adc_refcor;
D
Dave Hylands 已提交
690 691
}

692
float adc_read_core_vref(ADC_HandleTypeDef *adcHandle) {
D
Dave Hylands 已提交
693
    uint32_t raw_value = adc_config_and_read_channel(adcHandle, ADC_CHANNEL_VREFINT);
D
Dave Hylands 已提交
694 695 696 697 698

    // Note: constants assume 12-bit resolution, so we scale the raw value to
    //       be 12-bits.
    raw_value <<= (12 - adc_get_resolution(adcHandle));

699 700 701 702
    // update the reference correction factor
    adc_refcor = ((float)(*VREFIN_CAL)) / ((float)raw_value);

    return (*VREFIN_CAL) * ADC_SCALE;
D
Dave Hylands 已提交
703
}
D
Dave Hylands 已提交
704
#endif
D
Dave Hylands 已提交
705 706

/******************************************************************************/
707
/* MicroPython bindings : adc_all object                                      */
D
Dave Hylands 已提交
708

709
STATIC mp_obj_t adc_all_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
710
    // check number of arguments
711
    mp_arg_check_num(n_args, n_kw, 1, 2, false);
712 713 714 715

    // make ADCAll object
    pyb_adc_all_obj_t *o = m_new_obj(pyb_adc_all_obj_t);
    o->base.type = &pyb_adc_all_type;
716 717 718 719 720 721
    mp_int_t res = mp_obj_get_int(args[0]);
    uint32_t en_mask = 0xffffffff;
    if (n_args > 1) {
        en_mask =  mp_obj_get_int(args[1]);
    }
    adc_init_all(o, res, en_mask);
722 723

    return o;
D
Dave Hylands 已提交
724 725
}

726
STATIC mp_obj_t adc_all_read_channel(mp_obj_t self_in, mp_obj_t channel) {
727
    pyb_adc_all_obj_t *self = self_in;
728
    uint32_t chan = adc_get_internal_channel(mp_obj_get_int(channel));
D
Dave Hylands 已提交
729 730 731
    uint32_t data = adc_config_and_read_channel(&self->handle, chan);
    return mp_obj_new_int(data);
}
732
STATIC MP_DEFINE_CONST_FUN_OBJ_2(adc_all_read_channel_obj, adc_all_read_channel);
D
Dave Hylands 已提交
733

734
STATIC mp_obj_t adc_all_read_core_temp(mp_obj_t self_in) {
735
    pyb_adc_all_obj_t *self = self_in;
736 737 738 739
    #if MICROPY_PY_BUILTINS_FLOAT
    float data = adc_read_core_temp_float(&self->handle);
    return mp_obj_new_float(data);
    #else
D
Dave Hylands 已提交
740 741
    int data  = adc_read_core_temp(&self->handle);
    return mp_obj_new_int(data);
742
    #endif
D
Dave Hylands 已提交
743
}
744
STATIC MP_DEFINE_CONST_FUN_OBJ_1(adc_all_read_core_temp_obj, adc_all_read_core_temp);
D
Dave Hylands 已提交
745

D
Dave Hylands 已提交
746
#if MICROPY_PY_BUILTINS_FLOAT
747
STATIC mp_obj_t adc_all_read_core_vbat(mp_obj_t self_in) {
748
    pyb_adc_all_obj_t *self = self_in;
D
Dave Hylands 已提交
749 750 751
    float data = adc_read_core_vbat(&self->handle);
    return mp_obj_new_float(data);
}
752
STATIC MP_DEFINE_CONST_FUN_OBJ_1(adc_all_read_core_vbat_obj, adc_all_read_core_vbat);
D
Dave Hylands 已提交
753

754
STATIC mp_obj_t adc_all_read_core_vref(mp_obj_t self_in) {
755
    pyb_adc_all_obj_t *self = self_in;
D
Dave Hylands 已提交
756 757 758
    float data  = adc_read_core_vref(&self->handle);
    return mp_obj_new_float(data);
}
759
STATIC MP_DEFINE_CONST_FUN_OBJ_1(adc_all_read_core_vref_obj, adc_all_read_core_vref);
760 761 762 763 764 765 766

STATIC mp_obj_t adc_all_read_vref(mp_obj_t self_in) {
    pyb_adc_all_obj_t *self = self_in;
    adc_read_core_vref(&self->handle);
    return mp_obj_new_float(3.3 * adc_refcor);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(adc_all_read_vref_obj, adc_all_read_vref);
D
Dave Hylands 已提交
767
#endif
D
Dave Hylands 已提交
768

769 770 771
STATIC const mp_rom_map_elem_t adc_all_locals_dict_table[] = {
    { MP_ROM_QSTR(MP_QSTR_read_channel), MP_ROM_PTR(&adc_all_read_channel_obj) },
    { MP_ROM_QSTR(MP_QSTR_read_core_temp), MP_ROM_PTR(&adc_all_read_core_temp_obj) },
D
Dave Hylands 已提交
772
#if MICROPY_PY_BUILTINS_FLOAT
773 774 775
    { MP_ROM_QSTR(MP_QSTR_read_core_vbat), MP_ROM_PTR(&adc_all_read_core_vbat_obj) },
    { MP_ROM_QSTR(MP_QSTR_read_core_vref), MP_ROM_PTR(&adc_all_read_core_vref_obj) },
    { MP_ROM_QSTR(MP_QSTR_read_vref), MP_ROM_PTR(&adc_all_read_vref_obj) },
D
Dave Hylands 已提交
776
#endif
D
Dave Hylands 已提交
777 778
};

779 780
STATIC MP_DEFINE_CONST_DICT(adc_all_locals_dict, adc_all_locals_dict_table);

781
const mp_obj_type_t pyb_adc_all_type = {
D
Dave Hylands 已提交
782
    { &mp_type_type },
783 784
    .name = MP_QSTR_ADCAll,
    .make_new = adc_all_make_new,
785
    .locals_dict = (mp_obj_dict_t*)&adc_all_locals_dict,
D
Dave Hylands 已提交
786
};
787 788

#endif // MICROPY_HW_ENABLE_ADC