diff options
Diffstat (limited to 'ports/raspberrypi/common-hal')
36 files changed, 3297 insertions, 0 deletions
diff --git a/ports/raspberrypi/common-hal/analogio/AnalogIn.c b/ports/raspberrypi/common-hal/analogio/AnalogIn.c new file mode 100644 index 000000000..c51a74929 --- /dev/null +++ b/ports/raspberrypi/common-hal/analogio/AnalogIn.c @@ -0,0 +1,73 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 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 "src/rp2_common/hardware_adc/include/hardware/adc.h" + +#define ADC_FIRST_PIN_NUMBER 26 +#define ADC_PIN_COUNT 4 + +void common_hal_analogio_analogin_construct(analogio_analogin_obj_t *self, const mcu_pin_obj_t *pin) { + if (pin->number < ADC_FIRST_PIN_NUMBER || pin->number > ADC_FIRST_PIN_NUMBER + ADC_PIN_COUNT) { + mp_raise_ValueError(translate("Pin does not have ADC capabilities")); + } + + adc_init(); + + adc_gpio_init(pin->number); + + claim_pin(pin); + self->pin = pin; +} + +bool common_hal_analogio_analogin_deinited(analogio_analogin_obj_t *self) { + return self->pin == NULL; +} + +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 = NULL; +} + +uint16_t common_hal_analogio_analogin_get_value(analogio_analogin_obj_t *self) { + adc_select_input(self->pin->number - ADC_FIRST_PIN_NUMBER); + uint16_t value = adc_read(); + + // Map value to from 12 to 16 bits + return (value << 4); +} + +float common_hal_analogio_analogin_get_reference_voltage(analogio_analogin_obj_t *self) { + // The nominal VCC voltage + return 3.3f; +} diff --git a/ports/raspberrypi/common-hal/analogio/AnalogIn.h b/ports/raspberrypi/common-hal/analogio/AnalogIn.h new file mode 100644 index 000000000..ee9976e34 --- /dev/null +++ b/ports/raspberrypi/common-hal/analogio/AnalogIn.h @@ -0,0 +1,41 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 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. + */ + +#ifndef MICROPY_INCLUDED_RASPBERRYPI_COMMON_HAL_ANALOGIO_ANALOGIN_H +#define MICROPY_INCLUDED_RASPBERRYPI_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; + +void analogin_init(void); + +#endif // MICROPY_INCLUDED_RASPBERRYPI_COMMON_HAL_ANALOGIO_ANALOGIN_H diff --git a/ports/raspberrypi/common-hal/analogio/AnalogOut.c b/ports/raspberrypi/common-hal/analogio/AnalogOut.c new file mode 100644 index 000000000..adafa15d5 --- /dev/null +++ b/ports/raspberrypi/common-hal/analogio/AnalogOut.c @@ -0,0 +1,48 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 Dan Halbert 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 "shared-bindings/analogio/AnalogOut.h" + +#include <stdint.h> +#include <string.h> + +#include "py/mperrno.h" +#include "py/runtime.h" +#include "supervisor/shared/translate.h" + +void common_hal_analogio_analogout_construct(analogio_analogout_obj_t* self, const mcu_pin_obj_t *pin) { + mp_raise_RuntimeError(translate("AnalogOut functionality not supported")); +} + +bool common_hal_analogio_analogout_deinited(analogio_analogout_obj_t *self) { + return true; +} + +void common_hal_analogio_analogout_deinit(analogio_analogout_obj_t *self) { +} + +void common_hal_analogio_analogout_set_value(analogio_analogout_obj_t *self, uint16_t value) { +} diff --git a/ports/raspberrypi/common-hal/analogio/AnalogOut.h b/ports/raspberrypi/common-hal/analogio/AnalogOut.h new file mode 100644 index 000000000..7c7a61aa2 --- /dev/null +++ b/ports/raspberrypi/common-hal/analogio/AnalogOut.h @@ -0,0 +1,36 @@ +/* + * 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_RASPBERRYPI_COMMON_HAL_ANALOGIO_ANALOGOUT_H +#define MICROPY_INCLUDED_RASPBERRYPI_COMMON_HAL_ANALOGIO_ANALOGOUT_H + +#include "py/obj.h" + +typedef struct { + mp_obj_base_t base; +} analogio_analogout_obj_t; + +#endif // MICROPY_INCLUDED_RASPBERRYPI_COMMON_HAL_ANALOGIO_ANALOGOUT_H diff --git a/ports/raspberrypi/common-hal/analogio/__init__.c b/ports/raspberrypi/common-hal/analogio/__init__.c new file mode 100644 index 000000000..eea58c77d --- /dev/null +++ b/ports/raspberrypi/common-hal/analogio/__init__.c @@ -0,0 +1 @@ +// No analogio module functions. diff --git a/ports/raspberrypi/common-hal/board/__init__.c b/ports/raspberrypi/common-hal/board/__init__.c new file mode 100644 index 000000000..3c7f30df2 --- /dev/null +++ b/ports/raspberrypi/common-hal/board/__init__.c @@ -0,0 +1,34 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 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 <string.h> + +#include "py/runtime.h" +#include "py/mphal.h" +#include "common-hal/microcontroller/Pin.h" + +// Pins aren't actually defined here. They are in the board specific directory +// such as boards/arduino_zero/pins.c. diff --git a/ports/raspberrypi/common-hal/busio/I2C.c b/ports/raspberrypi/common-hal/busio/I2C.c new file mode 100644 index 000000000..fa49e375e --- /dev/null +++ b/ports/raspberrypi/common-hal/busio/I2C.c @@ -0,0 +1,175 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 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 "shared-bindings/busio/I2C.h" +#include "py/mperrno.h" +#include "py/runtime.h" + +#include "shared-bindings/microcontroller/__init__.h" +#include "supervisor/shared/translate.h" + +#include "src/rp2_common/hardware_gpio/include/hardware/gpio.h" + +// Synopsys DW_apb_i2c (v2.01) IP + +#define NO_PIN 0xff + +STATIC bool never_reset_i2c[2]; +STATIC i2c_inst_t* i2c[2] = {i2c0, i2c1}; + +void reset_i2c(void) { + for (size_t i = 0; i < 2; i++) { + if (never_reset_i2c[i]) { + continue; + } + + i2c_deinit(i2c[i]); + } +} + +void common_hal_busio_i2c_construct(busio_i2c_obj_t *self, + const mcu_pin_obj_t* scl, const mcu_pin_obj_t* sda, uint32_t frequency, uint32_t timeout) { + self->peripheral = NULL; + // I2C pins have a regular pattern. SCL is always odd and SDA is even. They match up in pairs + // so we can divide by two to get the instance. This pattern repeats. + if (scl->number % 2 == 1 && sda->number % 2 == 0 && scl->number / 2 == sda->number / 2) { + size_t instance = (scl->number / 2) % 2; + self->peripheral = i2c[instance]; + } + if (self->peripheral == NULL) { + mp_raise_ValueError(translate("Invalid pins")); + } + if ((i2c_get_hw(self->peripheral)->enable & I2C_IC_ENABLE_ENABLE_BITS) != 0) { + mp_raise_ValueError(translate("I2C peripheral in use")); + } + if (frequency > 1000000) { + mp_raise_ValueError(translate("Unsupported baudrate")); + } + +#if CIRCUITPY_REQUIRE_I2C_PULLUPS + // Test that the pins are in a high state. (Hopefully indicating they are pulled up.) + gpio_set_function(sda->number, GPIO_FUNC_SIO); + gpio_set_function(scl->number, GPIO_FUNC_SIO); + gpio_set_dir(sda->number, GPIO_IN); + gpio_set_dir(scl->number, GPIO_IN); + + gpio_set_pulls(sda->number, false, true); + gpio_set_pulls(scl->number, false, true); + + common_hal_mcu_delay_us(10); + + gpio_set_pulls(sda->number, false, false); + gpio_set_pulls(scl->number, false, false); + + // We must pull up within 3us to achieve 400khz. + common_hal_mcu_delay_us(3); + + if (!gpio_get(sda->number) || !gpio_get(scl->number)) { + reset_pin_number(sda->number); + reset_pin_number(scl->number); + mp_raise_RuntimeError(translate("SDA or SCL needs a pull up")); + } +#endif + + gpio_set_function(sda->number, GPIO_FUNC_I2C); + gpio_set_function(scl->number, GPIO_FUNC_I2C); + + self->baudrate = i2c_init(self->peripheral, frequency); + + self->sda_pin = sda->number; + self->scl_pin = scl->number; + claim_pin(sda); + claim_pin(scl); +} + +bool common_hal_busio_i2c_deinited(busio_i2c_obj_t *self) { + return self->sda_pin == NO_PIN; +} + +void common_hal_busio_i2c_deinit(busio_i2c_obj_t *self) { + if (common_hal_busio_i2c_deinited(self)) { + return; + } + never_reset_i2c[i2c_hw_index(self->peripheral)] = false; + + i2c_deinit(self->peripheral); + + reset_pin_number(self->sda_pin); + reset_pin_number(self->scl_pin); + self->sda_pin = NO_PIN; + self->scl_pin = NO_PIN; +} + +bool common_hal_busio_i2c_probe(busio_i2c_obj_t *self, uint8_t addr) { + uint8_t fake_read = 0; + return i2c_read_blocking(self->peripheral, addr, &fake_read, 1, false) != PICO_ERROR_GENERIC; +} + +bool common_hal_busio_i2c_try_lock(busio_i2c_obj_t *self) { + bool grabbed_lock = false; + if (!self->has_lock) { + grabbed_lock = true; + self->has_lock = true; + } + return grabbed_lock; +} + +bool common_hal_busio_i2c_has_lock(busio_i2c_obj_t *self) { + return self->has_lock; +} + +void common_hal_busio_i2c_unlock(busio_i2c_obj_t *self) { + self->has_lock = false; +} + +uint8_t common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t addr, + const uint8_t *data, size_t len, bool transmit_stop_bit) { + int result = i2c_write_blocking(self->peripheral, addr, data, len, !transmit_stop_bit); + if (result == len) { + return 0; + } else if (result == PICO_ERROR_GENERIC) { + return MP_ENODEV; + } + return MP_EIO; +} + +uint8_t common_hal_busio_i2c_read(busio_i2c_obj_t *self, uint16_t addr, + uint8_t *data, size_t len) { + int result = i2c_read_blocking(self->peripheral, addr, data, len, false); + if (result == len) { + return 0; + } else if (result == PICO_ERROR_GENERIC) { + return MP_ENODEV; + } + return MP_EIO; +} + +void common_hal_busio_i2c_never_reset(busio_i2c_obj_t *self) { + never_reset_i2c[i2c_hw_index(self->peripheral)] = true; + + never_reset_pin_number(self->scl_pin); + never_reset_pin_number(self->sda_pin); +} diff --git a/ports/raspberrypi/common-hal/busio/I2C.h b/ports/raspberrypi/common-hal/busio/I2C.h new file mode 100644 index 000000000..d09f29e54 --- /dev/null +++ b/ports/raspberrypi/common-hal/busio/I2C.h @@ -0,0 +1,47 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 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. + */ + +#ifndef MICROPY_INCLUDED_RASPBERRYPI_COMMON_HAL_BUSIO_I2C_H +#define MICROPY_INCLUDED_RASPBERRYPI_COMMON_HAL_BUSIO_I2C_H + +#include "common-hal/microcontroller/Pin.h" + +#include "py/obj.h" + +#include "src/rp2_common/hardware_i2c/include/hardware/i2c.h" + +typedef struct { + mp_obj_base_t base; + i2c_inst_t * peripheral; + bool has_lock; + uint baudrate; + uint8_t scl_pin; + uint8_t sda_pin; +} busio_i2c_obj_t; + +void reset_i2c(void); + +#endif // MICROPY_INCLUDED_RASPBERRYPI_COMMON_HAL_BUSIO_I2C_H diff --git a/ports/raspberrypi/common-hal/busio/OneWire.h b/ports/raspberrypi/common-hal/busio/OneWire.h new file mode 100644 index 000000000..e27723ab2 --- /dev/null +++ b/ports/raspberrypi/common-hal/busio/OneWire.h @@ -0,0 +1,33 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 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. + */ + +#ifndef MICROPY_INCLUDED_RASPBERRYPI_COMMON_HAL_BUSIO_ONEWIRE_H +#define MICROPY_INCLUDED_RASPBERRYPI_COMMON_HAL_BUSIO_ONEWIRE_H + +// Use bitbangio. +#include "shared-module/busio/OneWire.h" + +#endif // MICROPY_INCLUDED_RASPBERRYPI_COMMON_HAL_BUSIO_ONEWIRE_H diff --git a/ports/raspberrypi/common-hal/busio/SPI.c b/ports/raspberrypi/common-hal/busio/SPI.c new file mode 100644 index 000000000..b157ae3eb --- /dev/null +++ b/ports/raspberrypi/common-hal/busio/SPI.c @@ -0,0 +1,294 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 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 "shared-bindings/busio/SPI.h" + +#include "lib/utils/interrupt_char.h" +#include "py/mperrno.h" +#include "py/runtime.h" + +#include "supervisor/board.h" +#include "common-hal/microcontroller/Pin.h" +#include "supervisor/shared/rgb_led_status.h" +#include "shared-bindings/microcontroller/Pin.h" + +#include "src/rp2_common/hardware_dma/include/hardware/dma.h" +#include "src/rp2_common/hardware_gpio/include/hardware/gpio.h" + +#define NO_INSTANCE 0xff + +STATIC bool never_reset_spi[2]; +STATIC spi_inst_t* spi[2] = {spi0, spi1}; + +void reset_spi(void) { + for (size_t i = 0; i < 2; i++) { + if (never_reset_spi[i]) { + continue; + } + + spi_deinit(spi[i]); + } +} + +void common_hal_busio_spi_construct(busio_spi_obj_t *self, + const mcu_pin_obj_t * clock, const mcu_pin_obj_t * mosi, + const mcu_pin_obj_t * miso) { + size_t instance_index = NO_INSTANCE; + if (clock->number % 4 == 2) { + instance_index = (clock->number / 8) % 2; + } + if (mosi != NULL) { + // Make sure the set MOSI matches the clock settings. + if (mosi->number % 4 != 3 || + (mosi->number / 8) % 2 != instance_index) { + instance_index = NO_INSTANCE; + } + } + if (miso != NULL) { + // Make sure the set MOSI matches the clock settings. + if (miso->number % 4 != 0 || + (miso->number / 8) % 2 != instance_index) { + instance_index = NO_INSTANCE; + } + } + + // TODO: Check to see if we're sharing the SPI with a native APA102. + + if (instance_index > 1) { + mp_raise_ValueError(translate("Invalid pins")); + } + + if (instance_index == 0) { + self->peripheral = spi0; + } else if (instance_index == 1) { + self->peripheral = spi1; + } + + if ((spi_get_hw(self->peripheral)->cr1 & SPI_SSPCR1_SSE_BITS) != 0) { + mp_raise_ValueError(translate("SPI peripheral in use")); + } + + spi_init(self->peripheral, 250000); + + gpio_set_function(clock->number, GPIO_FUNC_SPI); + claim_pin(clock); + self->clock = clock; + + self->MOSI = mosi; + if (mosi != NULL) { + gpio_set_function(mosi->number, GPIO_FUNC_SPI); + claim_pin(mosi); + } + + self->MISO = miso; + if (miso != NULL) { + gpio_set_function(miso->number, GPIO_FUNC_SPI); + claim_pin(miso); + } +} + +void common_hal_busio_spi_never_reset(busio_spi_obj_t *self) { + never_reset_spi[spi_get_index(self->peripheral)] = true; + + common_hal_never_reset_pin(self->clock); + common_hal_never_reset_pin(self->MOSI); + common_hal_never_reset_pin(self->MISO); +} + +bool common_hal_busio_spi_deinited(busio_spi_obj_t *self) { + return self->clock == NULL; +} + +void common_hal_busio_spi_deinit(busio_spi_obj_t *self) { + if (common_hal_busio_spi_deinited(self)) { + return; + } + never_reset_spi[spi_get_index(self->peripheral)] = false; + spi_deinit(self->peripheral); + + common_hal_reset_pin(self->clock); + common_hal_reset_pin(self->MOSI); + common_hal_reset_pin(self->MISO); + self->clock = NULL; +} + +bool common_hal_busio_spi_configure(busio_spi_obj_t *self, + uint32_t baudrate, uint8_t polarity, uint8_t phase, uint8_t bits) { + if (baudrate == self->target_frequency && + polarity == self->polarity && + phase == self->phase && + bits == self->bits) { + return true; + } + + spi_set_format(self->peripheral, bits, polarity, phase, SPI_MSB_FIRST); + + self->polarity = polarity; + self->phase = phase; + self->bits = bits; + self->target_frequency = baudrate; + self->real_frequency = spi_set_baudrate(self->peripheral, baudrate); + + return true; +} + +bool common_hal_busio_spi_try_lock(busio_spi_obj_t *self) { + bool grabbed_lock = false; + if (!self->has_lock) { + grabbed_lock = true; + self->has_lock = true; + } + return grabbed_lock; +} + +bool common_hal_busio_spi_has_lock(busio_spi_obj_t *self) { + return self->has_lock; +} + +void common_hal_busio_spi_unlock(busio_spi_obj_t *self) { + self->has_lock = false; +} + +static bool _transfer(busio_spi_obj_t *self, + const uint8_t *data_out, size_t out_len, + uint8_t *data_in, size_t in_len) { + // Use DMA for large transfers if channels are available + const size_t dma_min_size_threshold = 32; + int chan_tx = -1; + int chan_rx = -1; + size_t len = MAX(out_len, in_len); + if (len >= dma_min_size_threshold) { + // Use two DMA channels to service the two FIFOs + chan_tx = dma_claim_unused_channel(false); + chan_rx = dma_claim_unused_channel(false); + } + bool use_dma = chan_rx >= 0 && chan_tx >= 0; + if (use_dma) { + dma_channel_config c = dma_channel_get_default_config(chan_tx); + channel_config_set_transfer_data_size(&c, DMA_SIZE_8); + channel_config_set_dreq(&c, spi_get_index(self->peripheral) ? DREQ_SPI1_TX : DREQ_SPI0_TX); + channel_config_set_read_increment(&c, out_len == len); + channel_config_set_write_increment(&c, false); + dma_channel_configure(chan_tx, &c, + &spi_get_hw(self->peripheral)->dr, + data_out, + len, + false); + + c = dma_channel_get_default_config(chan_rx); + channel_config_set_transfer_data_size(&c, DMA_SIZE_8); + channel_config_set_dreq(&c, spi_get_index(self->peripheral) ? DREQ_SPI1_RX : DREQ_SPI0_RX); + channel_config_set_read_increment(&c, false); + channel_config_set_write_increment(&c, in_len == len); + dma_channel_configure(chan_rx, &c, + data_in, + &spi_get_hw(self->peripheral)->dr, + len, + false); + + dma_start_channel_mask((1u << chan_rx) | (1u << chan_tx)); + while (dma_channel_is_busy(chan_rx) || dma_channel_is_busy(chan_tx)) { + // TODO: We should idle here until we get a DMA interrupt or something else. + RUN_BACKGROUND_TASKS; + if (mp_hal_is_interrupted()) { + if (dma_channel_is_busy(chan_rx)) { + dma_channel_abort(chan_rx); + } + if (dma_channel_is_busy(chan_tx)) { + dma_channel_abort(chan_tx); + } + break; + } + } + } + + // If we have claimed only one channel successfully, we should release immediately. This also + // releases the DMA after use_dma has been done. + if (chan_rx >= 0) { + dma_channel_unclaim(chan_rx); + } + if (chan_tx >= 0) { + dma_channel_unclaim(chan_tx); + } + + if (!use_dma && !mp_hal_is_interrupted()) { + // Use software for small transfers, or if couldn't claim two DMA channels + // Never have more transfers in flight than will fit into the RX FIFO, + // else FIFO will overflow if this code is heavily interrupted. + const size_t fifo_depth = 8; + size_t rx_remaining = len; + size_t tx_remaining = len; + + while (!mp_hal_is_interrupted() && (rx_remaining || tx_remaining)) { + if (tx_remaining && spi_is_writable(self->peripheral) && rx_remaining - tx_remaining < fifo_depth) { + spi_get_hw(self->peripheral)->dr = (uint32_t) *data_out; + // Increment only if the buffer is the transfer length. It's 1 otherwise. + if (out_len == len) { + data_out++; + } + --tx_remaining; + } + if (rx_remaining && spi_is_readable(self->peripheral)) { + *data_in = (uint8_t) spi_get_hw(self->peripheral)->dr; + // Increment only if the buffer is the transfer length. It's 1 otherwise. + if (in_len == len) { + data_in++; + } + --rx_remaining; + } + RUN_BACKGROUND_TASKS; + } + } + return true; +} + +bool common_hal_busio_spi_write(busio_spi_obj_t *self, + const uint8_t *data, size_t len) { + uint32_t data_in; + return _transfer(self, data, len, (uint8_t*) &data_in, MIN(len, 4)); +} + +bool common_hal_busio_spi_read(busio_spi_obj_t *self, + uint8_t *data, size_t len, uint8_t write_value) { + uint32_t data_out = write_value << 24 | write_value << 16 | write_value << 8 | write_value; + return _transfer(self, (const uint8_t*) &data_out, MIN(4, len), data, len); +} + +bool common_hal_busio_spi_transfer(busio_spi_obj_t *self, const uint8_t *data_out, uint8_t *data_in, size_t len) { + return _transfer(self, data_out, len, data_in, len); +} + +uint32_t common_hal_busio_spi_get_frequency(busio_spi_obj_t* self) { + return self->real_frequency; +} + +uint8_t common_hal_busio_spi_get_phase(busio_spi_obj_t* self) { + return self->phase; +} + +uint8_t common_hal_busio_spi_get_polarity(busio_spi_obj_t* self) { + return self->polarity; +} diff --git a/ports/raspberrypi/common-hal/busio/SPI.h b/ports/raspberrypi/common-hal/busio/SPI.h new file mode 100644 index 000000000..981db46d4 --- /dev/null +++ b/ports/raspberrypi/common-hal/busio/SPI.h @@ -0,0 +1,52 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 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. + */ + +#ifndef MICROPY_INCLUDED_RASPBERRYPI_COMMON_HAL_BUSIO_SPI_H +#define MICROPY_INCLUDED_RASPBERRYPI_COMMON_HAL_BUSIO_SPI_H + +#include "common-hal/microcontroller/Pin.h" + +#include "py/obj.h" + +#include "src/rp2_common/hardware_spi/include/hardware/spi.h" + +typedef struct { + mp_obj_base_t base; + spi_inst_t * peripheral; + bool has_lock; + const mcu_pin_obj_t* clock; + const mcu_pin_obj_t* MOSI; + const mcu_pin_obj_t* MISO; + uint32_t target_frequency; + int32_t real_frequency; + uint8_t polarity; + uint8_t phase; + uint8_t bits; +} busio_spi_obj_t; + +void reset_spi(void); + +#endif // MICROPY_INCLUDED_RASPBERRYPI_COMMON_HAL_BUSIO_SPI_H diff --git a/ports/raspberrypi/common-hal/busio/UART.c b/ports/raspberrypi/common-hal/busio/UART.c new file mode 100644 index 000000000..f9a75b499 --- /dev/null +++ b/ports/raspberrypi/common-hal/busio/UART.c @@ -0,0 +1,404 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 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 "shared-bindings/microcontroller/__init__.h" +#include "shared-bindings/busio/UART.h" + +#include "mpconfigport.h" +#include "lib/utils/interrupt_char.h" +#include "py/gc.h" +#include "py/mperrno.h" +#include "py/runtime.h" +#include "py/stream.h" +#include "supervisor/shared/translate.h" +#include "supervisor/shared/tick.h" + +#define UART_DEBUG(...) (void)0 +// #define UART_DEBUG(...) mp_printf(&mp_plat_print __VA_OPT__(,) __VA_ARGS__) + +// Do-nothing callback needed so that usart_async code will enable rx interrupts. +// See comment below re usart_async_register_callback() +// static void usart_async_rxc_callback(const struct usart_async_descriptor *const descr) { +// // Nothing needs to be done by us. +// } + +#define NO_PIN 0xff + +void common_hal_busio_uart_construct(busio_uart_obj_t *self, + const mcu_pin_obj_t * tx, const mcu_pin_obj_t * rx, + const mcu_pin_obj_t * rts, const mcu_pin_obj_t * cts, + const mcu_pin_obj_t * rs485_dir, bool rs485_invert, + uint32_t baudrate, uint8_t bits, busio_uart_parity_t parity, uint8_t stop, + mp_float_t timeout, uint16_t receiver_buffer_size, byte* receiver_buffer, + bool sigint_enabled) { + mp_raise_NotImplementedError(translate("UART not yet supported")); + +// Sercom* sercom = NULL; +// uint8_t sercom_index = 255; // Unset index +// uint32_t rx_pinmux = 0; +// uint8_t rx_pad = 255; // Unset pad +// uint32_t tx_pinmux = 0; +// uint8_t tx_pad = 255; // Unset pad + +// if ((rts != NULL) || (cts != NULL) || (rs485_dir != NULL) || (rs485_invert)) { +// mp_raise_ValueError(translate("RTS/CTS/RS485 Not yet supported on this device")); +// } + +// if (bits > 8) { +// mp_raise_NotImplementedError(translate("bytes > 8 bits not supported")); +// } + +// bool have_tx = tx != NULL; +// bool have_rx = rx != NULL; +// if (!have_tx && !have_rx) { +// mp_raise_ValueError(translate("tx and rx cannot both be None")); +// } + +// self->baudrate = baudrate; +// self->character_bits = bits; +// self->timeout_ms = timeout * 1000; + +// // This assignment is only here because the usart_async routines take a *const argument. +// struct usart_async_descriptor * const usart_desc_p = (struct usart_async_descriptor * const) &self->usart_desc; + +// for (int i = 0; i < NUM_SERCOMS_PER_PIN; i++) { +// Sercom* potential_sercom = NULL; +// if (have_tx) { +// sercom_index = tx->sercom[i].index; +// if (sercom_index >= SERCOM_INST_NUM) { +// continue; +// } +// potential_sercom = sercom_insts[sercom_index]; +// #ifdef SAMD21 +// if (potential_sercom->USART.CTRLA.bit.ENABLE != 0 || +// !(tx->sercom[i].pad == 0 || +// tx->sercom[i].pad == 2)) { +// continue; +// } +// #endif +// #ifdef SAM_D5X_E5X +// if (potential_sercom->USART.CTRLA.bit.ENABLE != 0 || +// !(tx->sercom[i].pad == 0)) { +// continue; +// } +// #endif +// tx_pinmux = PINMUX(tx->number, (i == 0) ? MUX_C : MUX_D); +// tx_pad = tx->sercom[i].pad; +// if (rx == NULL) { +// sercom = potential_sercom; +// break; +// } +// } +// for (int j = 0; j < NUM_SERCOMS_PER_PIN; j++) { +// if (((!have_tx && rx->sercom[j].index < SERCOM_INST_NUM && +// sercom_insts[rx->sercom[j].index]->USART.CTRLA.bit.ENABLE == 0) || +// sercom_index == rx->sercom[j].index) && +// rx->sercom[j].pad != tx_pad) { +// rx_pinmux = PINMUX(rx->number, (j == 0) ? MUX_C : MUX_D); +// rx_pad = rx->sercom[j].pad; +// sercom = sercom_insts[rx->sercom[j].index]; +// sercom_index = rx->sercom[j].index; +// break; +// } +// } +// if (sercom != NULL) { +// break; +// } +// } +// if (sercom == NULL) { +// mp_raise_ValueError(translate("Invalid pins")); +// } +// if (!have_tx) { +// tx_pad = 0; +// if (rx_pad == 0) { +// tx_pad = 2; +// } +// } +// if (!have_rx) { +// rx_pad = (tx_pad + 1) % 4; +// } + +// // Set up clocks on SERCOM. +// samd_peripherals_sercom_clock_init(sercom, sercom_index); + +// if (rx && receiver_buffer_size > 0) { +// self->buffer_length = receiver_buffer_size; +// // Initially allocate the UART's buffer in the long-lived part of the +// // heap. UARTs are generally long-lived objects, but the "make long- +// // lived" machinery is incapable of moving internal pointers like +// // self->buffer, so do it manually. (However, as long as internal +// // pointers like this are NOT moved, allocating the buffer +// // in the long-lived pool is not strictly necessary) +// self->buffer = (uint8_t *) gc_alloc(self->buffer_length * sizeof(uint8_t), false, true); +// if (self->buffer == NULL) { +// common_hal_busio_uart_deinit(self); +// mp_raise_msg_varg(&mp_type_MemoryError, translate("Failed to allocate RX buffer of %d bytes"), self->buffer_length * sizeof(uint8_t)); +// } +// } else { +// self->buffer_length = 0; +// self->buffer = NULL; +// } + +// if (usart_async_init(usart_desc_p, sercom, self->buffer, self->buffer_length, NULL) != ERR_NONE) { +// mp_raise_ValueError(translate("Could not initialize UART")); +// } + +// // usart_async_init() sets a number of defaults based on a prototypical SERCOM +// // which don't necessarily match what we need. After calling it, set the values +// // specific to this instantiation of UART. + +// // Set pads computed for this SERCOM. +// // TXPO: +// // 0x0: TX pad 0; no RTS/CTS +// // 0x1: TX pad 2; no RTS/CTS +// // 0x2: TX pad 0; RTS: pad 2, CTS: pad 3 (not used by us right now) +// // So divide by 2 to map pad to value. +// // RXPO: +// // 0x0: RX pad 0 +// // 0x1: RX pad 1 +// // 0x2: RX pad 2 +// // 0x3: RX pad 3 + +// // Doing a group mask and set of the registers saves 60 bytes over setting the bitfields individually. + +// sercom->USART.CTRLA.reg &= ~(SERCOM_USART_CTRLA_TXPO_Msk | +// SERCOM_USART_CTRLA_RXPO_Msk | +// SERCOM_USART_CTRLA_FORM_Msk); +// sercom->USART.CTRLA.reg |= SERCOM_USART_CTRLA_TXPO(tx_pad / 2) | +// SERCOM_USART_CTRLA_RXPO(rx_pad) | +// (parity == BUSIO_UART_PARITY_NONE ? 0 : SERCOM_USART_CTRLA_FORM(1)); + +// // Enable tx and/or rx based on whether the pins were specified. +// // CHSIZE is 0 for 8 bits, 5, 6, 7 for 5, 6, 7 bits. 1 for 9 bits, but we don't support that. +// sercom->USART.CTRLB.reg &= ~(SERCOM_USART_CTRLB_TXEN | +// SERCOM_USART_CTRLB_RXEN | +// SERCOM_USART_CTRLB_PMODE | +// SERCOM_USART_CTRLB_SBMODE | +// SERCOM_USART_CTRLB_CHSIZE_Msk); +// sercom->USART.CTRLB.reg |= (have_tx ? SERCOM_USART_CTRLB_TXEN : 0) | +// (have_rx ? SERCOM_USART_CTRLB_RXEN : 0) | +// (parity == BUSIO_UART_PARITY_ODD ? SERCOM_USART_CTRLB_PMODE : 0) | +// (stop > 1 ? SERCOM_USART_CTRLB_SBMODE : 0) | +// SERCOM_USART_CTRLB_CHSIZE(bits % 8); + +// // Set baud rate +// common_hal_busio_uart_set_baudrate(self, baudrate); + +// // Turn on rx interrupt handling. The UART async driver has its own set of internal callbacks, +// // which are set up by uart_async_init(). These in turn can call user-specified callbacks. +// // In fact, the actual interrupts are not enabled unless we set up a user-specified callback. +// // This is confusing. It's explained in the Atmel START User Guide -> Implementation Description -> +// // Different read function behavior in some asynchronous drivers. As of this writing: +// // http://start.atmel.com/static/help/index.html?GUID-79201A5A-226F-4FBB-B0B8-AB0BE0554836 +// // Look at the ASFv4 code example for async USART. +// usart_async_register_callback(usart_desc_p, USART_ASYNC_RXC_CB, usart_async_rxc_callback); + + +// if (have_tx) { +// gpio_set_pin_direction(tx->number, GPIO_DIRECTION_OUT); +// gpio_set_pin_pull_mode(tx->number, GPIO_PULL_OFF); +// gpio_set_pin_function(tx->number, tx_pinmux); +// self->tx_pin = tx->number; +// claim_pin(tx); +// } else { +// self->tx_pin = NO_PIN; +// } + +// if (have_rx) { +// gpio_set_pin_direction(rx->number, GPIO_DIRECTION_IN); +// gpio_set_pin_pull_mode(rx->number, GPIO_PULL_OFF); +// gpio_set_pin_function(rx->number, rx_pinmux); +// self->rx_pin = rx->number; +// claim_pin(rx); +// } else { +// self->rx_pin = NO_PIN; +// } + +// usart_async_enable(usart_desc_p); +} + +bool common_hal_busio_uart_deinited(busio_uart_obj_t *self) { + return self->rx_pin == NO_PIN && self->tx_pin == NO_PIN; +} + +void common_hal_busio_uart_deinit(busio_uart_obj_t *self) { + if (common_hal_busio_uart_deinited(self)) { + return; + } + // This assignment is only here because the usart_async routines take a *const argument. + // struct usart_async_descriptor * const usart_desc_p = (struct usart_async_descriptor * const) &self->usart_desc; + // usart_async_disable(usart_desc_p); + // usart_async_deinit(usart_desc_p); + reset_pin_number(self->rx_pin); + reset_pin_number(self->tx_pin); + self->rx_pin = NO_PIN; + self->tx_pin = NO_PIN; +} + +// Read characters. +size_t common_hal_busio_uart_read(busio_uart_obj_t *self, uint8_t *data, size_t len, int *errcode) { + if (self->rx_pin == NO_PIN) { + mp_raise_ValueError(translate("No RX pin")); + } + + // This assignment is only here because the usart_async routines take a *const argument. + // struct usart_async_descriptor * const usart_desc_p = (struct usart_async_descriptor * const) &self->usart_desc; + + if (len == 0) { + // Nothing to read. + return 0; + } + + // struct io_descriptor *io; + // usart_async_get_io_descriptor(usart_desc_p, &io); + + size_t total_read = 0; + // uint64_t start_ticks = supervisor_ticks_ms64(); + + // // Busy-wait until timeout or until we've read enough chars. + // while (supervisor_ticks_ms64() - start_ticks <= self->timeout_ms) { + // // Read as many chars as we can right now, up to len. + // size_t num_read = io_read(io, data, len); + + // // Advance pointer in data buffer, and decrease how many chars left to read. + // data += num_read; + // len -= num_read; + // total_read += num_read; + // if (len == 0) { + // // Don't need to read any more: data buf is full. + // break; + // } + // if (num_read > 0) { + // // Reset the timeout on every character read. + // start_ticks = supervisor_ticks_ms64(); + // } + // RUN_BACKGROUND_TASKS; + // // Allow user to break out of a timeout with a KeyboardInterrupt. + // if (mp_hal_is_interrupted()) { + // break; + // } + // // If we are zero timeout, make sure we don't loop again (in the event + // // we read in under 1ms) + // if (self->timeout_ms == 0) { + // break; + // } + // } + + // if (total_read == 0) { + // *errcode = EAGAIN; + // return MP_STREAM_ERROR; + // } + + return total_read; +} + +// Write characters. +size_t common_hal_busio_uart_write(busio_uart_obj_t *self, const uint8_t *data, size_t len, int *errcode) { + if (self->tx_pin == NO_PIN) { + mp_raise_ValueError(translate("No TX pin")); + } + + // This assignment is only here because the usart_async routines take a *const argument. + // struct usart_async_descriptor * const usart_desc_p = (struct usart_async_descriptor * const) &self->usart_desc; + + // struct io_descriptor *io; + // usart_async_get_io_descriptor(usart_desc_p, &io); + + // // Start writing characters. This is non-blocking and will + // // return immediately after setting up the write. + // if (io_write(io, data, len) < 0) { + // *errcode = MP_EAGAIN; + // return MP_STREAM_ERROR; + // } + + // // Busy-wait until all characters transmitted. + // struct usart_async_status async_status; + // while (true) { + // usart_async_get_status(usart_desc_p, &async_status); + // if (async_status.txcnt >= len) { + // break; + // } + // RUN_BACKGROUND_TASKS; + // } + + return len; +} + +uint32_t common_hal_busio_uart_get_baudrate(busio_uart_obj_t *self) { + return self->baudrate; +} + +void common_hal_busio_uart_set_baudrate(busio_uart_obj_t *self, uint32_t baudrate) { + // This assignment is only here because the usart_async routines take a *const argument. + // struct usart_async_descriptor * const usart_desc_p = (struct usart_async_descriptor * const) &self->usart_desc; + // usart_async_set_baud_rate(usart_desc_p, + // // Samples and ARITHMETIC vs FRACTIONAL must correspond to USART_SAMPR in + // // hpl_sercom_config.h. + // _usart_async_calculate_baud_rate(baudrate, // e.g. 9600 baud + // PROTOTYPE_SERCOM_USART_ASYNC_CLOCK_FREQUENCY, + // 16, // samples + // USART_BAUDRATE_ASYNCH_ARITHMETIC, + // 0 // fraction - not used for ARITHMETIC + // )); + self->baudrate = baudrate; +} + +mp_float_t common_hal_busio_uart_get_timeout(busio_uart_obj_t *self) { + return (mp_float_t) (self->timeout_ms / 1000.0f); +} + +void common_hal_busio_uart_set_timeout(busio_uart_obj_t *self, mp_float_t timeout) { + self->timeout_ms = timeout * 1000; +} + +uint32_t common_hal_busio_uart_rx_characters_available(busio_uart_obj_t *self) { + // This assignment is only here because the usart_async routines take a *const argument. + // struct usart_async_descriptor * const usart_desc_p = (struct usart_async_descriptor * const) &self->usart_desc; + // struct usart_async_status async_status; + // usart_async_get_status(usart_desc_p, &async_status); + // return async_status.rxcnt; + return 0; +} + +void common_hal_busio_uart_clear_rx_buffer(busio_uart_obj_t *self) { + // This assignment is only here because the usart_async routines take a *const argument. + // struct usart_async_descriptor * const usart_desc_p = (struct usart_async_descriptor * const) &self->usart_desc; + // usart_async_flush_rx_buffer(usart_desc_p); + +} + +// True if there are no characters still to be written. +bool common_hal_busio_uart_ready_to_tx(busio_uart_obj_t *self) { + if (self->tx_pin == NO_PIN) { + return false; + } + return false; + // // This assignment is only here because the usart_async routines take a *const argument. + // struct usart_async_descriptor * const usart_desc_p = (struct usart_async_descriptor * const) &self->usart_desc; + // struct usart_async_status async_status; + // usart_async_get_status(usart_desc_p, &async_status); + // return !(async_status.flags & USART_ASYNC_STATUS_BUSY); +} diff --git a/ports/raspberrypi/common-hal/busio/UART.h b/ports/raspberrypi/common-hal/busio/UART.h new file mode 100644 index 000000000..43ed9bee0 --- /dev/null +++ b/ports/raspberrypi/common-hal/busio/UART.h @@ -0,0 +1,47 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 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. + */ + +#ifndef MICROPY_INCLUDED_RASPBERRYPI_COMMON_HAL_BUSIO_UART_H +#define MICROPY_INCLUDED_RASPBERRYPI_COMMON_HAL_BUSIO_UART_H + +#include "common-hal/microcontroller/Pin.h" + +#include "py/obj.h" + +typedef struct { + mp_obj_base_t base; + // struct usart_async_descriptor usart_desc; + uint8_t rx_pin; + uint8_t tx_pin; + uint8_t character_bits; + bool rx_error; + uint32_t baudrate; + uint32_t timeout_ms; + uint32_t buffer_length; + uint8_t* buffer; +} busio_uart_obj_t; + +#endif // MICROPY_INCLUDED_RASPBERRYPI_COMMON_HAL_BUSIO_UART_H diff --git a/ports/raspberrypi/common-hal/busio/__init__.c b/ports/raspberrypi/common-hal/busio/__init__.c new file mode 100644 index 000000000..41761b674 --- /dev/null +++ b/ports/raspberrypi/common-hal/busio/__init__.c @@ -0,0 +1 @@ +// No busio module functions. diff --git a/ports/raspberrypi/common-hal/digitalio/DigitalInOut.c b/ports/raspberrypi/common-hal/digitalio/DigitalInOut.c new file mode 100644 index 000000000..b0bc1b96e --- /dev/null +++ b/ports/raspberrypi/common-hal/digitalio/DigitalInOut.c @@ -0,0 +1,154 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 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 <stdint.h> +#include <string.h> + +#include "py/runtime.h" +#include "py/mphal.h" + +#include "common-hal/microcontroller/Pin.h" +#include "shared-bindings/digitalio/DigitalInOut.h" +#include "supervisor/shared/translate.h" + +#include "src/rp2_common/hardware_gpio/include/hardware/gpio.h" + +digitalinout_result_t common_hal_digitalio_digitalinout_construct( + digitalio_digitalinout_obj_t* self, const mcu_pin_obj_t* pin) { + claim_pin(pin); + self->pin = pin; + self->output = false; + self->open_drain = false; + + gpio_init(pin->number); + return DIGITALINOUT_OK; +} + +void common_hal_digitalio_digitalinout_never_reset( + digitalio_digitalinout_obj_t *self) { + never_reset_pin_number(self->pin->number); +} + +bool common_hal_digitalio_digitalinout_deinited(digitalio_digitalinout_obj_t* self) { + return self->pin == NULL; +} + +void common_hal_digitalio_digitalinout_deinit(digitalio_digitalinout_obj_t* self) { + if (common_hal_digitalio_digitalinout_deinited(self)) { + return; + } + reset_pin_number(self->pin->number); + self->pin = NULL; +} + +void common_hal_digitalio_digitalinout_switch_to_input( + digitalio_digitalinout_obj_t* self, digitalio_pull_t pull) { + self->output = false; + // This also sets direction to input. + common_hal_digitalio_digitalinout_set_pull(self, pull); +} + +digitalinout_result_t common_hal_digitalio_digitalinout_switch_to_output( + digitalio_digitalinout_obj_t* self, bool value, + digitalio_drive_mode_t drive_mode) { + const uint8_t pin = self->pin->number; + gpio_set_dir(pin, GPIO_OUT); + // TODO: Turn on "strong" pin driving (more current available). + + self->output = true; + common_hal_digitalio_digitalinout_set_drive_mode(self, drive_mode); + common_hal_digitalio_digitalinout_set_value(self, value); + return DIGITALINOUT_OK; +} + +digitalio_direction_t common_hal_digitalio_digitalinout_get_direction( + digitalio_digitalinout_obj_t* self) { + return self->output ? DIRECTION_OUTPUT : DIRECTION_INPUT; +} + +void common_hal_digitalio_digitalinout_set_value( + digitalio_digitalinout_obj_t* self, bool value) { + const uint8_t pin = self->pin->number; + if (self->open_drain) { + gpio_set_dir(pin, value ? GPIO_IN : GPIO_OUT); + } else { + gpio_put(pin, value); + } +} + +bool common_hal_digitalio_digitalinout_get_value( + digitalio_digitalinout_obj_t* self) { + return gpio_get(self->pin->number); +} + +digitalinout_result_t common_hal_digitalio_digitalinout_set_drive_mode( + digitalio_digitalinout_obj_t* self, + digitalio_drive_mode_t drive_mode) { + const uint8_t pin = self->pin->number; + bool value = common_hal_digitalio_digitalinout_get_value(self); + self->open_drain = drive_mode == DRIVE_MODE_OPEN_DRAIN; + if (self->open_drain) { + gpio_put(pin, false); + } + // True is implemented differently between modes so reset the value to make + // sure it's correct for the new mode. + if (value) { + common_hal_digitalio_digitalinout_set_value(self, value); + } + return DIGITALINOUT_OK; +} + +digitalio_drive_mode_t common_hal_digitalio_digitalinout_get_drive_mode( + digitalio_digitalinout_obj_t* self) { + if (self->open_drain) { + return DRIVE_MODE_OPEN_DRAIN; + } else { + return DRIVE_MODE_PUSH_PULL; + } +} + +void common_hal_digitalio_digitalinout_set_pull( + digitalio_digitalinout_obj_t* self, digitalio_pull_t pull) { + const uint8_t pin = self->pin->number; + gpio_set_pulls(pin, pull == PULL_UP, pull == PULL_DOWN); + gpio_set_dir(pin, GPIO_IN); +} + +digitalio_pull_t common_hal_digitalio_digitalinout_get_pull( + digitalio_digitalinout_obj_t* self) { + uint32_t pin = self->pin->number; + if (self->output) { + mp_raise_AttributeError(translate("Cannot get pull while in output mode")); + return PULL_NONE; + } else { + if (gpio_is_pulled_up(pin)) { + return PULL_UP; + } else if (gpio_is_pulled_down(pin)) { + return PULL_DOWN; + } + } + return PULL_NONE; +} diff --git a/ports/raspberrypi/common-hal/digitalio/DigitalInOut.h b/ports/raspberrypi/common-hal/digitalio/DigitalInOut.h new file mode 100644 index 000000000..8b14bbad8 --- /dev/null +++ b/ports/raspberrypi/common-hal/digitalio/DigitalInOut.h @@ -0,0 +1,40 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 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. + */ + +#ifndef MICROPY_INCLUDED_RASPBERRYPI_COMMON_HAL_DIGITALIO_DIGITALINOUT_H +#define MICROPY_INCLUDED_RASPBERRYPI_COMMON_HAL_DIGITALIO_DIGITALINOUT_H + +#include "common-hal/microcontroller/Pin.h" +#include "py/obj.h" + +typedef struct { + mp_obj_base_t base; + const mcu_pin_obj_t * pin; + bool output; + bool open_drain; +} digitalio_digitalinout_obj_t; + +#endif // MICROPY_INCLUDED_RASPBERRYPI_COMMON_HAL_DIGITALIO_DIGITALINOUT_H diff --git a/ports/raspberrypi/common-hal/digitalio/__init__.c b/ports/raspberrypi/common-hal/digitalio/__init__.c new file mode 100644 index 000000000..20fad4595 --- /dev/null +++ b/ports/raspberrypi/common-hal/digitalio/__init__.c @@ -0,0 +1 @@ +// No digitalio module functions. diff --git a/ports/raspberrypi/common-hal/displayio/ParallelBus.c b/ports/raspberrypi/common-hal/displayio/ParallelBus.c new file mode 100644 index 000000000..57b2ffc36 --- /dev/null +++ b/ports/raspberrypi/common-hal/displayio/ParallelBus.c @@ -0,0 +1,68 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 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 "shared-bindings/displayio/ParallelBus.h" + +#include <stdint.h> + +#include "common-hal/microcontroller/Pin.h" +#include "py/runtime.h" +#include "shared-bindings/digitalio/DigitalInOut.h" +#include "shared-bindings/microcontroller/__init__.h" + +void common_hal_displayio_parallelbus_construct(displayio_parallelbus_obj_t* self, + const mcu_pin_obj_t* data0, const mcu_pin_obj_t* command, const mcu_pin_obj_t* chip_select, + const mcu_pin_obj_t* write, const mcu_pin_obj_t* read, const mcu_pin_obj_t* reset) { + + mp_raise_NotImplementedError(translate("ParallelBus not yet supported")); + // TODO: Implement with PIO and DMA. +} + +void common_hal_displayio_parallelbus_deinit(displayio_parallelbus_obj_t* self) { + +} + +bool common_hal_displayio_parallelbus_reset(mp_obj_t obj) { + return false; +} + +bool common_hal_displayio_parallelbus_bus_free(mp_obj_t obj) { + return false; +} + +bool common_hal_displayio_parallelbus_begin_transaction(mp_obj_t obj) { + + return false; +} + +void common_hal_displayio_parallelbus_send(mp_obj_t obj, display_byte_type_t byte_type, + display_chip_select_behavior_t chip_select, const uint8_t *data, uint32_t data_length) { + +} + +void common_hal_displayio_parallelbus_end_transaction(mp_obj_t obj) { + +} diff --git a/ports/raspberrypi/common-hal/displayio/ParallelBus.h b/ports/raspberrypi/common-hal/displayio/ParallelBus.h new file mode 100644 index 000000000..45989d990 --- /dev/null +++ b/ports/raspberrypi/common-hal/displayio/ParallelBus.h @@ -0,0 +1,36 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 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. + */ + +#ifndef MICROPY_INCLUDED_RASPBERRYPI_COMMON_HAL_DISPLAYIO_PARALLELBUS_H +#define MICROPY_INCLUDED_RASPBERRYPI_COMMON_HAL_DISPLAYIO_PARALLELBUS_H + +#include "common-hal/digitalio/DigitalInOut.h" + +typedef struct { + mp_obj_base_t base; +} displayio_parallelbus_obj_t; + +#endif // MICROPY_INCLUDED_RASPBERRYPI_COMMON_HAL_DISPLAYIO_PARALLELBUS_H diff --git a/ports/raspberrypi/common-hal/microcontroller/Pin.c b/ports/raspberrypi/common-hal/microcontroller/Pin.c new file mode 100644 index 000000000..ca5cf5a04 --- /dev/null +++ b/ports/raspberrypi/common-hal/microcontroller/Pin.c @@ -0,0 +1,181 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 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 "py/runtime.h" + +#include "common-hal/microcontroller/__init__.h" +#include "shared-bindings/microcontroller/Pin.h" + +#include "supervisor/shared/rgb_led_status.h" + +#include "src/rp2_common/hardware_gpio/include/hardware/gpio.h" + +#ifdef MICROPY_HW_NEOPIXEL +bool neopixel_in_use; +#endif +#ifdef MICROPY_HW_APA102_MOSI +bool apa102_sck_in_use; +bool apa102_mosi_in_use; +#endif +#ifdef SPEAKER_ENABLE_PIN +bool speaker_enable_in_use; +#endif + +STATIC uint32_t never_reset_pins; + +void reset_all_pins(void) { + for (size_t i = 0; i < TOTAL_GPIO_COUNT; i++) { + if ((never_reset_pins & (1 << i)) != 0) { + continue; + } + reset_pin_number(i); + } +} + +void never_reset_pin_number(uint8_t pin_number) { + if (pin_number >= TOTAL_GPIO_COUNT) { + return; + } + + never_reset_pins |= 1 << pin_number; +} + +void reset_pin_number(uint8_t pin_number) { + if (pin_number >= TOTAL_GPIO_COUNT) { + return; + } + + never_reset_pins &= ~(1 << pin_number); + + // We are very aggressive in shutting down the pad fully. Both pulls are + // disabled and both buffers are as well. + gpio_init(pin_number); + hw_clear_bits(&padsbank0_hw->io[pin_number], PADS_BANK0_GPIO0_IE_BITS | + PADS_BANK0_GPIO0_PUE_BITS | + PADS_BANK0_GPIO0_PDE_BITS); + hw_set_bits(&padsbank0_hw->io[pin_number], PADS_BANK0_GPIO0_OD_BITS); + + #ifdef MICROPY_HW_NEOPIXEL + if (pin_number == MICROPY_HW_NEOPIXEL->number) { + neopixel_in_use = false; + rgb_led_status_init(); + return; + } + #endif + #ifdef MICROPY_HW_APA102_MOSI + if (pin_number == MICROPY_HW_APA102_MOSI->number || + pin_number == MICROPY_HW_APA102_SCK->number) { + apa102_mosi_in_use = apa102_mosi_in_use && pin_number != MICROPY_HW_APA102_MOSI->number; + apa102_sck_in_use = apa102_sck_in_use && pin_number != MICROPY_HW_APA102_SCK->number; + if (!apa102_sck_in_use && !apa102_mosi_in_use) { + rgb_led_status_init(); + } + return; + } + #endif + + #ifdef SPEAKER_ENABLE_PIN + if (pin_number == SPEAKER_ENABLE_PIN->number) { + speaker_enable_in_use = false; + } + #endif +} + +void common_hal_never_reset_pin(const mcu_pin_obj_t* pin) { + never_reset_pin_number(pin->number); +} + +void common_hal_reset_pin(const mcu_pin_obj_t* pin) { + reset_pin_number(pin->number); +} + +void claim_pin(const mcu_pin_obj_t* pin) { + #ifdef MICROPY_HW_NEOPIXEL + if (pin == MICROPY_HW_NEOPIXEL) { + neopixel_in_use = true; + } + #endif + #ifdef MICROPY_HW_APA102_MOSI + if (pin == MICROPY_HW_APA102_MOSI) { + apa102_mosi_in_use = true; + } + if (pin == MICROPY_HW_APA102_SCK) { + apa102_sck_in_use = true; + } + #endif + + #ifdef SPEAKER_ENABLE_PIN + if (pin == SPEAKER_ENABLE_PIN) { + speaker_enable_in_use = true; + } + #endif +} + +bool pin_number_is_free(uint8_t pin_number) { + if (pin_number >= TOTAL_GPIO_COUNT) { + return false; + } + + uint32_t pad_state = padsbank0_hw->io[pin_number]; + return (pad_state & PADS_BANK0_GPIO0_IE_BITS) == 0 && + (pad_state & PADS_BANK0_GPIO0_OD_BITS) != 0; +} + +bool common_hal_mcu_pin_is_free(const mcu_pin_obj_t* pin) { + #ifdef MICROPY_HW_NEOPIXEL + if (pin == MICROPY_HW_NEOPIXEL) { + return !neopixel_in_use; + } + #endif + #ifdef MICROPY_HW_APA102_MOSI + if (pin == MICROPY_HW_APA102_MOSI) { + return !apa102_mosi_in_use; + } + if (pin == MICROPY_HW_APA102_SCK) { + return !apa102_sck_in_use; + } + #endif + + #ifdef SPEAKER_ENABLE_PIN + if (pin == SPEAKER_ENABLE_PIN) { + return !speaker_enable_in_use; + } + #endif + + return pin_number_is_free(pin->number); +} + +uint8_t common_hal_mcu_pin_number(const mcu_pin_obj_t* pin) { + return pin->number; +} + +void common_hal_mcu_pin_claim(const mcu_pin_obj_t* pin) { + return claim_pin(pin); +} + +void common_hal_mcu_pin_reset_number(uint8_t pin_no) { + reset_pin_number(pin_no); +} diff --git a/ports/raspberrypi/common-hal/microcontroller/Pin.h b/ports/raspberrypi/common-hal/microcontroller/Pin.h new file mode 100644 index 000000000..07c321185 --- /dev/null +++ b/ports/raspberrypi/common-hal/microcontroller/Pin.h @@ -0,0 +1,53 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 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. + */ + +#ifndef MICROPY_INCLUDED_RASPBERRYPI_COMMON_HAL_MICROCONTROLLER_PIN_H +#define MICROPY_INCLUDED_RASPBERRYPI_COMMON_HAL_MICROCONTROLLER_PIN_H + +#include <assert.h> +#include <stdint.h> + +#include <py/obj.h> + +#include "peripherals/pins.h" + +#ifdef MICROPY_HW_NEOPIXEL +extern bool neopixel_in_use; +#endif +#ifdef MICROPY_HW_APA102_MOSI +extern bool apa102_sck_in_use; +extern bool apa102_mosi_in_use; +#endif + +void reset_all_pins(void); +// reset_pin_number takes the pin number instead of the pointer so that objects don't +// need to store a full pointer. +void reset_pin_number(uint8_t pin_number); +void never_reset_pin_number(uint8_t pin_number); +void claim_pin(const mcu_pin_obj_t* pin); +bool pin_number_is_free(uint8_t pin_number); + +#endif // MICROPY_INCLUDED_RASPBERRYPI_COMMON_HAL_MICROCONTROLLER_PIN_H diff --git a/ports/raspberrypi/common-hal/microcontroller/Processor.c b/ports/raspberrypi/common-hal/microcontroller/Processor.c new file mode 100644 index 000000000..0ad3a51e2 --- /dev/null +++ b/ports/raspberrypi/common-hal/microcontroller/Processor.c @@ -0,0 +1,66 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 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 <math.h> + +#include "py/mphal.h" +#include "common-hal/microcontroller/Processor.h" +#include "shared-bindings/microcontroller/ResetReason.h" + +#include "src/rp2_common/hardware_adc/include/hardware/adc.h" +#include "src/rp2_common/hardware_clocks/include/hardware/clocks.h" + +float common_hal_mcu_processor_get_temperature(void) { + adc_init(); + adc_set_temp_sensor_enabled(true); + adc_select_input(4); + uint16_t value = adc_read(); + adc_set_temp_sensor_enabled(false); + float voltage = value * 3.3 / (1 << 12); + // TODO: turn the ADC back off + return 27 - (voltage - 0.706) / 0.001721; +} + +float common_hal_mcu_processor_get_voltage(void) { + return 3.3f; +} + +uint32_t common_hal_mcu_processor_get_frequency(void) { + return clock_get_hz(clk_sys); +} + +void common_hal_mcu_processor_get_uid(uint8_t raw_id[]) { + // TODO: get the unique id from the flash. The chip itself doesn't have one. + // for (int i=0; i<4; i++) { + // for (int k=0; k<4; k++) { + // raw_id[4 * i + k] = (*(id_addresses[i]) >> k * 8) & 0xff; + // } + // } +} + +mcu_reset_reason_t common_hal_mcu_processor_get_reset_reason(void) { + return RESET_REASON_UNKNOWN; +} diff --git a/ports/raspberrypi/common-hal/microcontroller/Processor.h b/ports/raspberrypi/common-hal/microcontroller/Processor.h new file mode 100644 index 000000000..b7c86e850 --- /dev/null +++ b/ports/raspberrypi/common-hal/microcontroller/Processor.h @@ -0,0 +1,39 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 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. + */ + +#ifndef MICROPY_INCLUDED_RASPBERRYPI_COMMON_HAL_MICROCONTROLLER_PROCESSOR_H +#define MICROPY_INCLUDED_RASPBERRYPI_COMMON_HAL_MICROCONTROLLER_PROCESSOR_H + +#define COMMON_HAL_MCU_PROCESSOR_UID_LENGTH 16 + +#include "py/obj.h" + +typedef struct { + mp_obj_base_t base; + // Stores no state currently. +} mcu_processor_obj_t; + +#endif // MICROPY_INCLUDED_RASPBERRYPI_COMMON_HAL_MICROCONTROLLER_PROCESSOR_H diff --git a/ports/raspberrypi/common-hal/microcontroller/__init__.c b/ports/raspberrypi/common-hal/microcontroller/__init__.c new file mode 100644 index 000000000..e454ffa1b --- /dev/null +++ b/ports/raspberrypi/common-hal/microcontroller/__init__.c @@ -0,0 +1,148 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 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 "py/mphal.h" +#include "py/obj.h" +#include "py/runtime.h" + +#include "common-hal/microcontroller/__init__.h" +#if CIRCUITPY_NVM +#include "shared-bindings/nvm/ByteArray.h" +#endif +#include "shared-bindings/microcontroller/__init__.h" +#include "shared-bindings/microcontroller/Pin.h" +#include "shared-bindings/microcontroller/Processor.h" +#include "supervisor/shared/safe_mode.h" +#include "supervisor/shared/translate.h" + +#include "src/rp2040/hardware_structs/include/hardware/structs/sio.h" +#include "src/rp2_common/hardware_sync/include/hardware/sync.h" + +void common_hal_mcu_delay_us(uint32_t delay) { + mp_hal_delay_us(delay); +} + +volatile uint32_t nesting_count = 0; +void common_hal_mcu_disable_interrupts(void) { + // We don't use save_and_disable_interrupts() from the sdk because we don't want to worry about PRIMASK. + // This is what we do on the SAMD21 via CMSIS. + asm volatile ("cpsid i" : : : "memory"); + __dmb(); + nesting_count++; +} + +void common_hal_mcu_enable_interrupts(void) { + if (nesting_count == 0) { + // reset_into_safe_mode(LOCKING_ERROR); + } + nesting_count--; + if (nesting_count > 0) { + return; + } + __dmb(); + asm volatile ("cpsie i" : : : "memory"); +} + +void common_hal_mcu_on_next_reset(mcu_runmode_t runmode) { + if (runmode == RUNMODE_BOOTLOADER) { + } else { + } + if (runmode == RUNMODE_SAFE_MODE) { + safe_mode_on_next_reset(PROGRAMMATIC_SAFE_MODE); + } +} + +void common_hal_mcu_reset(void) { +} + +// The singleton microcontroller.Processor object, bound to microcontroller.cpu +// It currently only has properties, and no state. +static const mcu_processor_obj_t processor0 = { + .base = { + .type = &mcu_processor_type, + }, +}; + +static const mcu_processor_obj_t processor1 = { + .base = { + .type = &mcu_processor_type, + }, +}; + +const mp_rom_obj_tuple_t common_hal_mcu_processor_obj = { + {&mp_type_tuple}, + CIRCUITPY_PROCESSOR_COUNT, + { + MP_ROM_PTR(&processor0), + MP_ROM_PTR(&processor1) + } +}; + +#if CIRCUITPY_NVM && CIRCUITPY_INTERNAL_NVM_SIZE > 0 +// The singleton nvm.ByteArray object. +const nvm_bytearray_obj_t common_hal_mcu_nvm_obj = { + .base = { + .type = &nvm_bytearray_type, + }, + .len = CIRCUITPY_INTERNAL_NVM_SIZE, + .start_address = (uint8_t*) (CIRCUITPY_INTERNAL_NVM_START_ADDR) +}; +#endif + +// This maps MCU pin names to pin objects. +const mp_rom_map_elem_t mcu_pin_global_dict_table[TOTAL_GPIO_COUNT] = { + { MP_ROM_QSTR(MP_QSTR_GPIO0), MP_ROM_PTR(&pin_GPIO0) }, + { MP_ROM_QSTR(MP_QSTR_GPIO1), MP_ROM_PTR(&pin_GPIO1) }, + { MP_ROM_QSTR(MP_QSTR_GPIO2), MP_ROM_PTR(&pin_GPIO2) }, + { MP_ROM_QSTR(MP_QSTR_GPIO3), MP_ROM_PTR(&pin_GPIO3) }, + { MP_ROM_QSTR(MP_QSTR_GPIO4), MP_ROM_PTR(&pin_GPIO4) }, + { MP_ROM_QSTR(MP_QSTR_GPIO5), MP_ROM_PTR(&pin_GPIO5) }, + { MP_ROM_QSTR(MP_QSTR_GPIO6), MP_ROM_PTR(&pin_GPIO6) }, + { MP_ROM_QSTR(MP_QSTR_GPIO7), MP_ROM_PTR(&pin_GPIO7) }, + { MP_ROM_QSTR(MP_QSTR_GPIO8), MP_ROM_PTR(&pin_GPIO8) }, + { MP_ROM_QSTR(MP_QSTR_GPIO9), MP_ROM_PTR(&pin_GPIO9) }, + { MP_ROM_QSTR(MP_QSTR_GPIO10), MP_ROM_PTR(&pin_GPIO10) }, + { MP_ROM_QSTR(MP_QSTR_GPIO11), MP_ROM_PTR(&pin_GPIO11) }, + { MP_ROM_QSTR(MP_QSTR_GPIO12), MP_ROM_PTR(&pin_GPIO12) }, + { MP_ROM_QSTR(MP_QSTR_GPIO13), MP_ROM_PTR(&pin_GPIO13) }, + { MP_ROM_QSTR(MP_QSTR_GPIO14), MP_ROM_PTR(&pin_GPIO14) }, + { MP_ROM_QSTR(MP_QSTR_GPIO15), MP_ROM_PTR(&pin_GPIO15) }, + { MP_ROM_QSTR(MP_QSTR_GPIO16), MP_ROM_PTR(&pin_GPIO16) }, + { MP_ROM_QSTR(MP_QSTR_GPIO17), MP_ROM_PTR(&pin_GPIO17) }, + { MP_ROM_QSTR(MP_QSTR_GPIO18), MP_ROM_PTR(&pin_GPIO18) }, + { MP_ROM_QSTR(MP_QSTR_GPIO19), MP_ROM_PTR(&pin_GPIO19) }, + { MP_ROM_QSTR(MP_QSTR_GPIO20), MP_ROM_PTR(&pin_GPIO20) }, + { MP_ROM_QSTR(MP_QSTR_GPIO21), MP_ROM_PTR(&pin_GPIO21) }, + { MP_ROM_QSTR(MP_QSTR_GPIO22), MP_ROM_PTR(&pin_GPIO22) }, + { MP_ROM_QSTR(MP_QSTR_GPIO23), MP_ROM_PTR(&pin_GPIO23) }, + { MP_ROM_QSTR(MP_QSTR_GPIO24), MP_ROM_PTR(&pin_GPIO24) }, + { MP_ROM_QSTR(MP_QSTR_GPIO25), MP_ROM_PTR(&pin_GPIO25) }, + { MP_ROM_QSTR(MP_QSTR_GPIO26), MP_ROM_PTR(&pin_GPIO26) }, + { MP_ROM_QSTR(MP_QSTR_GPIO27), MP_ROM_PTR(&pin_GPIO27) }, + { MP_ROM_QSTR(MP_QSTR_GPIO28), MP_ROM_PTR(&pin_GPIO28) }, + { MP_ROM_QSTR(MP_QSTR_GPIO29), MP_ROM_PTR(&pin_GPIO29) }, +}; +MP_DEFINE_CONST_DICT(mcu_pin_globals, mcu_pin_global_dict_table); diff --git a/ports/raspberrypi/common-hal/microcontroller/__init__.h b/ports/raspberrypi/common-hal/microcontroller/__init__.h new file mode 100644 index 000000000..cc509b6b1 --- /dev/null +++ b/ports/raspberrypi/common-hal/microcontroller/__init__.h @@ -0,0 +1,36 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 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. + */ + +#ifndef MICROPY_INCLUDED_RASPBERRYPI_COMMON_HAL_MICROCONTROLLER___INIT___H +#define MICROPY_INCLUDED_RASPBERRYPI_COMMON_HAL_MICROCONTROLLER___INIT___H + +#include "src/rp2040/hardware_regs/include/hardware/platform_defs.h" + +#define TOTAL_GPIO_COUNT NUM_BANK0_GPIOS + +extern const mp_rom_map_elem_t mcu_pin_global_dict_table[TOTAL_GPIO_COUNT]; + +#endif // MICROPY_INCLUDED_RASPBERRYPI_COMMON_HAL_MICROCONTROLLER___INIT___H diff --git a/ports/raspberrypi/common-hal/neopixel_write/__init__.c b/ports/raspberrypi/common-hal/neopixel_write/__init__.c new file mode 100644 index 000000000..10462b5a3 --- /dev/null +++ b/ports/raspberrypi/common-hal/neopixel_write/__init__.c @@ -0,0 +1,95 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 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 "shared-bindings/neopixel_write/__init__.h" + +#include "bindings/rp2pio/StateMachine.h" +#include "common-hal/rp2pio/StateMachine.h" +#include "shared-bindings/microcontroller/__init__.h" + +#include "supervisor/port.h" + +uint64_t next_start_raw_ticks = 0; + +// NeoPixels are 800khz bit streams. Zeroes are 1/3 duty cycle (~416ns) and ones +// are 2/3 duty cycle (~833ns). Each of the instructions below take 1/3 duty +// cycle. The first two instructions always run while only one of the two final +// instructions run per bit. We start with the low period because it can be +// longer than 1/3 period while waiting for more data. +const uint16_t neopixel_program[] = { +// bitloop: +// out x 1 side 0 [1]; Side-set still takes place before instruction stalls + 0x6121, +// jmp !x do_zero side 1 [1]; Branch on the bit we shifted out after 1/3 duty delay. Positive pulse + 0x1123, +// do_one: +// jmp bitloop side 1 [1]; Continue driving high, for a long pulse + 0x1100, +// do_zero: +// nop side 0 [1]; Or drive low, for a short pulse + 0xa142 +}; + +const uint16_t init_program[] = { + 0xe081 +}; + +void common_hal_neopixel_write(const digitalio_digitalinout_obj_t* digitalinout, uint8_t *pixels, uint32_t num_bytes) { + // Set everything up. + rp2pio_statemachine_obj_t state_machine; + + // TODO: Cache the state machine after we create it once. We'll need a way to + // change the pins then though. + uint8_t pin_number = digitalinout->pin->number; + bool ok = rp2pio_statemachine_construct(&state_machine, + neopixel_program, sizeof(neopixel_program) / sizeof(neopixel_program[0]), + 800000 * 6, // 800 khz * 6 cycles per bit + init_program, 1, + NULL, 1, + NULL, 1, + digitalinout->pin, 1, + digitalinout->pin, 1, + 1 << pin_number, true, false, + true, 8, false, // TX, auto pull every 8 bits. shift left to output msb first + false, 32, true, // RX setting we don't use + false); // claim pins + if (!ok) { + // Do nothing. Maybe bitbang? + return; + } + + // Wait to make sure we don't append onto the last transmission. This should only be a tick or + // two. + while (port_get_raw_ticks(NULL) < next_start_raw_ticks) {} + + common_hal_rp2pio_statemachine_write(&state_machine, pixels, num_bytes); + + // Use a private deinit of the state machine that doesn't reset the pin. + rp2pio_statemachine_deinit(&state_machine, true); + gpio_init(digitalinout->pin->number); + // Update the next start. + next_start_raw_ticks = port_get_raw_ticks(NULL) + 1; +} diff --git a/ports/raspberrypi/common-hal/os/__init__.c b/ports/raspberrypi/common-hal/os/__init__.c new file mode 100644 index 000000000..dcbd06e93 --- /dev/null +++ b/ports/raspberrypi/common-hal/os/__init__.c @@ -0,0 +1,62 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 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 "genhdr/mpversion.h" +#include "py/mpconfig.h" +#include "py/objstr.h" +#include "py/objtuple.h" +#include "py/qstr.h" + + +STATIC const qstr os_uname_info_fields[] = { + MP_QSTR_sysname, MP_QSTR_nodename, + MP_QSTR_release, MP_QSTR_version, MP_QSTR_machine +}; +STATIC const MP_DEFINE_STR_OBJ(os_uname_info_sysname_obj, "rp2040"); +STATIC const MP_DEFINE_STR_OBJ(os_uname_info_nodename_obj, "rp2040"); +STATIC const MP_DEFINE_STR_OBJ(os_uname_info_release_obj, MICROPY_VERSION_STRING); +STATIC const MP_DEFINE_STR_OBJ(os_uname_info_version_obj, MICROPY_GIT_TAG " on " MICROPY_BUILD_DATE); +STATIC const MP_DEFINE_STR_OBJ(os_uname_info_machine_obj, MICROPY_HW_BOARD_NAME " with " MICROPY_HW_MCU_NAME); + + +STATIC MP_DEFINE_ATTRTUPLE( + os_uname_info_obj, + os_uname_info_fields, + 5, + (mp_obj_t)&os_uname_info_sysname_obj, + (mp_obj_t)&os_uname_info_nodename_obj, + (mp_obj_t)&os_uname_info_release_obj, + (mp_obj_t)&os_uname_info_version_obj, + (mp_obj_t)&os_uname_info_machine_obj +); + +mp_obj_t common_hal_os_uname(void) { + return (mp_obj_t)&os_uname_info_obj; +} + +bool common_hal_os_urandom(uint8_t* buffer, uint32_t length) { + return false; +} diff --git a/ports/raspberrypi/common-hal/pwmio/PWMOut.c b/ports/raspberrypi/common-hal/pwmio/PWMOut.c new file mode 100644 index 000000000..567ec5ef5 --- /dev/null +++ b/ports/raspberrypi/common-hal/pwmio/PWMOut.c @@ -0,0 +1,216 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 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 <stdint.h> + +#include "py/runtime.h" +#include "common-hal/pwmio/PWMOut.h" +#include "shared-bindings/pwmio/PWMOut.h" +#include "shared-bindings/microcontroller/Processor.h" + +#include "supervisor/shared/translate.h" + +#include "src/rp2040/hardware_regs/include/hardware/platform_defs.h" +#include "src/rp2_common/hardware_clocks/include/hardware/clocks.h" +#include "src/rp2_common/hardware_gpio/include/hardware/gpio.h" +#include "src/rp2_common/hardware_pwm/include/hardware/pwm.h" + +uint32_t target_slice_frequencies[NUM_PWM_SLICES]; +uint32_t slice_fixed_frequency; + +#define CHANNELS_PER_SLICE 2 +static uint32_t channel_use; +static uint32_t never_reset_channel; + +static uint32_t _mask(uint8_t slice, uint8_t channel) { + return 1 << (slice * CHANNELS_PER_SLICE + channel); +} + +void common_hal_pwmio_pwmout_never_reset(pwmio_pwmout_obj_t *self) { + never_reset_channel |= _mask(self->slice, self->channel); + + never_reset_pin_number(self->pin->number); +} + +void common_hal_pwmio_pwmout_reset_ok(pwmio_pwmout_obj_t *self) { + never_reset_channel &= ~_mask(self->slice, self->channel); +} + +void pwmout_reset(void) { + // Reset all slices + for (size_t slice = 0; slice < NUM_PWM_SLICES; slice++) { + bool reset = true; + for (size_t channel = 0; channel < CHANNELS_PER_SLICE; channel++) { + uint32_t channel_use_mask = _mask(slice, channel); + if ((never_reset_channel & channel_use_mask) != 0) { + reset = false; + continue; + } + channel_use &= ~channel_use_mask; + } + if (!reset) { + continue; + } + pwm_set_enabled(slice, false); + target_slice_frequencies[slice] = 0; + slice_fixed_frequency &= ~(1 << slice); + } +} + +pwmout_result_t common_hal_pwmio_pwmout_construct(pwmio_pwmout_obj_t* self, + const mcu_pin_obj_t* pin, + uint16_t duty, + uint32_t frequency, + bool variable_frequency) { + self->pin = pin; + self->variable_frequency = variable_frequency; + self->duty_cycle = duty; + + if (frequency == 0 || frequency > (common_hal_mcu_processor_get_frequency() / 2)) { + return PWMOUT_INVALID_FREQUENCY; + } + + uint8_t slice = pwm_gpio_to_slice_num(pin->number); + uint8_t channel = pwm_gpio_to_channel(pin->number); + uint32_t channel_use_mask = _mask(slice, channel); + + // Check the channel first. + if ((channel_use & channel_use_mask) != 0) { + return PWMOUT_ALL_TIMERS_ON_PIN_IN_USE; + } + // Now check if the slice is in use and if we can share with it. + if (target_slice_frequencies[slice] > 0) { + // If we want to change frequency then we can't share. + if (variable_frequency) { + return PWMOUT_ALL_TIMERS_ON_PIN_IN_USE; + } + // If the other user wants to change frequency then we can't share either. + if ((slice_fixed_frequency & (1 << slice)) != 0) { + return PWMOUT_ALL_TIMERS_ON_PIN_IN_USE; + } + // If we're both fixed frequency but we don't match target frequencies then we can't share. + if (target_slice_frequencies[slice] != frequency) { + return PWMOUT_ALL_TIMERS_ON_PIN_IN_USE; + } + } + self->slice = slice; + self->channel = channel; + channel_use |= channel_use_mask; + if (!variable_frequency) { + slice_fixed_frequency |= 1 << slice; + } + + if (target_slice_frequencies[slice] != frequency) { + // Reset the counter and compare values. + pwm_hw->slice[slice].ctr = PWM_CH0_CTR_RESET; + common_hal_pwmio_pwmout_set_duty_cycle(self, duty); + common_hal_pwmio_pwmout_set_frequency(self, frequency); + pwm_set_enabled(slice, true); + } else { + common_hal_pwmio_pwmout_set_duty_cycle(self, duty); + } + + // Connect to the pad last to avoid any glitches from changing settings. + gpio_set_function(pin->number, GPIO_FUNC_PWM); + + return PWMOUT_OK; +} + +bool common_hal_pwmio_pwmout_deinited(pwmio_pwmout_obj_t* self) { + return self->pin == NULL; +} + +void common_hal_pwmio_pwmout_deinit(pwmio_pwmout_obj_t* self) { + if (common_hal_pwmio_pwmout_deinited(self)) { + return; + } + uint32_t channel_mask = _mask(self->slice, self->channel); + channel_use &= ~channel_mask; + never_reset_channel &= ~channel_mask; + uint32_t slice_mask = ((1 << CHANNELS_PER_SLICE) - 1) << (self->slice * CHANNELS_PER_SLICE + self->channel); + if ((channel_use & slice_mask) == 0) { + target_slice_frequencies[self->slice] = 0; + slice_fixed_frequency &= ~(1 << self->slice); + pwm_set_enabled(self->slice, false); + } + + reset_pin_number(self->pin->number); + self->pin = NULL; +} + +extern void common_hal_pwmio_pwmout_set_duty_cycle(pwmio_pwmout_obj_t* self, uint16_t duty) { + self->duty_cycle = duty; + uint16_t actual_duty = duty * self->top / ((1 << 16) - 1); + pwm_set_chan_level(self->slice, self->channel, actual_duty); +} + +uint16_t common_hal_pwmio_pwmout_get_duty_cycle(pwmio_pwmout_obj_t* self) { + return self->duty_cycle; +} + +void common_hal_pwmio_pwmout_set_frequency(pwmio_pwmout_obj_t* self, uint32_t frequency) { + if (frequency == 0 || frequency > (common_hal_mcu_processor_get_frequency() / 2)) { + mp_raise_ValueError(translate("Invalid PWM frequency")); + } + + target_slice_frequencies[self->slice] = frequency; + + // For low frequencies use the divider to give us full resolution duty_cycle. + if (frequency < (common_hal_mcu_processor_get_frequency() / (1 << 16))) { + // Compute the divisor. It's an 8 bit integer and 4 bit fraction. Therefore, + // we compute everything * 16 for the fractional part. + // This is 1 << 12 because 4 bits are the * 16. + uint64_t frequency16 = ((uint64_t) clock_get_hz(clk_sys)) / (1 << 12); + uint64_t div16 = frequency16 / frequency; + // Round the divisor to try and get closest to the target frequency. We could + // also always round up and use TOP to get us closer. We may not need that though. + if (frequency16 % frequency >= frequency / 2) { + div16 += 1; + } + if (div16 >= (1 << 12)) { + div16 = (1 << 12) - 1; + } + self->actual_frequency = frequency16 / div16; + self->top = 1 << 16; + pwm_set_clkdiv_int_frac(self->slice, div16 / 16, div16 % 16); + pwm_set_wrap(self->slice, self->top - 1); + } else { + uint32_t top = common_hal_mcu_processor_get_frequency() / frequency; + self->actual_frequency = common_hal_mcu_processor_get_frequency() / top; + self->top = top; + pwm_set_clkdiv_int_frac(self->slice, 1, 0); + pwm_set_wrap(self->slice, self->top - 1); + } + common_hal_pwmio_pwmout_set_duty_cycle(self, self->duty_cycle); +} + +uint32_t common_hal_pwmio_pwmout_get_frequency(pwmio_pwmout_obj_t* self) { + return self->actual_frequency; +} + +bool common_hal_pwmio_pwmout_get_variable_frequency(pwmio_pwmout_obj_t* self) { + return self->variable_frequency; +} diff --git a/ports/raspberrypi/common-hal/pwmio/PWMOut.h b/ports/raspberrypi/common-hal/pwmio/PWMOut.h new file mode 100644 index 000000000..50f84777b --- /dev/null +++ b/ports/raspberrypi/common-hal/pwmio/PWMOut.h @@ -0,0 +1,47 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 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. + */ + +#ifndef MICROPY_INCLUDED_ATMEL_SAMD_COMMON_HAL_PWMIO_PWMOUT_H +#define MICROPY_INCLUDED_ATMEL_SAMD_COMMON_HAL_PWMIO_PWMOUT_H + +#include "common-hal/microcontroller/Pin.h" + +#include "py/obj.h" + +typedef struct { + mp_obj_base_t base; + const mcu_pin_obj_t *pin; + uint8_t slice; + uint8_t channel; + bool variable_frequency; + uint16_t duty_cycle; + uint32_t actual_frequency; + uint32_t top; +} pwmio_pwmout_obj_t; + +void pwmout_reset(void); + +#endif // MICROPY_INCLUDED_ATMEL_SAMD_COMMON_HAL_PWMIO_PWMOUT_H diff --git a/ports/raspberrypi/common-hal/pwmio/__init__.c b/ports/raspberrypi/common-hal/pwmio/__init__.c new file mode 100644 index 000000000..9e551a107 --- /dev/null +++ b/ports/raspberrypi/common-hal/pwmio/__init__.c @@ -0,0 +1 @@ +// No pwmio module functions. diff --git a/ports/raspberrypi/common-hal/rp2pio/StateMachine.c b/ports/raspberrypi/common-hal/rp2pio/StateMachine.c new file mode 100644 index 000000000..6510410b0 --- /dev/null +++ b/ports/raspberrypi/common-hal/rp2pio/StateMachine.c @@ -0,0 +1,585 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 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 "bindings/rp2pio/StateMachine.h" + +#include "common-hal/microcontroller/__init__.h" +#include "shared-bindings/microcontroller/Pin.h" + +#include "src/rp2040/hardware_regs/include/hardware/platform_defs.h" +#include "src/rp2_common/hardware_clocks/include/hardware/clocks.h" +#include "src/rp2_common/hardware_dma/include/hardware/dma.h" +#include "src/rp2_common/hardware_pio/include/hardware/pio_instructions.h" +#include "src/rp2040/hardware_structs/include/hardware/structs/iobank0.h" + +#include "lib/utils/interrupt_char.h" +#include "py/obj.h" +#include "py/objproperty.h" +#include "py/runtime.h" + +// Count how many state machines are using each pin. +STATIC uint8_t _pin_reference_count[TOTAL_GPIO_COUNT]; +STATIC uint32_t _current_program_id[NUM_PIOS][NUM_PIO_STATE_MACHINES]; +STATIC uint8_t _current_program_offset[NUM_PIOS][NUM_PIO_STATE_MACHINES]; +STATIC uint8_t _current_program_len[NUM_PIOS][NUM_PIO_STATE_MACHINES]; +STATIC bool _never_reset[NUM_PIOS][NUM_PIO_STATE_MACHINES]; + +STATIC uint32_t _current_pins[NUM_PIOS]; +STATIC uint32_t _current_sm_pins[NUM_PIOS][NUM_PIO_STATE_MACHINES]; + +STATIC PIO pio_instances[2] = {pio0, pio1}; + +void _reset_statemachine(PIO pio, uint8_t sm, bool leave_pins) { + uint8_t pio_index = pio_get_index(pio); + pio_sm_unclaim(pio, sm); + uint32_t program_id = _current_program_id[pio_index][sm]; + if (program_id == 0) { + return; + } + _current_program_id[pio_index][sm] = 0; + bool program_in_use = false; + for (size_t i = 0; i < NUM_PIO_STATE_MACHINES; i++) { + if (_current_program_id[pio_index][i] == program_id) { + program_in_use = true; + break; + } + } + if (!program_in_use) { + uint8_t offset = _current_program_offset[pio_index][sm]; + pio_program_t program_struct = { + .length = _current_program_len[pio_index][sm] + }; + pio_remove_program(pio, &program_struct, offset); + } + + uint32_t pins = _current_sm_pins[pio_index][sm]; + for (size_t pin_number = 0; pin_number < TOTAL_GPIO_COUNT; pin_number++) { + if ((pins & (1 << pin_number)) == 0) { + continue; + } + _pin_reference_count[pin_number]--; + if (_pin_reference_count[pin_number] == 0) { + if (!leave_pins) { + reset_pin_number(pin_number); + } + _current_pins[pio_index] &= ~(1 << pin_number); + } + } + _current_sm_pins[pio_index][sm] = 0; +} + +void reset_rp2pio_statemachine(void) { + for (size_t i = 0; i < NUM_PIOS; i++) { + PIO pio = pio_instances[i]; + for (size_t j = 0; j < NUM_PIO_STATE_MACHINES; j++) { + if (_never_reset[i][j]) { + continue; + } + _reset_statemachine(pio, j, false); + } + } +} + +STATIC uint32_t _check_pins_free(const mcu_pin_obj_t * first_pin, uint8_t pin_count, bool exclusive_pin_use) { + uint32_t pins_we_use = 0; + if (first_pin != NULL) { + for (size_t i = 0; i < pin_count; i++) { + uint8_t pin_number = first_pin->number + i; + if (pin_number >= TOTAL_GPIO_COUNT) { + mp_raise_ValueError(translate("Pin count too large")); + } + const mcu_pin_obj_t * pin = mcu_pin_global_dict_table[pin_number].value; + if (exclusive_pin_use || _pin_reference_count[pin_number] == 0) { + assert_pin_free(pin); + } + pins_we_use |= 1 << pin_number; + } + } + return pins_we_use; +} + + +bool rp2pio_statemachine_construct(rp2pio_statemachine_obj_t *self, + const uint16_t* program, size_t program_len, + size_t frequency, + const uint16_t* init, size_t init_len, + const mcu_pin_obj_t * first_out_pin, uint8_t out_pin_count, + const mcu_pin_obj_t * first_in_pin, uint8_t in_pin_count, + const mcu_pin_obj_t * first_set_pin, uint8_t set_pin_count, + const mcu_pin_obj_t * first_sideset_pin, uint8_t sideset_pin_count, + uint32_t pins_we_use, bool tx_fifo, bool rx_fifo, + bool auto_pull, uint8_t pull_threshold, bool out_shift_right, + bool auto_push, uint8_t push_threshold, bool in_shift_right, + bool claim_pins) { + // Create a program id that isn't the pointer so we can store it without storing the original object. + uint32_t program_id = ~((uint32_t) program); + + // Next, find a PIO and state machine to use. + size_t pio_index = NUM_PIOS; + uint8_t program_offset = 32; + pio_program_t program_struct = { + .instructions = (uint16_t*) program, + .length = program_len, + .origin = 0 + }; + for (size_t i = 0; i < NUM_PIOS; i++) { + PIO pio = pio_instances[i]; + uint8_t free_count = 0; + for (size_t j = 0; j < NUM_PIO_STATE_MACHINES; j++) { + if (_current_program_id[i][j] == program_id && + _current_program_len[i][j] == program_len) { + program_offset = _current_program_offset[i][j]; + } + int temp_claim = pio_claim_unused_sm(pio, false); + if (temp_claim >= 0) { + pio_sm_unclaim(pio, temp_claim); + free_count++; + } + } + if (free_count > 0 && (program_offset < 32 || pio_can_add_program(pio, &program_struct))) { + pio_index = i; + if (program_offset < 32) { + break; + } + } + // Reset program offset if we weren't able to find a free state machine + // on that PIO. (We would have broken the loop otherwise.) + program_offset = 32; + } + + int state_machine = -1; + if (pio_index < NUM_PIOS) { + PIO pio = pio_instances[pio_index]; + for (size_t i = 0; i < NUM_PIOS; i++) { + if (i == pio_index) { + continue; + } + if ((_current_pins[i] & pins_we_use) != 0) { + // Pin in use by another PIO already. + return false; + } + } + state_machine = pio_claim_unused_sm(pio, false); + } + if (pio_index == NUM_PIOS || state_machine < 0 || state_machine >= NUM_PIO_STATE_MACHINES) { + return false; + } + + self->pio = pio_instances[pio_index]; + self->state_machine = state_machine; + if (program_offset == 32) { + program_offset = pio_add_program(self->pio, &program_struct); + } + _current_program_id[pio_index][state_machine] = program_id; + _current_program_len[pio_index][state_machine] = program_len; + _current_program_offset[pio_index][state_machine] = program_offset; + _current_sm_pins[pio_index][state_machine] = pins_we_use; + _current_pins[pio_index] |= pins_we_use; + + for (size_t pin_number = 0; pin_number < TOTAL_GPIO_COUNT; pin_number++) { + if ((pins_we_use & (1 << pin_number)) == 0) { + continue; + } + _pin_reference_count[pin_number]++; + const mcu_pin_obj_t * pin = mcu_pin_global_dict_table[pin_number].value; + // Also claim the pin at the top level when we're the first to grab it. + if (_pin_reference_count[pin_number] == 1) { + if (claim_pins) { + claim_pin(pin); + } + pio_gpio_init(self->pio, pin_number); + } + } + + pio_sm_config c = {0, 0, 0}; + + if (frequency == 0) { + frequency = clock_get_hz(clk_sys); + } + uint64_t frequency256 = ((uint64_t) clock_get_hz(clk_sys)) * 256; + uint64_t div256 = frequency256 / frequency; + if (frequency256 % div256 > 0) { + div256 += 1; + } + self->actual_frequency = frequency256 / div256; + sm_config_set_clkdiv_int_frac(&c, div256 / 256, div256 % 256); + + if (first_out_pin != NULL) { + sm_config_set_out_pins(&c, first_out_pin->number, out_pin_count); + } + if (first_in_pin != NULL) { + sm_config_set_in_pins(&c, first_in_pin->number); + } + if (first_set_pin != NULL) { + sm_config_set_set_pins(&c, first_set_pin->number, set_pin_count); + } + if (first_sideset_pin != NULL) { + sm_config_set_sideset(&c, sideset_pin_count, false /* optional */, false /* pin direction */); + sm_config_set_sideset_pins(&c, first_sideset_pin->number); + } + sm_config_set_wrap(&c, program_offset, program_offset + program_len - 1); + sm_config_set_in_shift(&c, in_shift_right, auto_push, push_threshold); + sm_config_set_out_shift(&c, out_shift_right, auto_pull, pull_threshold); + + enum pio_fifo_join join = PIO_FIFO_JOIN_NONE; + if (!rx_fifo) { + join = PIO_FIFO_JOIN_TX; + } else if (!tx_fifo) { + join = PIO_FIFO_JOIN_RX; + } + if (rx_fifo) { + self->rx_dreq = pio_get_dreq(self->pio, self->state_machine, false); + } + if (tx_fifo) { + self->tx_dreq = pio_get_dreq(self->pio, self->state_machine, true); + } + self->in = rx_fifo; + self->out = tx_fifo; + self->out_shift_right = out_shift_right; + self->in_shift_right = in_shift_right; + + sm_config_set_fifo_join(&c, join); + + pio_sm_init(self->pio, self->state_machine, program_offset, &c); + pio_sm_set_enabled(self->pio, self->state_machine, true); + for (size_t i = 0; i < init_len; i++) { + pio_sm_exec(self->pio, self->state_machine, init[i]); + } + return true; +} + +void common_hal_rp2pio_statemachine_construct(rp2pio_statemachine_obj_t *self, + const uint16_t* program, size_t program_len, + size_t frequency, + const uint16_t* init, size_t init_len, + const mcu_pin_obj_t * first_out_pin, uint8_t out_pin_count, + const mcu_pin_obj_t * first_in_pin, uint8_t in_pin_count, + const mcu_pin_obj_t * first_set_pin, uint8_t set_pin_count, + const mcu_pin_obj_t * first_sideset_pin, uint8_t sideset_pin_count, + bool exclusive_pin_use, + bool auto_pull, uint8_t pull_threshold, bool out_shift_right, + bool auto_push, uint8_t push_threshold, bool in_shift_right) { + + // First, check that all pins are free OR already in use by any PIO if exclusive_pin_use is false. + uint32_t pins_we_use = 0; + pins_we_use |= _check_pins_free(first_out_pin, out_pin_count, exclusive_pin_use); + pins_we_use |= _check_pins_free(first_in_pin, in_pin_count, exclusive_pin_use); + pins_we_use |= _check_pins_free(first_set_pin, set_pin_count, exclusive_pin_use); + pins_we_use |= _check_pins_free(first_sideset_pin, sideset_pin_count, exclusive_pin_use); + + // Look through the program to see what we reference and make sure it was provided. + bool tx_fifo = false; + bool rx_fifo = false; + bool in_loaded = false; // can be loaded in other ways besides the fifo + bool out_loaded = false; + bool in_used = false; + bool out_used = false; + for (size_t i = 0; i < program_len; i++) { + uint16_t full_instruction = program[i]; + uint16_t instruction = full_instruction & 0xe000; + if (instruction == 0x8000) { + if ((full_instruction & 0xe080) == pio_instr_bits_push) { + rx_fifo = true; + in_loaded = true; + } else { // pull otherwise. + tx_fifo = true; + out_loaded = true; + } + } + if (instruction == pio_instr_bits_jmp) { + uint16_t condition = (full_instruction & 0x00e0) >> 5; + if (condition == 0x6) { // GPIO + mp_raise_NotImplementedError_varg(translate("Instruction %d jumps on pin"), i); + } + } + if (instruction == pio_instr_bits_wait) { + uint16_t wait_source = (full_instruction & 0x0060) >> 5; + uint16_t wait_index = full_instruction & 0x001f; + if (wait_source == 0 && (pins_we_use & (1 << wait_index)) == 0) { // GPIO + mp_raise_ValueError_varg(translate("Instruction %d uses extra pin"), i); + } + if (wait_source == 1) { // Input pin + if (first_in_pin == NULL) { + mp_raise_ValueError_varg(translate("Missing first_in_pin. Instruction %d waits based on pin"), i); + } + if (wait_index > in_pin_count) { + mp_raise_ValueError_varg(translate("Instruction %d waits on input outside of count"), i); + } + } + } + if (instruction == pio_instr_bits_in) { + uint16_t source = (full_instruction & 0x00e0) >> 5; + uint16_t bit_count = full_instruction & 0x001f; + if (source == 0) { + if (first_in_pin == NULL) { + mp_raise_ValueError_varg(translate("Missing first_in_pin. Instruction %d shifts in from pin(s)"), i); + } + if (bit_count > in_pin_count) { + mp_raise_ValueError_varg(translate("Instruction %d shifts in more bits than pin count"), i); + } + } + if (auto_push) { + in_loaded = true; + rx_fifo = true; + } + in_used = true; + } + if (instruction == pio_instr_bits_out) { + uint16_t bit_count = full_instruction & 0x001f; + uint16_t destination = (full_instruction & 0x00e0) >> 5; + // Check for pins or pindirs destination. + if (destination == 0x0 || destination == 0x4) { + if (first_out_pin == NULL) { + mp_raise_ValueError_varg(translate("Missing first_out_pin. Instruction %d shifts out to pin(s)"), i); + } + if (bit_count > out_pin_count) { + mp_raise_ValueError_varg(translate("Instruction %d shifts out more bits than pin count"), i); + } + } + if (auto_pull) { + out_loaded = true; + tx_fifo = true; + } + out_used = true; + } + if (instruction == pio_instr_bits_set) { + uint16_t destination = (full_instruction & 0x00e0) >> 5; + // Check for pins or pindirs destination. + if ((destination == 0x00 || destination == 0x4) && first_set_pin == NULL) { + mp_raise_ValueError_varg(translate("Missing first_set_pin. Instruction %d sets pin(s)"), i); + } + } + if (instruction == pio_instr_bits_mov) { + uint16_t source = full_instruction & 0x0007; + uint16_t destination = (full_instruction & 0x00e0) >> 5; + // Check for pins or pindirs destination. + if (destination == 0x0 && first_out_pin == NULL) { + mp_raise_ValueError_varg(translate("Missing first_out_pin. Instruction %d writes pin(s)"), i); + } + if (source == 0x0 && first_in_pin == NULL) { + mp_raise_ValueError_varg(translate("Missing first_in_pin. Instruction %d reads pin(s)"), i); + } + if (destination == 0x6) { + in_loaded = true; + } else if (destination == 0x7) { + out_loaded = true; + } + } + } + + if (!in_loaded && in_used) { + mp_raise_ValueError_varg(translate("Program does IN without loading ISR")); + } + if (!out_loaded && out_used) { + mp_raise_ValueError_varg(translate("Program does OUT without loading OSR")); + } + + if (in_pin_count > 8 || out_pin_count > 8) { + mp_raise_NotImplementedError(translate("Only IN/OUT of up to 8 supported")); + } + + bool ok = rp2pio_statemachine_construct(self, + program, program_len, + frequency, + init, init_len, + first_out_pin, out_pin_count, + first_in_pin, in_pin_count, + first_set_pin, set_pin_count, + first_sideset_pin, sideset_pin_count, + pins_we_use, tx_fifo, rx_fifo, + auto_pull, pull_threshold, out_shift_right, + auto_push, push_threshold, in_shift_right, + true /* claim pins */); + if (!ok) { + mp_raise_RuntimeError(translate("All state machines in use")); + } +} + +uint32_t common_hal_rp2pio_statemachine_get_frequency(rp2pio_statemachine_obj_t* self) { + return self->actual_frequency; +} + +void rp2pio_statemachine_deinit(rp2pio_statemachine_obj_t *self, bool leave_pins) { + uint8_t sm = self->state_machine; + uint8_t pio_index = pio_get_index(self->pio); + _never_reset[pio_index][sm] = false; + _reset_statemachine(self->pio, sm, leave_pins); + self->state_machine = NUM_PIO_STATE_MACHINES; +} + +void common_hal_rp2pio_statemachine_deinit(rp2pio_statemachine_obj_t *self) { + rp2pio_statemachine_deinit(self, false); +} + +void common_hal_rp2pio_statemachine_never_reset(rp2pio_statemachine_obj_t *self) { + uint8_t sm = self->state_machine; + uint8_t pio_index = pio_get_index(self->pio); + _never_reset[pio_index][sm] = true; + // TODO: never reset all the pins +} + +bool common_hal_rp2pio_statemachine_deinited(rp2pio_statemachine_obj_t *self) { + return self->state_machine == NUM_PIO_STATE_MACHINES; +} + +static bool _transfer(rp2pio_statemachine_obj_t *self, + const uint8_t *data_out, size_t out_len, + uint8_t *data_in, size_t in_len) { + // This implementation is based on SPI but varies because the tx and rx buffers + // may be different lengths and occur at different times or speeds. + + // Use DMA for large transfers if channels are available + const size_t dma_min_size_threshold = 32; + int chan_tx = -1; + int chan_rx = -1; + size_t len = MAX(out_len, in_len); + bool tx = data_out != NULL; + bool rx = data_in != NULL; + if (len >= dma_min_size_threshold) { + // Use DMA channels to service the two FIFOs + if (tx) { + chan_tx = dma_claim_unused_channel(false); + } + if (rx) { + chan_rx = dma_claim_unused_channel(false); + } + } + volatile uint8_t* tx_destination = NULL; + const volatile uint8_t* rx_source = NULL; + if (tx) { + tx_destination = (volatile uint8_t*) &self->pio->txf[self->state_machine]; + if (!self->out_shift_right) { + tx_destination += 3; + } + } + if (rx) { + rx_source = (const volatile uint8_t*) &self->pio->rxf[self->state_machine]; + if (!self->in_shift_right) { + rx_source += 3; + } + } + bool use_dma = (!rx || chan_rx >= 0) && (!tx || chan_tx >= 0); + if (use_dma) { + dma_channel_config c; + uint32_t channel_mask = 0; + if (tx) { + c = dma_channel_get_default_config(chan_tx); + channel_config_set_transfer_data_size(&c, DMA_SIZE_8); + channel_config_set_dreq(&c, self->tx_dreq); + channel_config_set_read_increment(&c, true); + channel_config_set_write_increment(&c, false); + dma_channel_configure(chan_tx, &c, + tx_destination, + data_out, + len, + false); + channel_mask |= 1u << chan_tx; + } + if (rx) { + c = dma_channel_get_default_config(chan_rx); + channel_config_set_transfer_data_size(&c, DMA_SIZE_8); + channel_config_set_dreq(&c, self->rx_dreq); + channel_config_set_read_increment(&c, false); + channel_config_set_write_increment(&c, true); + dma_channel_configure(chan_rx, &c, + data_in, + rx_source, + len, + false); + channel_mask |= 1u << chan_rx; + } + + dma_start_channel_mask(channel_mask); + while ((rx && dma_channel_is_busy(chan_rx)) || + (tx && dma_channel_is_busy(chan_tx))) { + // TODO: We should idle here until we get a DMA interrupt or something else. + RUN_BACKGROUND_TASKS; + if (mp_hal_is_interrupted()) { + if (rx && dma_channel_is_busy(chan_rx)) { + dma_channel_abort(chan_rx); + } + if (tx && dma_channel_is_busy(chan_tx)) { + dma_channel_abort(chan_tx); + } + break; + } + } + // Clear the stall bit so we can detect when the state machine is done transmitting. + self->pio->fdebug = PIO_FDEBUG_TXSTALL_BITS; + } + + // If we have claimed only one channel successfully, we should release immediately. This also + // releases the DMA after use_dma has been done. + if (chan_rx >= 0) { + dma_channel_unclaim(chan_rx); + } + if (chan_tx >= 0) { + dma_channel_unclaim(chan_tx); + } + + if (!use_dma && !mp_hal_is_interrupted()) { + // Use software for small transfers, or if couldn't claim two DMA channels + size_t rx_remaining = in_len; + size_t tx_remaining = out_len; + + while (rx_remaining || tx_remaining) { + if (tx_remaining && !pio_sm_is_tx_fifo_full(self->pio, self->state_machine)) { + *tx_destination = *data_out; + data_out++; + --tx_remaining; + } + if (rx_remaining && !pio_sm_is_rx_fifo_empty(self->pio, self->state_machine)) { + *data_in = (uint8_t) *rx_source; + data_in++; + --rx_remaining; + } + RUN_BACKGROUND_TASKS; + if (mp_hal_is_interrupted()) { + break; + } + } + // Clear the stall bit so we can detect when the state machine is done transmitting. + self->pio->fdebug = PIO_FDEBUG_TXSTALL_BITS; + } + // Wait for the state machine to finish transmitting the data we've queued + // up. + if (tx) { + while (!pio_sm_is_tx_fifo_empty(self->pio, self->state_machine) || + (self->pio->fdebug & PIO_FDEBUG_TXSTALL_BITS) == 0) { + RUN_BACKGROUND_TASKS; + } + } + return true; +} + +// Writes out the given data. +bool common_hal_rp2pio_statemachine_write(rp2pio_statemachine_obj_t *self, + const uint8_t *data, size_t len) { + if (!self->out) { + mp_raise_RuntimeError(translate("No out in program")); + } + return _transfer(self, data, len, NULL, 0); +} diff --git a/ports/raspberrypi/common-hal/rp2pio/StateMachine.h b/ports/raspberrypi/common-hal/rp2pio/StateMachine.h new file mode 100644 index 000000000..6b70b6b5b --- /dev/null +++ b/ports/raspberrypi/common-hal/rp2pio/StateMachine.h @@ -0,0 +1,68 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 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. + */ + +#ifndef MICROPY_INCLUDED_RASPBERRYPI_COMMON_HAL_RP2PIO_STATEMACHINE_H +#define MICROPY_INCLUDED_RASPBERRYPI_COMMON_HAL_RP2PIO_STATEMACHINE_H + +#include "py/obj.h" + +#include "src/rp2_common/hardware_pio/include/hardware/pio.h" + +typedef struct { + mp_obj_base_t base; + uint32_t pins; // Bitmask of what pins this state machine uses. + int state_machine; + PIO pio; + bool in; + bool out; + uint tx_dreq; + uint rx_dreq; + bool out_shift_right; + bool in_shift_right; + uint32_t actual_frequency; +} rp2pio_statemachine_obj_t; + +void reset_rp2pio_statemachine(void); + +// Minimal internal version that only fails on pin error (not in use) or full PIO. +bool rp2pio_statemachine_construct(rp2pio_statemachine_obj_t *self, + const uint16_t* program, size_t program_len, + size_t frequency, + const uint16_t* init, size_t init_len, + const mcu_pin_obj_t * first_out_pin, uint8_t out_pin_count, + const mcu_pin_obj_t * first_in_pin, uint8_t in_pin_count, + const mcu_pin_obj_t * first_set_pin, uint8_t set_pin_count, + const mcu_pin_obj_t * first_sideset_pin, uint8_t sideset_pin_count, + uint32_t pins_we_use, bool tx_fifo, bool rx_fifo, + bool auto_pull, uint8_t pull_threshold, bool out_shift_right, + bool auto_push, uint8_t push_threshold, bool in_shift_right, + bool claim_pins); + +void rp2pio_statemachine_deinit(rp2pio_statemachine_obj_t *self, bool leave_pins); + +extern const mp_obj_type_t rp2pio_statemachine_type; + +#endif // MICROPY_INCLUDED_RASPBERRYPI_COMMON_HAL_RP2PIO_STATEMACHINE_H diff --git a/ports/raspberrypi/common-hal/rp2pio/__init__.c b/ports/raspberrypi/common-hal/rp2pio/__init__.c new file mode 100644 index 000000000..21699dfa3 --- /dev/null +++ b/ports/raspberrypi/common-hal/rp2pio/__init__.c @@ -0,0 +1 @@ +// Nothing yet. diff --git a/ports/raspberrypi/common-hal/supervisor/Runtime.c b/ports/raspberrypi/common-hal/supervisor/Runtime.c new file mode 100755 index 000000000..6be38f216 --- /dev/null +++ b/ports/raspberrypi/common-hal/supervisor/Runtime.c @@ -0,0 +1,37 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 Michael Schroeder + * + * 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 <stdbool.h> +#include "shared-bindings/supervisor/Runtime.h" +#include "supervisor/serial.h" + +bool common_hal_get_serial_connected(void) { + return (bool) serial_connected(); +} + +bool common_hal_get_serial_bytes_available(void) { + return (bool) serial_bytes_available(); +} diff --git a/ports/raspberrypi/common-hal/supervisor/Runtime.h b/ports/raspberrypi/common-hal/supervisor/Runtime.h new file mode 100755 index 000000000..45db489bd --- /dev/null +++ b/ports/raspberrypi/common-hal/supervisor/Runtime.h @@ -0,0 +1,37 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 Michael Schroeder + * + * 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_RASPBERRYPI_COMMON_HAL_SUPERVISOR_RUNTIME_H +#define MICROPY_INCLUDED_RASPBERRYPI_COMMON_HAL_SUPERVISOR_RUNTIME_H + +#include "py/obj.h" + +typedef struct { + mp_obj_base_t base; + // Stores no state currently. +} super_runtime_obj_t; + +#endif // MICROPY_INCLUDED_RASPBERRYPI_COMMON_HAL_SUPERVISOR_RUNTIME_H diff --git a/ports/raspberrypi/common-hal/supervisor/__init__.c b/ports/raspberrypi/common-hal/supervisor/__init__.c new file mode 100755 index 000000000..6dca35fb5 --- /dev/null +++ b/ports/raspberrypi/common-hal/supervisor/__init__.c @@ -0,0 +1,40 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 Michael Schroeder + * + * 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 "py/obj.h" + +#include "shared-bindings/supervisor/__init__.h" +#include "shared-bindings/supervisor/Runtime.h" + + +// The singleton supervisor.Runtime object, bound to supervisor.runtime +// It currently only has properties, and no state. +const super_runtime_obj_t common_hal_supervisor_runtime_obj = { + .base = { + .type = &supervisor_runtime_type, + }, +}; |
