From 0d2e9c37622a039b552b3e508076db072e7d2a64 Mon Sep 17 00:00:00 2001 From: Hierophect Date: Sat, 7 Sep 2019 15:54:16 -0400 Subject: [PATCH] WIP --- ports/stm32f4/Makefile | 1 + ports/stm32f4/common-hal/analogio/AnalogIn.c | 101 ++++++++++++ ports/stm32f4/common-hal/analogio/AnalogIn.h | 47 ++++++ ports/stm32f4/common-hal/analogio/AnalogOut.c | 155 ++++++++++++++++++ ports/stm32f4/common-hal/analogio/AnalogOut.h | 45 +++++ ports/stm32f4/common-hal/analogio/__init__.c | 1 + .../common-hal/digitalio/DigitalInOut.c | 1 + ports/stm32f4/peripherals/stm32f4/pins.h | 9 +- 8 files changed, 356 insertions(+), 4 deletions(-) create mode 100644 ports/stm32f4/common-hal/analogio/AnalogIn.c create mode 100644 ports/stm32f4/common-hal/analogio/AnalogIn.h create mode 100644 ports/stm32f4/common-hal/analogio/AnalogOut.c create mode 100644 ports/stm32f4/common-hal/analogio/AnalogOut.h create mode 100644 ports/stm32f4/common-hal/analogio/__init__.c diff --git a/ports/stm32f4/Makefile b/ports/stm32f4/Makefile index f3558588b6..369c60606b 100755 --- a/ports/stm32f4/Makefile +++ b/ports/stm32f4/Makefile @@ -145,6 +145,7 @@ CFLAGS += -DHSE_VALUE=8000000 -DCFG_TUSB_MCU=OPT_MCU_STM32F4 -DCFG_TUD_CDC_RX_BU SRC_STM32 = \ boards/$(BOARD)/stm32f4xx_hal_msp.c \ stm32f4/STM32F4xx_HAL_Driver/Src/stm32f4xx_ll_gpio.c \ + stm32f4/STM32F4xx_HAL_Driver/Src/stm32f4xx_ll_adc.c \ stm32f4/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_pcd.c \ stm32f4/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_pcd_ex.c \ stm32f4/STM32F4xx_HAL_Driver/Src/stm32f4xx_ll_usb.c \ diff --git a/ports/stm32f4/common-hal/analogio/AnalogIn.c b/ports/stm32f4/common-hal/analogio/AnalogIn.c new file mode 100644 index 0000000000..7318e3a2d9 --- /dev/null +++ b/ports/stm32f4/common-hal/analogio/AnalogIn.c @@ -0,0 +1,101 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Scott Shawcroft for Adafruit Industries + * + * 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 "common-hal/analogio/AnalogIn.h" +#include "py/runtime.h" +#include "supervisor/shared/translate.h" + +#include "common-hal/microcontroller/Pin.h" + +#include "stm32f4xx_hal.h" +#include "stm32f4xx_ll_gpio.h" +#include "stm32f4xx_ll_adc.h" + +//mp_raise_ValueError(translate("U dun goofed")); + +void common_hal_analogio_analogin_construct(analogio_analogin_obj_t* self, + const mcu_pin_obj_t *pin) { + + //No ADC function on pin + if (pin->adc == 0xff) { + mp_raise_ValueError(translate("Pin does not have ADC capabilities")); + } + //TODO: add ADC traits to structure? + + //LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_GPIOA); //required? + LL_GPIO_SetPinMode(pin_port(pin->number), pin_mask(pin->number), LL_GPIO_MODE_ANALOG); + LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_ADC1); //TODO: conditional on ADC unit + claim_pin(pin); + self->pin = pin; +} + +bool common_hal_analogio_analogin_deinited(analogio_analogin_obj_t *self) { + return self->pin == mp_const_none; +} + +void common_hal_analogio_analogin_deinit(analogio_analogin_obj_t *self) { + if (common_hal_analogio_analogin_deinited(self)) { + return; + } + reset_pin_number(self->pin->number); + self->pin = mp_const_none; +} + +uint16_t common_hal_analogio_analogin_get_value(analogio_analogin_obj_t *self) { + // Something else might have used the ADC in a different way, + // so we completely re-initialize it. + + if (LL_ADC_IsEnabled(ADC1) == 0) + { + LL_ADC_REG_SetTriggerSource(ADC1, LL_ADC_REG_TRIG_SOFTWARE); + LL_ADC_REG_SetContinuousMode(ADC1, LL_ADC_REG_CONV_SINGLE); + LL_ADC_REG_SetSequencerLength(ADC1, LL_ADC_REG_SEQ_SCAN_DISABLE); + LL_ADC_REG_SetSequencerRanks(ADC1, LL_ADC_REG_RANK_1, LL_ADC_CHANNEL_4); + + LL_ADC_SetChannelSamplingTime(ADC1, LL_ADC_CHANNEL_4, LL_ADC_SAMPLINGTIME_56CYCLES); + LL_ADC_EnableIT_OVR(ADC1); + } + + LL_ADC_Enable(ADC1); + + + struct adc_sync_descriptor adc; + + samd_peripherals_adc_setup(&adc, self->instance); + + ConversionStartPoll_ADC_GrpRegular(); + + /* Retrieve ADC conversion data */ + /* (data scale corresponds to ADC resolution: 12 bits) */ + uhADCxConvertedData = LL_ADC_REG_ReadConversionData12(ADC1); + + // Shift the value to be 16 bit. + return value << 4; +} + +float common_hal_analogio_analogin_get_reference_voltage(analogio_analogin_obj_t *self) { + return 3.3f; +} diff --git a/ports/stm32f4/common-hal/analogio/AnalogIn.h b/ports/stm32f4/common-hal/analogio/AnalogIn.h new file mode 100644 index 0000000000..e67135ab69 --- /dev/null +++ b/ports/stm32f4/common-hal/analogio/AnalogIn.h @@ -0,0 +1,47 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Scott Shawcroft + * + * 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. + */ + +#ifndef MICROPY_INCLUDED_ATMEL_SAMD_COMMON_HAL_ANALOGIO_ANALOGIN_H +#define MICROPY_INCLUDED_ATMEL_SAMD_COMMON_HAL_ANALOGIO_ANALOGIN_H + +#include "common-hal/microcontroller/Pin.h" + +#include "py/obj.h" + +typedef struct { + mp_obj_base_t base; + const mcu_pin_obj_t * pin; +} analogio_analogin_obj_t; + +static inline uint8_t stm32_adc_units(uint8_t adc_packed) { + return adc_packed >> 5; +} + +static inline uint8_t stm32_adc_channel(uint8_t adc_packed) { + return adc_packed & 0x1f; +} + +#endif // MICROPY_INCLUDED_ATMEL_SAMD_COMMON_HAL_ANALOGIO_ANALOGIN_H diff --git a/ports/stm32f4/common-hal/analogio/AnalogOut.c b/ports/stm32f4/common-hal/analogio/AnalogOut.c new file mode 100644 index 0000000000..9ac1f7bd15 --- /dev/null +++ b/ports/stm32f4/common-hal/analogio/AnalogOut.c @@ -0,0 +1,155 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * 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. + */ + +#include +#include + +#include "py/mperrno.h" +#include "py/runtime.h" + +#include "shared-bindings/analogio/AnalogOut.h" +#include "shared-bindings/audioio/AudioOut.h" +#include "shared-bindings/microcontroller/Pin.h" +#include "supervisor/shared/translate.h" + +#include "atmel_start_pins.h" +#include "hal/include/hal_dac_sync.h" +#include "hpl/gclk/hpl_gclk_base.h" +#include "peripheral_clk_config.h" + +#ifdef SAMD21 +#include "hpl/pm/hpl_pm_base.h" +#endif + +void common_hal_analogio_analogout_construct(analogio_analogout_obj_t* self, + const mcu_pin_obj_t *pin) { + #if defined(SAMD21) && !defined(PIN_PA02) + mp_raise_NotImplementedError(translate("No DAC on chip")); + #else + if (pin->number != PIN_PA02 + #ifdef SAMD51 + && pin->number != PIN_PA05 + #endif + ) { + mp_raise_ValueError(translate("AnalogOut not supported on given pin")); + return; + } + + self->channel = 0; + #ifdef SAMD51 + if (pin->number == PIN_PA05) { + self->channel = 1; + } + #endif + + #ifdef SAMD51 + hri_mclk_set_APBDMASK_DAC_bit(MCLK); + #endif + + #ifdef SAMD21 + _pm_enable_bus_clock(PM_BUS_APBC, DAC); + #endif + + // SAMD21: This clock should be <= 12 MHz, per datasheet section 47.6.3. + // SAMD51: This clock should be <= 350kHz, per datasheet table 37-6. + _gclk_enable_channel(DAC_GCLK_ID, CONF_GCLK_DAC_SRC); + + // Don't double init the DAC on the SAMD51 when both outputs are in use. We use the free state + // of each output pin to determine DAC state. + int32_t result = ERR_NONE; + #ifdef SAMD51 + if (!common_hal_mcu_pin_is_free(&pin_PA02) || !common_hal_mcu_pin_is_free(&pin_PA05)) { + #endif + // Fake the descriptor if the DAC is already initialized. + self->descriptor.device.hw = DAC; + #ifdef SAMD51 + } else { + #endif + result = dac_sync_init(&self->descriptor, DAC); + #ifdef SAMD51 + } + #endif + if (result != ERR_NONE) { + mp_raise_OSError(MP_EIO); + return; + } + claim_pin(pin); + + gpio_set_pin_function(pin->number, GPIO_PIN_FUNCTION_B); + + dac_sync_enable_channel(&self->descriptor, self->channel); + #endif +} + +bool common_hal_analogio_analogout_deinited(analogio_analogout_obj_t *self) { + return self->deinited; +} + +void common_hal_analogio_analogout_deinit(analogio_analogout_obj_t *self) { + #if (defined(SAMD21) && defined(PIN_PA02)) || defined(SAMD51) + if (common_hal_analogio_analogout_deinited(self)) { + return; + } + dac_sync_disable_channel(&self->descriptor, self->channel); + reset_pin_number(PIN_PA02); + // Only deinit the DAC on the SAMD51 if both outputs are free. + #ifdef SAMD51 + if (common_hal_mcu_pin_is_free(&pin_PA02) && common_hal_mcu_pin_is_free(&pin_PA05)) { + #endif + dac_sync_deinit(&self->descriptor); + #ifdef SAMD51 + } + #endif + self->deinited = true; + // TODO(tannewt): Turn off the DAC clocks to save power. + #endif +} + +void common_hal_analogio_analogout_set_value(analogio_analogout_obj_t *self, + uint16_t value) { + #if defined(SAMD21) && !defined(PIN_PA02) + return; + #endif + // Input is 16 bit so make sure and set LEFTADJ to 1 so it takes the top + // bits. This is currently done in asf4_conf/*/hpl_dac_config.h. + dac_sync_write(&self->descriptor, self->channel, &value, 1); +} + +void analogout_reset(void) { + // audioout_reset also resets the DAC, and does a smooth ramp down to avoid clicks + // if it was enabled, so do that instead if AudioOut is enabled. +#if CIRCUITPY_AUDIOIO + audioout_reset(); +#else + #ifdef SAMD21 + while (DAC->STATUS.reg & DAC_STATUS_SYNCBUSY) {} + #endif + #ifdef SAMD51 + while (DAC->SYNCBUSY.reg & DAC_SYNCBUSY_SWRST) {} + #endif + DAC->CTRLA.reg |= DAC_CTRLA_SWRST; +#endif +} diff --git a/ports/stm32f4/common-hal/analogio/AnalogOut.h b/ports/stm32f4/common-hal/analogio/AnalogOut.h new file mode 100644 index 0000000000..3710a7211a --- /dev/null +++ b/ports/stm32f4/common-hal/analogio/AnalogOut.h @@ -0,0 +1,45 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Scott Shawcroft + * + * 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. + */ + +#ifndef MICROPY_INCLUDED_ATMEL_SAMD_COMMON_HAL_ANALOGIO_ANALOGOUT_H +#define MICROPY_INCLUDED_ATMEL_SAMD_COMMON_HAL_ANALOGIO_ANALOGOUT_H + +#include "common-hal/microcontroller/Pin.h" + +#include "hal/include/hal_dac_sync.h" + +#include "py/obj.h" + +typedef struct { + mp_obj_base_t base; + struct dac_sync_descriptor descriptor; + uint8_t channel; + bool deinited; +} analogio_analogout_obj_t; + +void analogout_reset(void); + +#endif // MICROPY_INCLUDED_ATMEL_SAMD_COMMON_HAL_ANALOGIO_ANALOGOUT_H diff --git a/ports/stm32f4/common-hal/analogio/__init__.c b/ports/stm32f4/common-hal/analogio/__init__.c new file mode 100644 index 0000000000..eea58c77d6 --- /dev/null +++ b/ports/stm32f4/common-hal/analogio/__init__.c @@ -0,0 +1 @@ +// No analogio module functions. diff --git a/ports/stm32f4/common-hal/digitalio/DigitalInOut.c b/ports/stm32f4/common-hal/digitalio/DigitalInOut.c index e19988a7f7..750a4d3c08 100644 --- a/ports/stm32f4/common-hal/digitalio/DigitalInOut.c +++ b/ports/stm32f4/common-hal/digitalio/DigitalInOut.c @@ -28,6 +28,7 @@ #include "shared-bindings/digitalio/DigitalInOut.h" #include "py/runtime.h" #include "supervisor/shared/translate.h" + #include "stm32f4xx_hal.h" #include "stm32f4xx_ll_gpio.h" diff --git a/ports/stm32f4/peripherals/stm32f4/pins.h b/ports/stm32f4/peripherals/stm32f4/pins.h index ee11cbe832..0b0d42982e 100644 --- a/ports/stm32f4/peripherals/stm32f4/pins.h +++ b/ports/stm32f4/peripherals/stm32f4/pins.h @@ -39,21 +39,22 @@ typedef struct { mp_obj_base_t base; uint8_t number; - uint8_t adc_num_input; //(3)mask () + uint8_t adc; //(3)units (5)channel } mcu_pin_obj_t; +//Standard stm32 adc unit combinations #define ADC_1 1 -#define ADC_123 7 #define ADC_12 3 +#define ADC_123 7 #define ADC_3 4 //STM32 ADC pins can have a combination of 1, 2 or all 3 ADCs on a single pin, //but all 3 ADCs will share the same input number per pin. #define ADC_INPUT(mask, number) \ - .adc_num_input = (((mask) << 5) | ((number) & 0x1F)), + .adc = (((mask) << 5) | ((number) & 0x1F)), #define NO_ADC \ - .adc_num_input = 0xff, + .adc = 0xff, extern const mp_obj_type_t mcu_pin_type;