adc.c 28.7 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) {
D
Dave Hylands 已提交
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];
254
      mp_hal_gpio_clock_enable(pin->gpio);
D
Dave Hylands 已提交
255 256
      GPIO_InitTypeDef GPIO_InitStructure;
      GPIO_InitStructure.Pin = pin->pin_mask;
257
#if defined(STM32F4) || defined(STM32F7) || defined(STM32H7)
D
Dave Hylands 已提交
258
      GPIO_InitStructure.Mode = GPIO_MODE_ANALOG;
259
#elif defined(STM32L4)
260 261 262 263
      GPIO_InitStructure.Mode = GPIO_MODE_ANALOG_ADC_CONTROL;
#else
    #error Unsupported processor
#endif
D
Dave Hylands 已提交
264 265 266 267
      GPIO_InitStructure.Pull = GPIO_NOPULL;
      HAL_GPIO_Init(pin->gpio, &GPIO_InitStructure);
    }

268
    adcx_init_periph(&adc_obj->handle, ADC_RESOLUTION_12B);
269

270
#if defined(STM32L4)
271 272
    ADC_MultiModeTypeDef multimode;
    multimode.Mode = ADC_MODE_INDEPENDENT;
273
    if (HAL_ADCEx_MultiModeConfigChannel(&adc_obj->handle, &multimode) != HAL_OK)
274 275 276 277
    {
        nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "Can not set multimode on ADC1 channel: %d", adc_obj->channel));
    }
#endif
278
}
D
Dave Hylands 已提交
279

280
STATIC void adc_config_channel(ADC_HandleTypeDef *adc_handle, uint32_t channel) {
D
Dave Hylands 已提交
281 282
    ADC_ChannelConfTypeDef sConfig;

283
    sConfig.Channel = channel;
D
Dave Hylands 已提交
284
    sConfig.Rank = 1;
285
#if defined(STM32F4) || defined(STM32F7)
D
Dave Hylands 已提交
286
    sConfig.SamplingTime = ADC_SAMPLETIME_15CYCLES;
287 288 289 290 291 292
#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;
293
#elif defined(STM32L4)
294
    sConfig.SamplingTime = ADC_SAMPLETIME_12CYCLES_5;
295 296
    sConfig.SingleDiff = ADC_SINGLE_ENDED;
    sConfig.OffsetNumber = ADC_OFFSET_NONE;
297 298 299
#else
    #error Unsupported processor
#endif
D
Dave Hylands 已提交
300 301
    sConfig.Offset = 0;

302
    HAL_ADC_ConfigChannel(adc_handle, &sConfig);
D
Dave Hylands 已提交
303 304
}

305
STATIC uint32_t adc_read_channel(ADC_HandleTypeDef *adcHandle) {
D
Dave Hylands 已提交
306
    HAL_ADC_Start(adcHandle);
307 308
    adc_wait_for_eoc_or_timeout(EOC_TIMEOUT);
    uint32_t value = ADCx->DR;
D
Dave Hylands 已提交
309
    HAL_ADC_Stop(adcHandle);
310 311
    return value;
}
D
Dave Hylands 已提交
312

313 314 315
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 已提交
316 317 318
}

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

321
STATIC void adc_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
D
Dave Hylands 已提交
322
    pyb_obj_adc_t *self = self_in;
323 324 325
    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 已提交
326 327
}

328 329 330
/// \classmethod \constructor(pin)
/// Create an ADC object associated with the given pin.
/// This allows you to then read analog values on that pin.
331
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) {
332
    // check number of arguments
D
Damien George 已提交
333
    mp_arg_check_num(n_args, n_kw, 1, 1, false);
D
Dave Hylands 已提交
334

335 336
    // 1st argument is the pin name
    mp_obj_t pin_obj = args[0];
D
Dave Hylands 已提交
337 338 339 340

    uint32_t channel;

    if (MP_OBJ_IS_INT(pin_obj)) {
341
        channel = adc_get_internal_channel(mp_obj_get_int(pin_obj));
D
Dave Hylands 已提交
342
    } else {
343
        const pin_obj_t *pin = pin_find(pin_obj);
D
Dave Hylands 已提交
344 345
        if ((pin->adc_num & PIN_ADC1) == 0) {
            // No ADC1 function on that pin
346
            nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "pin %q does not have ADC capabilities", pin->name));
D
Dave Hylands 已提交
347 348 349 350
        }
        channel = pin->adc_channel;
    }

