diff options
| author | Philipp Ebensberger <philipp.ebensberger@3bricks-software.de> | 2021-04-24 21:34:07 +0200 |
|---|---|---|
| committer | Damien George <damien@micropython.org> | 2021-06-04 00:51:58 +1000 |
| commit | b8c65b174f95c1fa1117d4f307a1c5a450607e33 (patch) | |
| tree | b4b8eac44b72b8084f2c01eb071e9eaaa9c0065e | |
| parent | bbdc98f72e019ef1370add51a3ad9ec991bfbc40 (diff) | |
mimxrt/machine_adc: Add the ADC class to the machine module.
This adds the machine.ADC class with the read_u16() method. make-pins.py
and supporting files are updated to generate ADC information.
| -rw-r--r-- | ports/mimxrt/Makefile | 7 | ||||
| -rw-r--r-- | ports/mimxrt/board_init.c | 3 | ||||
| -rw-r--r-- | ports/mimxrt/boards/make-pins.py | 54 | ||||
| -rw-r--r-- | ports/mimxrt/boards/mimxrt_prefix.c | 12 | ||||
| -rw-r--r-- | ports/mimxrt/machine_adc.c | 145 | ||||
| -rw-r--r-- | ports/mimxrt/modmachine.c | 1 | ||||
| -rw-r--r-- | ports/mimxrt/modmachine.h | 2 | ||||
| -rw-r--r-- | ports/mimxrt/pin.h | 11 |
8 files changed, 223 insertions, 12 deletions
diff --git a/ports/mimxrt/Makefile b/ports/mimxrt/Makefile index de7b9fd3e..cacbcc1a3 100644 --- a/ports/mimxrt/Makefile +++ b/ports/mimxrt/Makefile @@ -111,10 +111,11 @@ SRC_TINYUSB_C += \ lib/tinyusb/src/class/vendor/vendor_device.c \ lib/tinyusb/src/portable/nxp/transdimension/dcd_transdimension.c -SRC_TINYUSB_IMX_C += \ +SRC_HAL_IMX_C += \ $(MCU_DIR)/system_$(MCU_SERIES).c \ $(MCU_DIR)/xip/fsl_flexspi_nor_boot.c \ $(MCU_DIR)/project_template/clock_config.c \ + $(MCU_DIR)/drivers/fsl_adc.c \ $(MCU_DIR)/drivers/fsl_clock.c \ $(MCU_DIR)/drivers/fsl_gpio.c \ $(MCU_DIR)/drivers/fsl_gpt.c \ @@ -134,6 +135,7 @@ SRC_C = \ tusb_port.c \ board_init.c \ $(BOARD_DIR)/flash_config.c \ + machine_adc.c \ machine_led.c \ machine_pin.c \ machine_rtc.c \ @@ -155,7 +157,7 @@ SRC_C = \ drivers/bus/softspi.c \ extmod/modonewire.c \ $(SRC_TINYUSB_C) \ - $(SRC_TINYUSB_IMX_C) \ + $(SRC_HAL_IMX_C) \ ifeq ($(MICROPY_FLOAT_IMPL),double) LIBM_SRC_C += $(addprefix lib/libm_dbl/,\ @@ -256,6 +258,7 @@ SRC_S = lib/utils/gchelper_m3.s \ # List of sources for qstr extraction SRC_QSTR += \ + machine_adc.c \ machine_led.c \ machine_pin.c \ machine_rtc.c \ diff --git a/ports/mimxrt/board_init.c b/ports/mimxrt/board_init.c index 01f6848ea..65024ff3e 100644 --- a/ports/mimxrt/board_init.c +++ b/ports/mimxrt/board_init.c @@ -80,6 +80,9 @@ void board_init(void) { // CLOCK_EnableUsbhs1PhyPllClock(kCLOCK_Usbphy480M, 480000000U); // CLOCK_EnableUsbhs1Clock(kCLOCK_Usb480M, 480000000U); + // ADC + machine_adc_init(); + // PIT machine_timer_init_PIT(); } diff --git a/ports/mimxrt/boards/make-pins.py b/ports/mimxrt/boards/make-pins.py index 5e5b81e31..e9e32a504 100644 --- a/ports/mimxrt/boards/make-pins.py +++ b/ports/mimxrt/boards/make-pins.py @@ -6,9 +6,11 @@ from __future__ import print_function import argparse import sys import csv +import re SUPPORTED_AFS = {"GPIO"} MAX_AF = 10 # AF0 .. AF9 +ADC_COL = 11 def parse_pad(pad_str): @@ -38,7 +40,7 @@ class Pin(object): self.gpio = gpio self.pin = pin self.alt_fn = [] - self.adc_channel = 0 + self.adc_fns = [] self.board_pin = False def set_is_board_pin(self): @@ -48,7 +50,13 @@ class Pin(object): return self.board_pin def parse_adc(self, adc_str): - pass + adc_regex = r"ADC(?P<instance>\d*)_IN(?P<channel>\d*)" + + matches = re.finditer(adc_regex, adc_str, re.MULTILINE) + for match in matches: + self.adc_fns.append( + AdcFunction(instance=match.group("instance"), channel=match.group("channel")) + ) def parse_af(self, af_idx, af_strs_in): pass @@ -69,14 +77,34 @@ class Pin(object): else: raise ValueError("Pin '{}' has no alternative functions".format(self.name)) + def print_pin_adc(self): + if self.adc_fns: + print( + "static const machine_pin_adc_obj_t pin_{0}_adc[{1}] = {{".format( + self.name, len(self.adc_fns) + ) + ) + for adc_fn in self.adc_fns: + adc_fn.print() + print("};") + def print(self): if self.alt_fn: self.print_pin_af() - print( - "const machine_pin_obj_t pin_{0} = PIN({0}, {1}, {2}, pin_{3});\n".format( - self.name, self.gpio, int(self.pin), self.name + "_af" + self.print_pin_adc() + + if self.adc_fns: + print( + "const machine_pin_obj_t pin_{0} = PIN({0}, {1}, {2}, pin_{0}_af, {3}, pin_{0}_adc);\n".format( + self.name, self.gpio, int(self.pin), len(self.adc_fns) + ) + ) + else: + print( + "const machine_pin_obj_t pin_{0} = PIN({0}, {1}, {2}, pin_{0}_af, {3}, NULL);\n".format( + self.name, self.gpio, int(self.pin), len(self.adc_fns) + ) ) - ) else: raise ValueError("Pin '{}' has no alternative functions".format(self.name)) @@ -84,6 +112,18 @@ class Pin(object): pass +class AdcFunction(object): + """Holds the information associated with a pins ADC function.""" + + def __init__(self, instance, channel): + self.instance = instance + self.channel = channel + + def print(self): + """Prints the C representation of this AF.""" + print(f" PIN_ADC(ADC{self.instance}, {self.channel}),") + + class AlternateFunction(object): """Holds the information associated with a pins alternate function.""" @@ -149,6 +189,8 @@ class Pins(object): if af and af_supported(af): pin.add_af(AlternateFunction(af_idx, af)) + pin.parse_adc(row[ADC_COL]) + self.cpu_pins.append(pin) @staticmethod diff --git a/ports/mimxrt/boards/mimxrt_prefix.c b/ports/mimxrt/boards/mimxrt_prefix.c index 59e338976..96ba6a0d5 100644 --- a/ports/mimxrt/boards/mimxrt_prefix.c +++ b/ports/mimxrt/boards/mimxrt_prefix.c @@ -13,7 +13,13 @@ .pad_config = (uint32_t)(_pad_config), \ } \ -#define PIN(_name, _gpio, _pin, _af_list) \ +#define PIN_ADC(_instance, _channel) \ + { \ + .instance = (_instance), \ + .channel = (_channel) \ + } \ + +#define PIN(_name, _gpio, _pin, _af_list, _adc_list_len, _adc_list) \ { \ .base = { &machine_pin_type }, \ .name = MP_QSTR_##_name, \ @@ -21,6 +27,8 @@ .pin = (uint32_t)(_pin), \ .muxRegister = (uint32_t)&(IOMUXC->SW_MUX_CTL_PAD[kIOMUXC_SW_MUX_CTL_PAD_##_name]), \ .configRegister = (uint32_t)&(IOMUXC->SW_PAD_CTL_PAD[kIOMUXC_SW_PAD_CTL_PAD_##_name]), \ - .af_list_len = (size_t)(sizeof((_af_list)) / sizeof(machine_pin_af_obj_t)), \ + .af_list_len = (uint8_t)(sizeof((_af_list)) / sizeof(machine_pin_af_obj_t)), \ + .adc_list_len = (_adc_list_len), \ .af_list = (_af_list), \ + .adc_list = (_adc_list), \ } \ diff --git a/ports/mimxrt/machine_adc.c b/ports/mimxrt/machine_adc.c new file mode 100644 index 000000000..8bf5e7b9a --- /dev/null +++ b/ports/mimxrt/machine_adc.c @@ -0,0 +1,145 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 Philipp Ebensberger + * + * 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. + */ + +#include <stdint.h> +#include "py/obj.h" +#include "py/runtime.h" +#include "py/mphal.h" + +#include "fsl_adc.h" +#include "fsl_gpio.h" +#include "fsl_iomuxc.h" + +#include "modmachine.h" + +typedef struct _machine_adc_obj_t { + mp_obj_base_t base; + ADC_Type *adc; + uint8_t channel; + uint8_t channel_group; + uint16_t resolution; +} machine_adc_obj_t; + +STATIC ADC_Type *const adc_bases[] = ADC_BASE_PTRS; + +STATIC void adc_obj_print(const mp_print_t *print, mp_obj_t o, mp_print_kind_t kind) { + (void)kind; + machine_adc_obj_t *self = MP_OBJ_TO_PTR(o); + + // Get ADC adc id + for (int i = 1; i < sizeof(adc_bases) / sizeof(ADC_Type *); ++i) { + if (adc_bases[i] == self->adc) { + mp_printf(print, "ADC(%u, channel=%u)", i, self->channel); + break; + } + } +} + +STATIC mp_obj_t adc_obj_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + mp_arg_check_num(n_args, n_kw, 1, 1, false); + + // Unpack and check parameter + const machine_pin_obj_t *pin = pin_find(args[0]); + + if (pin->adc_list_len == 0) { + mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("Pin(%q) does not have ADC capabilities"), pin->name); + } + + // Extract arguments + ADC_Type *adc_instance = pin->adc_list[0].instance; // NOTE: we only use the first ADC assignment - multiple assignments are not supported for now + uint8_t channel = pin->adc_list[0].channel; + + // Configure ADC peripheral channel + adc_channel_config_t channel_config = { + .channelNumber = (uint32_t)channel, + .enableInterruptOnConversionCompleted = false, + }; + ADC_SetChannelConfig(adc_instance, 0UL, &channel_config); // NOTE: we always choose channel group '0' since we only perform software triggered conversion + + // Create ADC Instance + machine_adc_obj_t *o = m_new_obj(machine_adc_obj_t); + o->base.type = &machine_adc_type; + o->adc = adc_instance; + o->channel = (uint8_t)channel; + o->channel_group = 0; + o->resolution = 4096; // NOTE: currently only 12bit resolution supported + + return MP_OBJ_FROM_PTR(o); +} + +// read_u16() +STATIC mp_obj_t machine_adc_read_u16(mp_obj_t self_in) { + machine_adc_obj_t *self = MP_OBJ_TO_PTR(self_in); + + // Initiate conversion + adc_channel_config_t channel_config = { + .channelNumber = self->channel, + .enableInterruptOnConversionCompleted = false, + }; + ADC_SetChannelConfig(self->adc, (uint32_t)self->channel_group, &channel_config); + + // Wait for conversion to finish + while (!ADC_GetChannelStatusFlags(self->adc, (uint32_t)self->channel_group)) { + // do nothing + } + + // Measure input voltage + uint32_t value = ADC_GetChannelConversionValue(self->adc, (uint32_t)self->channel_group); + return MP_OBJ_NEW_SMALL_INT(value * 65535 / self->resolution); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_adc_read_u16_obj, machine_adc_read_u16); + +STATIC const mp_rom_map_elem_t adc_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_read_u16), MP_ROM_PTR(&machine_adc_read_u16_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(adc_locals_dict, adc_locals_dict_table); + +const mp_obj_type_t machine_adc_type = { + {&mp_type_type}, + .name = MP_QSTR_ADC, + .print = adc_obj_print, + .make_new = adc_obj_make_new, + .locals_dict = (mp_obj_dict_t *)&adc_locals_dict, +}; + +void machine_adc_init(void) { + for (int i = 1; i < sizeof(adc_bases) / sizeof(ADC_Type *); ++i) { + ADC_Type *adc_instance = adc_bases[i]; + + // Configure ADC perpheral + adc_config_t config; + ADC_GetDefaultConfig(&config); + ADC_Init(adc_instance, &config); + + // Perform calibration + status_t calib_state = ADC_DoAutoCalibration(adc_instance); + + if (calib_state == kStatus_Fail) { + mp_printf(&mp_plat_print, "Calibration for ADC Instance %d failed", i); + } + } +} diff --git a/ports/mimxrt/modmachine.c b/ports/mimxrt/modmachine.c index 96cae3a82..dfee91992 100644 --- a/ports/mimxrt/modmachine.c +++ b/ports/mimxrt/modmachine.c @@ -59,6 +59,7 @@ STATIC const mp_rom_map_elem_t machine_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_LED), MP_ROM_PTR(&machine_led_type) }, #endif { MP_ROM_QSTR(MP_QSTR_Pin), MP_ROM_PTR(&machine_pin_type) }, + { MP_ROM_QSTR(MP_QSTR_ADC), MP_ROM_PTR(&machine_adc_type) }, { MP_ROM_QSTR(MP_QSTR_Timer), MP_ROM_PTR(&machine_timer_type) }, { MP_ROM_QSTR(MP_QSTR_RTC), MP_ROM_PTR(&machine_rtc_type) }, { MP_ROM_QSTR(MP_QSTR_Signal), MP_ROM_PTR(&machine_signal_type) }, diff --git a/ports/mimxrt/modmachine.h b/ports/mimxrt/modmachine.h index d165c00e6..a7b577fa7 100644 --- a/ports/mimxrt/modmachine.h +++ b/ports/mimxrt/modmachine.h @@ -29,9 +29,11 @@ #include "py/obj.h" +extern const mp_obj_type_t machine_adc_type; extern const mp_obj_type_t machine_timer_type; extern const mp_obj_type_t machine_rtc_type; +void machine_adc_init(void); void machine_timer_init_PIT(void); #endif // MICROPY_INCLUDED_MIMXRT_MODMACHINE_H diff --git a/ports/mimxrt/pin.h b/ports/mimxrt/pin.h index 6afedd1f5..7a05d2d64 100644 --- a/ports/mimxrt/pin.h +++ b/ports/mimxrt/pin.h @@ -101,14 +101,21 @@ typedef struct { } machine_pin_af_obj_t; typedef struct { + ADC_Type *instance; + uint8_t channel; +} machine_pin_adc_obj_t; + +typedef struct { mp_obj_base_t base; qstr name; // pad name GPIO_Type *gpio; // gpio instance for pin uint32_t pin; // pin number uint32_t muxRegister; uint32_t configRegister; - size_t af_list_len; // length of available alternate functions list - const machine_pin_af_obj_t *af_list; // pointer tolist with alternate functions + uint8_t af_list_len; // length of available alternate functions list + uint8_t adc_list_len; // length of available ADC options list + const machine_pin_af_obj_t *af_list; // pointer to list with alternate functions + const machine_pin_adc_obj_t *adc_list; // pointer to list with ADC options } machine_pin_obj_t; // ------------------------------------------------------------------------------------------------------------------ // |