351
    if (!is_adcx_channel(channel)) {
352
        nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "not a valid ADC Channel: %d", channel));
D
Dave Hylands 已提交
353
    }
354 355 356 357 358 359 360 361


    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 已提交
362 363 364 365
    }

    pyb_obj_adc_t *o = m_new_obj(pyb_obj_adc_t);
    memset(o, 0, sizeof(*o));
366
    o->base.type = &pyb_adc_type;
D
Dave Hylands 已提交
367 368 369 370 371 372 373
    o->pin_name = pin_obj;
    o->channel = channel;
    adc_init_single(o);

    return o;
}

374 375 376
/// \method read()
/// Read the value on the analog pin and return it.  The returned value
/// will be between 0 and 4095.
377 378
STATIC mp_obj_t adc_read(mp_obj_t self_in) {
    pyb_obj_adc_t *self = self_in;
379
    return mp_obj_new_int(adc_config_and_read_channel(&self->handle, self->channel));
380 381 382
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(adc_read_obj, adc_read);

383
/// \method read_timed(buf, timer)
384
///
385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407
/// 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:
408 409 410 411 412 413 414 415 416
///
///     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.
417 418 419
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;

420 421
    mp_buffer_info_t bufinfo;
    mp_get_buffer_raise(buf_in, &bufinfo, MP_BUFFER_WRITE);
422
    size_t typesize = mp_binary_get_size('@', bufinfo.typecode, NULL);
423

424 425 426 427 428 429 430 431 432 433 434 435
    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);
    }
436

437
    // configure the ADC channel
438
    adc_config_channel(&self->handle, self->channel);
439 440 441 442

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

443 444
    uint nelems = bufinfo.len / typesize;
    for (uint index = 0; index < nelems; index++) {
445
        // Wait for the timer to trigger so we sample at the correct frequency
446
        while (__HAL_TIM_GET_FLAG(tim, TIM_FLAG_UPDATE) == RESET) {
447
        }
448
        __HAL_TIM_CLEAR_FLAG(tim, TIM_FLAG_UPDATE);
449 450 451 452 453 454

        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
455
#if defined(STM32F4) || defined(STM32F7)
456
            ADCx->CR2 |= (uint32_t)ADC_CR2_SWSTART;
457
#elif defined(STM32H7) || defined(STM32L4)
458 459 460 461
            SET_BIT(ADCx->CR, ADC_CR_ADSTART);
#else
            #error Unsupported processor
#endif
462 463 464
        }

        // wait for sample to complete
465
        adc_wait_for_eoc_or_timeout(EOC_TIMEOUT);
466 467 468 469 470

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

        // store value in buffer
471 472 473 474
        if (typesize == 1) {
            value >>= 4;
        }
        mp_binary_set_val_array_from_int(bufinfo.typecode, bufinfo.buf, index, value);
475 476
    }

477 478 479
    // turn the ADC off
    HAL_ADC_Stop(&self->handle);

480 481 482 483 484 485
    #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
486 487 488 489 490

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

491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515
// 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);
516
    void *bufptrs[nbufs];
517 518 519 520 521 522
    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");
        }
523
        bufptrs[array_index] = bufinfo_curr.buf;
524 525 526 527 528 529 530 531 532 533 534
    }

    // 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
535
    adc_wait_for_eoc_or_timeout(EOC_TIMEOUT);
536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566
    // 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;
567
            #elif defined(STM32H7) || defined(STM32L4)
568 569 570 571 572
            SET_BIT(ADCx->CR, ADC_CR_ADSTART);
            #else
            #error Unsupported processor
            #endif
            // wait for sample to complete
573
            adc_wait_for_eoc_or_timeout(EOC_TIMEOUT);
574 575 576 577 578 579 580 581

            // read value
            value = ADCx->DR;

            // store values in buffer
            if (typesize == 1) {
                value >>= 4;
            }
582
            mp_binary_set_val_array_from_int(bufinfo.typecode, bufptrs[array_index], elem_index, value);
583 584 585 586 587 588 589 590 591 592 593 594
        }
    }

    // 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));

595 596 597
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) },
598
    { MP_ROM_QSTR(MP_QSTR_read_timed_multi), MP_ROM_PTR(&adc_read_timed_multi_obj) },
599 600
};

601 602
STATIC MP_DEFINE_CONST_DICT(adc_locals_dict, adc_locals_dict_table);

603 604 605 606 607
const mp_obj_type_t pyb_adc_type = {
    { &mp_type_type },
    .name = MP_QSTR_ADC,
    .print = adc_print,
    .make_new = adc_make_new,
608
    .locals_dict = (mp_obj_dict_t*)&adc_locals_dict,
609
};
D
Dave Hylands 已提交
610 611 612 613

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

614
typedef struct _pyb_adc_all_obj_t {
D
Dave Hylands 已提交
615 616
    mp_obj_base_t base;
    ADC_HandleTypeDef handle;
617
} pyb_adc_all_obj_t;
D
Dave Hylands 已提交
618

619
void adc_init_all(pyb_adc_all_obj_t *adc_all, uint32_t resolution, uint32_t en_mask) {
D
Dave Hylands 已提交
620 621

    switch (resolution) {
622
        #if !defined(STM32H7)
623
        case 6:  resolution = ADC_RESOLUTION_6B;  break;
624
        #endif
625 626 627
        case 8:  resolution = ADC_RESOLUTION_8B;  break;
        case 10: resolution = ADC_RESOLUTION_10B; break;
        case 12: resolution = ADC_RESOLUTION_12B; break;
D
Dave Hylands 已提交
628
        default:
629
            nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError,
D
Dave Hylands 已提交
630 631 632
                "resolution %d not supported", resolution));
    }

633
    for (uint32_t channel = ADC_FIRST_GPIO_CHANNEL; channel <= ADC_LAST_GPIO_CHANNEL; ++channel) {
634 635 636 637 638 639 640 641 642 643 644 645 646 647
        // 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) {
                mp_hal_gpio_clock_enable(pin->gpio);
                GPIO_InitTypeDef GPIO_InitStructure;
                GPIO_InitStructure.Pin = pin->pin_mask;
                GPIO_InitStructure.Mode = GPIO_MODE_ANALOG;
                GPIO_InitStructure.Pull = GPIO_NOPULL;
                HAL_GPIO_Init(pin->gpio, &GPIO_InitStructure);
            }
        }
D
Dave Hylands 已提交
648 649
    }

650
    adcx_init_periph(&adc_all->handle, resolution);
D
Dave Hylands 已提交
651 652
}

D
Dave Hylands 已提交
653
int adc_get_resolution(ADC_HandleTypeDef *adcHandle) {
654
    uint32_t res_reg = ADC_GET_RESOLUTION(adcHandle);
D
Dave Hylands 已提交
655 656

    switch (res_reg) {
657
       #if !defined(STM32H7)
658
        case ADC_RESOLUTION_6B:  return 6;
659
        #endif
660 661
        case ADC_RESOLUTION_8B:  return 8;
        case ADC_RESOLUTION_10B: return 10;
D
Dave Hylands 已提交
662 663 664 665
    }
    return 12;
}

666
int adc_read_core_temp(ADC_HandleTypeDef *adcHandle) {
D
Dave Hylands 已提交
667
    int32_t raw_value = adc_config_and_read_channel(adcHandle, ADC_CHANNEL_TEMPSENSOR);
D
Dave Hylands 已提交
668 669 670 671 672

    // 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 已提交
673 674 675
    return ((raw_value - CORE_TEMP_V25) / CORE_TEMP_AVG_SLOPE) + 25;
}

D
Dave Hylands 已提交
676
#if MICROPY_PY_BUILTINS_FLOAT
677 678 679
// correction factor for reference value
STATIC volatile float adc_refcor = 1.0f;

680 681 682 683 684 685 686 687 688 689
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;
}

690
float adc_read_core_vbat(ADC_HandleTypeDef *adcHandle) {
D
Dave Hylands 已提交
691
    uint32_t raw_value = adc_config_and_read_channel(adcHandle, ADC_CHANNEL_VBAT);
D
Dave Hylands 已提交
692 693 694 695 696

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

697
    #if defined(STM32F4) || defined(STM32F7)
698 699 700 701 702 703 704 705 706
    // 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 已提交
707 708
}

709
float adc_read_core_vref(ADC_HandleTypeDef *adcHandle) {
D
Dave Hylands 已提交
710
    uint32_t raw_value = adc_config_and_read_channel(adcHandle, ADC_CHANNEL_VREFINT);
D
Dave Hylands 已提交
711 712 713 714 715

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

716 717 718 719
    // update the reference correction factor
    adc_refcor = ((float)(*VREFIN_CAL)) / ((float)raw_value);

    return (*VREFIN_CAL) * ADC_SCALE;
D
Dave Hylands 已提交
720
}
D
Dave Hylands 已提交
721
#endif
D
Dave Hylands 已提交
722 723

/******************************************************************************/
724
/* MicroPython bindings : adc_all object                                      */
D
Dave Hylands 已提交
725

726
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) {
727
    // check number of arguments
728
    mp_arg_check_num(n_args, n_kw, 1, 2, false);
729 730 731 732

    // make ADCAll object
    pyb_adc_all_obj_t *o = m_new_obj(pyb_adc_all_obj_t);
    o->base.type = &pyb_adc_all_type;
733 734 735 736 737 738
    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);
739 740

    return o;
D
Dave Hylands 已提交
741 742
}

743
STATIC mp_obj_t adc_all_read_channel(mp_obj_t self_in, mp_obj_t channel) {
744
    pyb_adc_all_obj_t *self = self_in;
745
    uint32_t chan = adc_get_internal_channel(mp_obj_get_int(channel));
D
Dave Hylands 已提交
746 747 748
    uint32_t data = adc_config_and_read_channel(&self->handle, chan);
    return mp_obj_new_int(data);
}
749
STATIC MP_DEFINE_CONST_FUN_OBJ_2(adc_all_read_channel_obj, adc_all_read_channel);
D
Dave Hylands 已提交
750

751
STATIC mp_obj_t adc_all_read_core_temp(mp_obj_t self_in) {
752
    pyb_adc_all_obj_t *self = self_in;
753 754 755 756
    #if MICROPY_PY_BUILTINS_FLOAT
    float data = adc_read_core_temp_float(&self->handle);
    return mp_obj_new_float(data);
    #else
D
Dave Hylands 已提交
757 758
    int data  = adc_read_core_temp(&self->handle);
    return mp_obj_new_int(data);
759
    #endif
D
Dave Hylands 已提交
760
}
761
STATIC MP_DEFINE_CONST_FUN_OBJ_1(adc_all_read_core_temp_obj, adc_all_read_core_temp);
D
Dave Hylands 已提交
762

D
Dave Hylands 已提交
763
#if MICROPY_PY_BUILTINS_FLOAT
764
STATIC mp_obj_t adc_all_read_core_vbat(mp_obj_t self_in) {
765
    pyb_adc_all_obj_t *self = self_in;
D
Dave Hylands 已提交
766 767 768
    float data = adc_read_core_vbat(&self->handle);
    return mp_obj_new_float(data);
}
769
STATIC MP_DEFINE_CONST_FUN_OBJ_1(adc_all_read_core_vbat_obj, adc_all_read_core_vbat);
D
Dave Hylands 已提交
770

771
STATIC mp_obj_t adc_all_read_core_vref(mp_obj_t self_in) {
772
    pyb_adc_all_obj_t *self = self_in;
D
Dave Hylands 已提交
773 774 775
    float data  = adc_read_core_vref(&self->handle);
    return mp_obj_new_float(data);
}
776
STATIC MP_DEFINE_CONST_FUN_OBJ_1(adc_all_read_core_vref_obj, adc_all_read_core_vref);
777 778 779 780 781 782 783

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 已提交
784
#endif
D
Dave Hylands 已提交
785

786 787 788
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 已提交
789
#if MICROPY_PY_BUILTINS_FLOAT
790 791 792
    { 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 已提交
793
#endif
D
Dave Hylands 已提交
794 795
};

796 797
STATIC MP_DEFINE_CONST_DICT(adc_all_locals_dict, adc_all_locals_dict_table);

798
const mp_obj_type_t pyb_adc_all_type = {
D
Dave Hylands 已提交
799
    { &mp_type_type },
800 801
    .name = MP_QSTR_ADCAll,
    .make_new = adc_all_make_new,
802
    .locals_dict = (mp_obj_dict_t*)&adc_all_locals_dict,
D
Dave Hylands 已提交
803
};
804 805

#endif // MICROPY_HW_ENABLE_ADC