diff --git a/.gitmodules b/.gitmodules index fbb74f013e..a7f31837a3 100644 --- a/.gitmodules +++ b/.gitmodules @@ -26,6 +26,9 @@ [submodule "frozen/Adafruit_CircuitPython_BusDevice"] path = frozen/Adafruit_CircuitPython_BusDevice url = https://github.com/adafruit/Adafruit_CircuitPython_BusDevice.git +[submodule "tools/python-semver"] + path = tools/python-semver + url = https://github.com/k-bx/python-semver.git [submodule "lib/stm32lib"] path = lib/stm32lib url = https://github.com/micropython/stm32lib diff --git a/.readthedocs.yml b/.readthedocs.yml new file mode 100644 index 0000000000..8b77f690a1 --- /dev/null +++ b/.readthedocs.yml @@ -0,0 +1,2 @@ +python: + version: 3 diff --git a/docs/troubleshooting.rst b/docs/troubleshooting.rst index 34ee392d25..1c7e87f61b 100644 --- a/docs/troubleshooting.rst +++ b/docs/troubleshooting.rst @@ -15,19 +15,29 @@ This often happens on Windows when the ``CIRCUITPY`` disk is not safely ejected before being reset by the button or being disconnected from USB. This can also happen on Linux and Mac OSX but its less likely. -.. caution:: Delete ``CIRCUITPY`` filesystem and reload CircuitPython. +.. caution:: To erase and re-create ``CIRCUITPY`` (for example, to correct a corrupted filesystem), + follow one of the procedures below. It's important to note that **any files stored on the** + ``CIRCUITPY`` **drive will be erased**. - To reload CircuitPython (for example, to correct a corrupted filesystem), - follow the process below. It's important to note that **any files stored on the - ``CIRCUITPY`` drive will be erased**. +**For boards with** ``CIRCUITPY`` **stored on a separate SPI flash chip, +such as Feather M0 Express, Metro M0 Express and Circuit Playground Express:** -#. Download the appropriate flash erase uf2 from `here `_. + +#. Download the appropriate flash .erase uf2 from `here `_. #. Double-click the reset button. #. Copy the appropriate .uf2 to the xxxBOOT drive. #. The on-board NeoPixel will turn blue, indicating the erase has started. #. After about 15 seconds, the NexoPixel will start flashing green. If it flashes red, the erase failed. #. Double-click again and load the appropriate `CircuitPython .uf2 `_. +**For boards without SPI flash, such as Feather M0 Proto, Gemma M0 and, Trinket M0:** + +#. Download the appropriate erase .uf2 from `here `_. +#. Double-click the reset button. +#. Copy the appropriate .uf2 to the xxxBOOT drive. +#. The boot LED will start pulsing again, and the xxxBOOT drive will appear again. +#. Load the appropriate `CircuitPython .uf2 `_. + ValueError: Incompatible ``.mpy`` file. --------------------------------------- @@ -35,9 +45,9 @@ This error occurs when importing a module that is stored as a ``mpy`` binary fil (rather than a ``py`` text file) that was generated by a different version of CircuitPython than the one its being loaded into. Most versions are compatible but, rarely they aren't. In particular, the ``mpy`` binary format changed between -CircuitPython versions 1.x and 2.x. +CircuitPython versions 1.x and 2.x, and will change again between 2.x and 3.x. -So, if you just upgraded to CircuitPython 2.x from 1.x you'll need to download a +So, for instance, if you just upgraded to CircuitPython 2.x from 1.x you'll need to download a newer version of the library that triggered the error on ``import``. They are all available in the `Adafruit bundle `_ diff --git a/lib/libm/nearbyintf.c b/lib/libm/nearbyintf.c index 1bb44aa466..5ac3178b51 100644 --- a/lib/libm/nearbyintf.c +++ b/lib/libm/nearbyintf.c @@ -18,7 +18,7 @@ float nearbyintf(float x) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wfloat-equal" if (y == 0) -#pragma GCC diagnostic pop return s ? -0.0f : 0.0f; +#pragma GCC diagnostic pop return y; } diff --git a/lib/utils/pyexec.c b/lib/utils/pyexec.c index df93614a10..f96deb9e1c 100644 --- a/lib/utils/pyexec.c +++ b/lib/utils/pyexec.c @@ -255,7 +255,8 @@ STATIC int pyexec_friendly_repl_process_char(int c) { } else if (ret == CHAR_CTRL_B) { // reset friendly REPL mp_hal_stdout_tx_str("\r\n"); - mp_hal_stdout_tx_str("Adafruit CircuitPython " MICROPY_GIT_TAG " on " MICROPY_BUILD_DATE "; " MICROPY_HW_BOARD_NAME " with " MICROPY_HW_MCU_NAME "\r\n"); + mp_hal_stdout_tx_str(MICROPY_FULL_VERSION_INFO); + mp_hal_stdout_tx_str("\r\n"); // mp_hal_stdout_tx_str("Type \"help()\" for more information.\r\n"); goto input_restart; } else if (ret == CHAR_CTRL_C) { @@ -394,7 +395,9 @@ int pyexec_friendly_repl(void) { #endif friendly_repl_reset: - mp_hal_stdout_tx_str("\r\nAdafruit CircuitPython " MICROPY_GIT_TAG " on " MICROPY_BUILD_DATE "; " MICROPY_HW_BOARD_NAME " with " MICROPY_HW_MCU_NAME "\r\n"); + mp_hal_stdout_tx_str("\r\n"); + mp_hal_stdout_tx_str(MICROPY_FULL_VERSION_INFO); + mp_hal_stdout_tx_str("\r\n"); // mp_hal_stdout_tx_str("Type \"help()\" for more information.\r\n"); // to test ctrl-C diff --git a/ports/atmel-samd/Makefile b/ports/atmel-samd/Makefile index 7a842b9c64..f77910f6a3 100644 --- a/ports/atmel-samd/Makefile +++ b/ports/atmel-samd/Makefile @@ -76,6 +76,9 @@ BASE_CFLAGS = \ -ffunction-sections \ -fdata-sections \ -fshort-enums \ + -DCIRCUITPY_SOFTWARE_SAFE_MODE=0x0ADABEEF \ + -DCIRCUITPY_CANARY_WORD=0xADAF00 \ + -DCIRCUITPY_SAFE_RESTART_WORD=0xDEADBEEF \ --param max-inline-insns-single=500 # NDEBUG disables assert() statements. This reduces code size pretty dramatically, per tannewt. @@ -312,6 +315,7 @@ SRC_BINDINGS_ENUMS = \ digitalio/Direction.c \ digitalio/DriveMode.c \ digitalio/Pull.c \ + microcontroller/RunMode.c \ help.c \ math/__init__.c \ supervisor/__init__.c \ diff --git a/ports/atmel-samd/boards/circuitplayground_express/mpconfigboard.h b/ports/atmel-samd/boards/circuitplayground_express/mpconfigboard.h index 8648980c08..6b86a68902 100644 --- a/ports/atmel-samd/boards/circuitplayground_express/mpconfigboard.h +++ b/ports/atmel-samd/boards/circuitplayground_express/mpconfigboard.h @@ -10,16 +10,29 @@ #define SPI_FLASH_BAUDRATE (8000000) // On-board flash -#define SPI_FLASH_MUX_SETTING SPI_SIGNAL_MUX_SETTING_E -// Use default pinmux for the chip select since we manage it ourselves. -#define SPI_FLASH_PAD0_PINMUX PINMUX_PA16D_SERCOM3_PAD0 // MISO -#define SPI_FLASH_PAD1_PINMUX PINMUX_UNUSED // CS -#define SPI_FLASH_PAD2_PINMUX PINMUX_PA20D_SERCOM3_PAD2 // MOSI -#define SPI_FLASH_PAD3_PINMUX PINMUX_PA21D_SERCOM3_PAD3 // SCK +#define SPI_FLASH_MOSI_PIN PIN_PA20 +#define SPI_FLASH_MISO_PIN PIN_PA16 +#define SPI_FLASH_SCK_PIN PIN_PA21 +#define SPI_FLASH_CS_PIN PIN_PB22 -#define SPI_FLASH_CS PIN_PB22 -#define SPI_FLASH_SERCOM SERCOM3 +#define SPI_FLASH_MOSI_PIN_FUNCTION PINMUX_PA20D_SERCOM3_PAD2 +#define SPI_FLASH_MISO_PIN_FUNCTION PINMUX_PA16D_SERCOM3_PAD0 +#define SPI_FLASH_SCK_PIN_FUNCTION PINMUX_PA21D_SERCOM3_PAD3 +#define SPI_FLASH_SERCOM SERCOM3 +#define SPI_FLASH_SERCOM_INDEX 5 +#define SPI_FLASH_MOSI_PAD 2 +#define SPI_FLASH_MISO_PAD 0 +#define SPI_FLASH_SCK_PAD 3 +// Transmit Data Pinout +// <0x0=>PAD[0,1]_DO_SCK +// <0x1=>PAD[2,3]_DO_SCK +// <0x2=>PAD[3,1]_DO_SCK +// <0x3=>PAD[0,3]_DO_SCK +#define SPI_FLASH_DOPO 1 +#define SPI_FLASH_DIPO 0 // same as MISO PAD + +// These are pins not to reset. // PA24 and PA25 are USB. #define MICROPY_PORT_A (PORT_PA16 | PORT_PA20 | PORT_PA21 | PORT_PA24 | PORT_PA25) #define MICROPY_PORT_B (PORT_PB22) @@ -27,8 +40,7 @@ #define SPEAKER_ENABLE_PIN (&pin_PA30) -#include "internal_flash.h" -//#include "spi_flash.h" +#include "spi_flash.h" // If you change this, then make sure to update the linker scripts as well to // make sure you don't overwrite code. diff --git a/ports/atmel-samd/boards/circuitplayground_express/mpconfigboard.mk b/ports/atmel-samd/boards/circuitplayground_express/mpconfigboard.mk index 6e975fdc14..1834a0ebe4 100644 --- a/ports/atmel-samd/boards/circuitplayground_express/mpconfigboard.mk +++ b/ports/atmel-samd/boards/circuitplayground_express/mpconfigboard.mk @@ -4,16 +4,13 @@ USB_PID = 0x8019 USB_PRODUCT = "CircuitPlayground Express" USB_MANUFACTURER = "Adafruit Industries LLC" -#SPI_FLASH_FILESYSTEM = 1 -INTERNAL_FLASH_FILESYSTEM = 1 +SPI_FLASH_FILESYSTEM = 1 CHIP_VARIANT = SAMD21G18A CHIP_FAMILY = samd21 # Include these Python libraries in firmware. -### TODO(halbert): disable some of these frozen modules; they don't fit in 3.0.0 build while internalfs -### is in use -###FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_BusDevice -###FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_LIS3DH -###FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_NeoPixel -###FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_Thermistor +FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_BusDevice +FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_LIS3DH +FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_NeoPixel +FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_Thermistor diff --git a/ports/atmel-samd/boards/feather_m0_supersized/board.c b/ports/atmel-samd/boards/feather_m0_supersized/board.c new file mode 100644 index 0000000000..c8e20206a1 --- /dev/null +++ b/ports/atmel-samd/boards/feather_m0_supersized/board.c @@ -0,0 +1,38 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 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 "boards/board.h" + +void board_init(void) +{ +} + +bool board_requests_safe_mode(void) { + return false; +} + +void reset_board(void) { +} diff --git a/ports/atmel-samd/boards/feather_m0_supersized/conf_access.h b/ports/atmel-samd/boards/feather_m0_supersized/conf_access.h new file mode 100644 index 0000000000..2326bfcdf2 --- /dev/null +++ b/ports/atmel-samd/boards/feather_m0_supersized/conf_access.h @@ -0,0 +1,115 @@ +/** + * \file + * + * \brief Memory access control configuration file. + * + * Copyright (c) 2014-2015 Atmel Corporation. All rights reserved. + * + * \asf_license_start + * + * \page License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 4. This software may only be redistributed and used in connection with an + * Atmel microcontroller product. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * \asf_license_stop + * + */ +/* + * Support and FAQ: visit Atmel Support + */ + +#ifndef _CONF_ACCESS_H_ +#define _CONF_ACCESS_H_ + +#include "compiler.h" +#include "board.h" + + +/*! \name Activation of Logical Unit Numbers + */ +//! @{ +#define LUN_0 ENABLE //!< On-Chip Virtual Memory. +#define LUN_1 DISABLE //!< AT45DBX Data Flash. +#define LUN_2 DISABLE //!< SD/MMC Card over SPI. +#define LUN_3 DISABLE //!< SD/MMC Card over MCI Slot 0. +#define LUN_4 DISABLE +#define LUN_5 DISABLE +#define LUN_6 DISABLE +#define LUN_7 DISABLE +#define LUN_USB DISABLE //!< Host Mass-Storage Memory. +//! @} + +/*! \name LUN 0 Definitions + */ +//! @{ +#define LUN_0_INCLUDE "access_vfs.h" +#define Lun_0_test_unit_ready vfs_test_unit_ready +#define Lun_0_read_capacity vfs_read_capacity +#define Lun_0_unload NULL +#define Lun_0_wr_protect vfs_wr_protect +#define Lun_0_removal vfs_removal +#define Lun_0_usb_read_10 vfs_usb_read_10 +#define Lun_0_usb_write_10 vfs_usb_write_10 +#define LUN_0_NAME "\"CircuitPython VFS[0]\"" +//! @} + +#define MEM_USB LUN_USB + +/*! \name Actions Associated with Memory Accesses + * + * Write here the action to associate with each memory access. + * + * \warning Be careful not to waste time in order not to disturb the functions. + */ +//! @{ +#define memory_start_read_action(nb_sectors) +#define memory_stop_read_action() +#define memory_start_write_action(nb_sectors) +#define memory_stop_write_action() +//! @} + +/*! \name Activation of Interface Features + */ +//! @{ +#define ACCESS_USB true //!< MEM <-> USB interface. +#define ACCESS_MEM_TO_RAM false //!< MEM <-> RAM interface. +#define ACCESS_STREAM false //!< Streaming MEM <-> MEM interface. +#define ACCESS_STREAM_RECORD false //!< Streaming MEM <-> MEM interface in record mode. +#define ACCESS_MEM_TO_MEM false //!< MEM <-> MEM interface. +#define ACCESS_CODEC false //!< Codec interface. +//! @} + +/*! \name Specific Options for Access Control + */ +//! @{ +#define GLOBAL_WR_PROTECT false //!< Management of a global write protection. +//! @} + + +#endif // _CONF_ACCESS_H_ diff --git a/ports/atmel-samd/boards/feather_m0_supersized/conf_board.h b/ports/atmel-samd/boards/feather_m0_supersized/conf_board.h new file mode 100644 index 0000000000..7b88c97fc2 --- /dev/null +++ b/ports/atmel-samd/boards/feather_m0_supersized/conf_board.h @@ -0,0 +1,14 @@ +/** + * \file + * + * \brief User board configuration template + * + */ +/* + * Support and FAQ: visit Atmel Support + */ + +#ifndef CONF_BOARD_H +#define CONF_BOARD_H + +#endif // CONF_BOARD_H diff --git a/ports/atmel-samd/boards/feather_m0_supersized/conf_clocks.h b/ports/atmel-samd/boards/feather_m0_supersized/conf_clocks.h new file mode 100644 index 0000000000..d3f3e6496d --- /dev/null +++ b/ports/atmel-samd/boards/feather_m0_supersized/conf_clocks.h @@ -0,0 +1 @@ +#include "conf_clocks_external_32k.h" diff --git a/ports/atmel-samd/boards/feather_m0_supersized/conf_usb.h b/ports/atmel-samd/boards/feather_m0_supersized/conf_usb.h new file mode 100644 index 0000000000..e5e59663c2 --- /dev/null +++ b/ports/atmel-samd/boards/feather_m0_supersized/conf_usb.h @@ -0,0 +1,220 @@ + +#include +#include + +#include "asf/common/services/usb/class/cdc/usb_protocol_cdc.h" + +#ifndef CONF_USB_H_INCLUDED +#define CONF_USB_H_INCLUDED + +#define USB_DEVICE_MAJOR_VERSION 1 +#define USB_DEVICE_MINOR_VERSION 0 +#define USB_DEVICE_POWER 100 // Consumption on Vbus line (mA) +#define USB_DEVICE_ATTR \ + (USB_CONFIG_ATTR_BUS_POWERED) +// (USB_CONFIG_ATTR_REMOTE_WAKEUP|USB_CONFIG_ATTR_SELF_POWERED) +// (USB_CONFIG_ATTR_REMOTE_WAKEUP|USB_CONFIG_ATTR_BUS_POWERED) + +//! USB Device string definitions (Optional) +#ifndef USB_DEVICE_MANUFACTURE_NAME +# define USB_DEVICE_MANUFACTURE_NAME "Dave Astels" +#endif + +#ifndef USB_DEVICE_PRODUCT_NAME +# define USB_DEVICE_PRODUCT_NAME "Hacked Feather M0 Express with 8Mbyte SPI flash" +#endif + +#define USB_DEVICE_GET_SERIAL_NAME_POINTER serial_number +#define USB_DEVICE_GET_SERIAL_NAME_LENGTH 32 +extern char serial_number[USB_DEVICE_GET_SERIAL_NAME_LENGTH]; + +//! Control endpoint size +#define USB_DEVICE_EP_CTRL_SIZE 64 + +//! Interfaces for this device (CDC COM + CDC DATA + MSC + HID mouse + HID kbd) +#define USB_DEVICE_NB_INTERFACE 5 + +// (3 | USB_EP_DIR_IN) // CDC Notify endpoint +// (4 | USB_EP_DIR_IN) // CDC TX +// (5 | USB_EP_DIR_OUT) // CDC RX +// (1 | USB_EP_DIR_IN) // MSC IN +// (2 | USB_EP_DIR_OUT) // MSC OUT +// (6 | USB_EP_DIR_IN) // HID mouse report +// (7 | USB_EP_DIR_IN) // HID keyboard report +#define USB_DEVICE_MAX_EP 7 + +#define UDI_CDC_PORT_NB 1 +#define UDI_CDC_ENABLE_EXT(port) mp_cdc_enable(port) +extern bool mp_cdc_enable(uint8_t port); +#define UDI_CDC_DISABLE_EXT(port) mp_cdc_disable(port) +extern void mp_cdc_disable(uint8_t port); +#define UDI_CDC_LOW_RATE + +#define UDI_CDC_DEFAULT_RATE 115200 +#define UDI_CDC_DEFAULT_STOPBITS CDC_STOP_BITS_1 +#define UDI_CDC_DEFAULT_PARITY CDC_PAR_NONE +#define UDI_CDC_DEFAULT_DATABITS 8 + +#define UDI_CDC_RX_NOTIFY(port) usb_rx_notify() +void usb_rx_notify(void); +#define UDI_CDC_SET_CODING_EXT(port,cfg) usb_coding_notify(port, cfg) +void usb_coding_notify(uint8_t port, usb_cdc_line_coding_t* coding); +#define UDI_CDC_SET_DTR_EXT(port,set) usb_dtr_notify(port, set) +void usb_dtr_notify(uint8_t port, bool set); +#define UDI_CDC_SET_RTS_EXT(port,set) usb_rts_notify(port, set) +void usb_rts_notify(uint8_t port, bool set); + +/** + * USB CDC low level configuration + * In standalone these configurations are defined by the CDC module. + * For composite device, these configuration must be defined here + * @{ + */ +//! Endpoint numbers definition + +#define UDI_CDC_COMM_EP_0 (3 | USB_EP_DIR_IN) // Notify endpoint +#define UDI_CDC_DATA_EP_IN_0 (4 | USB_EP_DIR_IN) // TX +#define UDI_CDC_DATA_EP_OUT_0 (5 | USB_EP_DIR_OUT) // RX + +//! Interface numbers +#define UDI_CDC_COMM_IFACE_NUMBER_0 0 +#define UDI_CDC_DATA_IFACE_NUMBER_0 1 + +/** + * Configuration of MSC interface + * @{ + */ +//! Vendor name and Product version of MSC interface +#define UDI_MSC_GLOBAL_VENDOR_ID \ + 'A', 'T', 'M', 'E', 'L', ' ', ' ', ' ' +#define UDI_MSC_GLOBAL_PRODUCT_VERSION \ + '1', '.', '0', '0' + +//! Interface callback definition +#define UDI_MSC_ENABLE_EXT() mp_msc_enable() +extern bool mp_msc_enable(void); +#define UDI_MSC_DISABLE_EXT() mp_msc_disable() +extern void mp_msc_disable(void); + +//! Enable id string of interface to add an extra USB string +#define UDI_MSC_STRING_ID 5 + +/** + * USB MSC low level configuration + * In standalone these configurations are defined by the MSC module. + * For composite device, these configuration must be defined here + * @{ + */ +//! Endpoint numbers definition +#define UDI_MSC_EP_IN (1 | USB_EP_DIR_IN) +#define UDI_MSC_EP_OUT (2 | USB_EP_DIR_OUT) + +//! Interface number +#define UDI_MSC_IFACE_NUMBER 2 +/** + * Configuration of HID Mouse interface + * @{ + */ +//! Interface callback definition +#define UDI_HID_MOUSE_ENABLE_EXT() mp_mouse_enable() +extern bool mp_mouse_enable(void); +#define UDI_HID_MOUSE_DISABLE_EXT() mp_mouse_disable() +extern void mp_mouse_disable(void); + +//! Enable id string of interface to add an extra USB string +#define UDI_HID_MOUSE_STRING_ID 6 + +/** + * USB HID Mouse low level configuration + * In standalone these configurations are defined by the HID Mouse module. + * For composite device, these configuration must be defined here + * @{ + */ +//! Endpoint numbers definition +#define UDI_HID_MOUSE_EP_IN (6 | USB_EP_DIR_IN) + +//! Interface number +#define UDI_HID_MOUSE_IFACE_NUMBER 3 +//@} +//@} + +/** + * Configuration of HID Keyboard interface + * @{ + */ +//! Interface callback definition +#define UDI_HID_KBD_ENABLE_EXT() mp_keyboard_enable() +extern bool mp_keyboard_enable(void); +#define UDI_HID_KBD_DISABLE_EXT() mp_keyboard_disable() +extern void mp_keyboard_disable(void); +#define UDI_HID_KBD_CHANGE_LED(value) mp_keyboard_led(value) +extern void mp_keyboard_led(uint8_t); + +//! Enable id string of interface to add an extra USB string +#define UDI_HID_KBD_STRING_ID 7 + +/** + * USB HID Keyboard low level configuration + * In standalone these configurations are defined by the HID Keyboard module. + * For composite device, these configuration must be defined here + * @{ + */ +//! Endpoint numbers definition +#define UDI_HID_KBD_EP_IN (7 | USB_EP_DIR_IN) + +//! Interface number +#define UDI_HID_KBD_IFACE_NUMBER 4 + +/** + * Description of Composite Device + * @{ + */ +//! USB Interfaces descriptor structure +#define UDI_COMPOSITE_DESC_T \ + usb_iad_desc_t udi_cdc_iad; \ + udi_cdc_comm_desc_t udi_cdc_comm; \ + udi_cdc_data_desc_t udi_cdc_data; \ + udi_msc_desc_t udi_msc; \ + udi_hid_mouse_desc_t udi_hid_mouse; \ + udi_hid_kbd_desc_t udi_hid_kbd + +//! USB Interfaces descriptor value for Full Speed +#define UDI_COMPOSITE_DESC_FS \ + .udi_cdc_iad = UDI_CDC_IAD_DESC_0, \ + .udi_cdc_comm = UDI_CDC_COMM_DESC_0, \ + .udi_cdc_data = UDI_CDC_DATA_DESC_0_FS, \ + .udi_msc = UDI_MSC_DESC_FS, \ + .udi_hid_mouse = UDI_HID_MOUSE_DESC, \ + .udi_hid_kbd = UDI_HID_KBD_DESC + +//! USB Interfaces descriptor value for High Speed +#define UDI_COMPOSITE_DESC_HS \ + .udi_cdc_iad = UDI_CDC_IAD_DESC_0, \ + .udi_cdc_comm = UDI_CDC_COMM_DESC_0, \ + .udi_cdc_data = UDI_CDC_DATA_DESC_0_HS, \ + .udi_msc = UDI_MSC_DESC_HS, \ + .udi_hid_mouse = UDI_HID_MOUSE_DESC, \ + .udi_hid_kbd = UDI_HID_KBD_DESC + +//! USB Interface APIs +#define UDI_COMPOSITE_API \ + &udi_api_cdc_comm, \ + &udi_api_cdc_data, \ + &udi_api_msc, \ + &udi_api_hid_mouse, \ + &udi_api_hid_kbd +//@} + +/** + * USB Device Driver Configuration + * @{ + */ +//@} + +//! The includes of classes and other headers must be done at the end of this file to avoid compile error +#include "udi_cdc.h" +#include "udi_msc.h" +#include "udi_hid_mouse.h" +#include "udi_hid_kbd.h" + +#endif diff --git a/ports/atmel-samd/boards/feather_m0_supersized/mpconfigboard.h b/ports/atmel-samd/boards/feather_m0_supersized/mpconfigboard.h new file mode 100644 index 0000000000..8eb59d9a0f --- /dev/null +++ b/ports/atmel-samd/boards/feather_m0_supersized/mpconfigboard.h @@ -0,0 +1,34 @@ +/* Adafruit Feather M0 Express with an 8MB SPI flash instead of the usual 2MB */ + +#define USB_REPL + +#define MICROPY_HW_BOARD_NAME "Hacked Feather M0 Express with 8Mbyte SPI flash" +#define MICROPY_HW_MCU_NAME "samd21g18" + +#define MICROPY_HW_NEOPIXEL (&pin_PA06) + +// Salae reads 12mhz which is the limit even though we set it to the safer 8mhz. +#define SPI_FLASH_BAUDRATE (8000000) + +#define SPI_FLASH_MUX_SETTING SPI_SIGNAL_MUX_SETTING_C +#define SPI_FLASH_PAD0_PINMUX PINMUX_PA08D_SERCOM2_PAD0 // MOSI +// Use default pinmux for the chip select since we manage it ourselves. +#define SPI_FLASH_PAD1_PINMUX PINMUX_PA09D_SERCOM2_PAD1 // SCK +#define SPI_FLASH_PAD2_PINMUX PINMUX_PA14C_SERCOM2_PAD2 // MISO +#define SPI_FLASH_PAD3_PINMUX PINMUX_UNUSED // SCK +#define SPI_FLASH_SERCOM SERCOM2 + +#define SPI_FLASH_CS PIN_PA13 + +#define MICROPY_PORT_A (PORT_PA06 | PORT_PA08 | PORT_PA09 | PORT_PA14 | PORT_PA13 | PORT_PA14 | PORT_PA24 | PORT_PA25) +#define MICROPY_PORT_B ( 0 ) + +#include "spi_flash.h" + +// If you change this, then make sure to update the linker scripts as well to +// make sure you don't overwrite code. +#define CIRCUITPY_INTERNAL_NVM_SIZE 256 + +#define BOARD_FLASH_SIZE (0x00040000 - 0x2000 - CIRCUITPY_INTERNAL_NVM_SIZE) + +#include "flash_S25FL064L.h" diff --git a/ports/atmel-samd/boards/feather_m0_supersized/mpconfigboard.mk b/ports/atmel-samd/boards/feather_m0_supersized/mpconfigboard.mk new file mode 100644 index 0000000000..340421f500 --- /dev/null +++ b/ports/atmel-samd/boards/feather_m0_supersized/mpconfigboard.mk @@ -0,0 +1,11 @@ +LD_FILE = boards/samd21x18-bootloader-external-flash.ld +USB_VID = 0x239A +USB_PID = 0x8023 +USB_PRODUCT = "Feather M0 Supersized" +USB_MANUFACTURER = "Dave Astels" + +SPI_FLASH_FILESYSTEM = 1 + +CHIP_VARIANT = SAMD21G18A +CHIP_FAMILY = samd21 + diff --git a/ports/atmel-samd/boards/feather_m0_supersized/pins.c b/ports/atmel-samd/boards/feather_m0_supersized/pins.c new file mode 100644 index 0000000000..c5c70ee5dc --- /dev/null +++ b/ports/atmel-samd/boards/feather_m0_supersized/pins.c @@ -0,0 +1,28 @@ +#include "samd21_pins.h" + +STATIC const mp_rom_map_elem_t board_global_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_A0), MP_ROM_PTR(&pin_PA02) }, + { MP_ROM_QSTR(MP_QSTR_A1), MP_ROM_PTR(&pin_PB08) }, + { MP_ROM_QSTR(MP_QSTR_A2), MP_ROM_PTR(&pin_PB09) }, + { MP_ROM_QSTR(MP_QSTR_A3), MP_ROM_PTR(&pin_PA04) }, + { MP_ROM_QSTR(MP_QSTR_A4), MP_ROM_PTR(&pin_PA05) }, + { MP_ROM_QSTR(MP_QSTR_A5), MP_ROM_PTR(&pin_PB02) }, + { MP_ROM_QSTR(MP_QSTR_SCK), MP_ROM_PTR(&pin_PB11) }, + { MP_ROM_QSTR(MP_QSTR_MOSI), MP_ROM_PTR(&pin_PB10) }, + { MP_ROM_QSTR(MP_QSTR_MISO), MP_ROM_PTR(&pin_PA12) }, + { MP_ROM_QSTR(MP_QSTR_D0), MP_ROM_PTR(&pin_PA11) }, + { MP_ROM_QSTR(MP_QSTR_RX), MP_ROM_PTR(&pin_PA11) }, + { MP_ROM_QSTR(MP_QSTR_D1), MP_ROM_PTR(&pin_PA10) }, + { MP_ROM_QSTR(MP_QSTR_TX), MP_ROM_PTR(&pin_PA10) }, + { MP_ROM_QSTR(MP_QSTR_SDA), MP_ROM_PTR(&pin_PA22) }, + { MP_ROM_QSTR(MP_QSTR_SCL), MP_ROM_PTR(&pin_PA23) }, + { MP_ROM_QSTR(MP_QSTR_D5), MP_ROM_PTR(&pin_PA15) }, + { MP_ROM_QSTR(MP_QSTR_D6), MP_ROM_PTR(&pin_PA20) }, + { MP_ROM_QSTR(MP_QSTR_D9), MP_ROM_PTR(&pin_PA07) }, + { MP_ROM_QSTR(MP_QSTR_D10), MP_ROM_PTR(&pin_PA18) }, + { MP_ROM_QSTR(MP_QSTR_D11), MP_ROM_PTR(&pin_PA16) }, + { MP_ROM_QSTR(MP_QSTR_D12), MP_ROM_PTR(&pin_PA19) }, + { MP_ROM_QSTR(MP_QSTR_D13), MP_ROM_PTR(&pin_PA17) }, + { MP_ROM_QSTR(MP_QSTR_NEOPIXEL), MP_ROM_PTR(&pin_PA06) }, +}; +MP_DEFINE_CONST_DICT(board_module_globals, board_global_dict_table); diff --git a/ports/atmel-samd/boards/flash_S25FL064L.h b/ports/atmel-samd/boards/flash_S25FL064L.h new file mode 100644 index 0000000000..40cfa4cf0a --- /dev/null +++ b/ports/atmel-samd/boards/flash_S25FL064L.h @@ -0,0 +1,55 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 Scott Shawcroft for Adafruit Industries + * Copyright (c) 2017 Dave Astels + * + * 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_BOARD_FLASH_S25FL064L_H +#define MICROPY_INCLUDED_ATMEL_SAMD_BOARD_FLASH_S25FL064L_H + +// Settings for the Cypress (was Spansion) S25FL064L 8MiB SPI flash. +// Datasheet: http://www.cypress.com/file/316661/download + +// The total flash size in bytes. +#define SPI_FLASH_TOTAL_SIZE (1 << 23) // 8 MiB + +// The size of the smallest erase unit thats erased with command 0x20. +#define SPI_FLASH_ERASE_SIZE (1 << 12) // 4 KiB + +// The size of a page that is programmed with page program command 0x02. +#define SPI_FLASH_PAGE_SIZE (256) // 256 bytes + +// These are the first three response bytes to the JEDEC ID command 0x9f that is +// used to confirm we're talking to the flash we expect. +#ifndef SPI_FLASH_JEDEC_MANUFACTURER +#define SPI_FLASH_JEDEC_MANUFACTURER 0x01 +#define SPI_FLASH_SECTOR_PROTECTION false +#else +#define SPI_FLASH_JEDEC_MANUFACTURER_2 0x013 +#define SPI_FLASH_SECTOR_PROTECTION_2 false +#endif +#define SPI_FLASH_JEDEC_MEMORY_TYPE 0x60 +#define SPI_FLASH_JEDEC_CAPACITY 0x17 + +#endif // MICROPY_INCLUDED_ATMEL_SAMD_BOARD_FLASH_S25FL216K_H diff --git a/ports/atmel-samd/boards/flash_W25Q80DV.h b/ports/atmel-samd/boards/flash_W25Q80DV.h new file mode 100644 index 0000000000..1e8003867f --- /dev/null +++ b/ports/atmel-samd/boards/flash_W25Q80DV.h @@ -0,0 +1,51 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 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_BOARD_FLASH_W25Q80DV_H +#define MICROPY_INCLUDED_ATMEL_SAMD_BOARD_FLASH_W25Q80DV_H + +// The total flash size in bytes. +#define SPI_FLASH_TOTAL_SIZE (1 << 20) // 1 MiB + +// The size of the smallest erase unit thats erased with command 0x20. +#define SPI_FLASH_ERASE_SIZE (1 << 12) // 4 KiB + +// The size of a page that is programmed with page program command 0x02. +#define SPI_FLASH_PAGE_SIZE (256) // 256 bytes + +// These are the first three response bytes to the JEDEC ID command 0x9f that is +// used to confirm we're talking to the flash we expect. +#ifndef SPI_FLASH_JEDEC_MANUFACTURER +#define SPI_FLASH_JEDEC_MANUFACTURER 0xef +#define SPI_FLASH_SECTOR_PROTECTION false +#else +#define SPI_FLASH_JEDEC_MANUFACTURER_2 0xef +#define SPI_FLASH_SECTOR_PROTECTION_2 false +#endif +#define SPI_FLASH_JEDEC_MEMORY_TYPE 0x40 +#define SPI_FLASH_JEDEC_CAPACITY 0x14 + +#endif // MICROPY_INCLUDED_ATMEL_SAMD_BOARD_FLASH_W25Q80DV_H diff --git a/ports/atmel-samd/boards/itsybitsy_m0/board.c b/ports/atmel-samd/boards/itsybitsy_m0/board.c new file mode 100644 index 0000000000..d7e856d611 --- /dev/null +++ b/ports/atmel-samd/boards/itsybitsy_m0/board.c @@ -0,0 +1,37 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 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 "boards/board.h" + +void board_init(void) { +} + +bool board_requests_safe_mode(void) { + return false; +} + +void reset_board(void) { +} diff --git a/ports/atmel-samd/boards/itsybitsy_m0/conf_access.h b/ports/atmel-samd/boards/itsybitsy_m0/conf_access.h new file mode 100644 index 0000000000..25109b75ca --- /dev/null +++ b/ports/atmel-samd/boards/itsybitsy_m0/conf_access.h @@ -0,0 +1,115 @@ +/** + * \file + * + * \brief Memory access control configuration file. + * + * Copyright (c) 2014-2015 Atmel Corporation. All rights reserved. + * + * \asf_license_start + * + * \page License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 4. This software may only be redistributed and used in connection with an + * Atmel microcontroller product. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * \asf_license_stop + * + */ +/* + * Support and FAQ: visit Atmel Support + */ + +#ifndef _CONF_ACCESS_H_ +#define _CONF_ACCESS_H_ + +#include "compiler.h" +#include "board.h" + + +/*! \name Activation of Logical Unit Numbers + */ +//! @{ +#define LUN_0 ENABLE //!< On-Chip Virtual Memory. +#define LUN_1 DISABLE //!< AT45DBX Data Flash. +#define LUN_2 DISABLE //!< SD/MMC Card over SPI. +#define LUN_3 DISABLE //!< SD/MMC Card over MCI Slot 0. +#define LUN_4 DISABLE +#define LUN_5 DISABLE +#define LUN_6 DISABLE +#define LUN_7 DISABLE +#define LUN_USB DISABLE //!< Host Mass-Storage Memory. +//! @} + +/*! \name LUN 0 Definitions + */ +//! @{ +#define LUN_0_INCLUDE "access_vfs.h" +#define Lun_0_test_unit_ready vfs_test_unit_ready +#define Lun_0_read_capacity vfs_read_capacity +#define Lun_0_unload NULL +#define Lun_0_wr_protect vfs_wr_protect +#define Lun_0_removal vfs_removal +#define Lun_0_usb_read_10 vfs_usb_read_10 +#define Lun_0_usb_write_10 vfs_usb_write_10 +#define LUN_0_NAME "\"MicroPython VFS[0]\"" +//! @} + +#define MEM_USB LUN_USB + +/*! \name Actions Associated with Memory Accesses + * + * Write here the action to associate with each memory access. + * + * \warning Be careful not to waste time in order not to disturb the functions. + */ +//! @{ +#define memory_start_read_action(nb_sectors) +#define memory_stop_read_action() +#define memory_start_write_action(nb_sectors) +#define memory_stop_write_action() +//! @} + +/*! \name Activation of Interface Features + */ +//! @{ +#define ACCESS_USB true //!< MEM <-> USB interface. +#define ACCESS_MEM_TO_RAM false //!< MEM <-> RAM interface. +#define ACCESS_STREAM false //!< Streaming MEM <-> MEM interface. +#define ACCESS_STREAM_RECORD false //!< Streaming MEM <-> MEM interface in record mode. +#define ACCESS_MEM_TO_MEM false //!< MEM <-> MEM interface. +#define ACCESS_CODEC false //!< Codec interface. +//! @} + +/*! \name Specific Options for Access Control + */ +//! @{ +#define GLOBAL_WR_PROTECT false //!< Management of a global write protection. +//! @} + + +#endif // _CONF_ACCESS_H_ diff --git a/ports/atmel-samd/boards/itsybitsy_m0/conf_board.h b/ports/atmel-samd/boards/itsybitsy_m0/conf_board.h new file mode 100644 index 0000000000..7b88c97fc2 --- /dev/null +++ b/ports/atmel-samd/boards/itsybitsy_m0/conf_board.h @@ -0,0 +1,14 @@ +/** + * \file + * + * \brief User board configuration template + * + */ +/* + * Support and FAQ: visit Atmel Support + */ + +#ifndef CONF_BOARD_H +#define CONF_BOARD_H + +#endif // CONF_BOARD_H diff --git a/ports/atmel-samd/boards/itsybitsy_m0/conf_clocks.h b/ports/atmel-samd/boards/itsybitsy_m0/conf_clocks.h new file mode 100644 index 0000000000..9e4f7876be --- /dev/null +++ b/ports/atmel-samd/boards/itsybitsy_m0/conf_clocks.h @@ -0,0 +1 @@ +#include "conf_clocks_crystalless.h" diff --git a/ports/atmel-samd/boards/itsybitsy_m0/conf_usb.h b/ports/atmel-samd/boards/itsybitsy_m0/conf_usb.h new file mode 100644 index 0000000000..5e8a61b884 --- /dev/null +++ b/ports/atmel-samd/boards/itsybitsy_m0/conf_usb.h @@ -0,0 +1,221 @@ + +#include +#include + +#include "asf/common/services/usb/class/cdc/usb_protocol_cdc.h" + +#ifndef CONF_USB_H_INCLUDED +#define CONF_USB_H_INCLUDED + +#define USB_DEVICE_MAJOR_VERSION 1 +#define USB_DEVICE_MINOR_VERSION 0 +#define USB_DEVICE_POWER 100 // Consumption on Vbus line (mA) +#define USB_DEVICE_ATTR \ + (USB_CONFIG_ATTR_BUS_POWERED) +// (USB_CONFIG_ATTR_REMOTE_WAKEUP|USB_CONFIG_ATTR_SELF_POWERED) +// (USB_CONFIG_ATTR_REMOTE_WAKEUP|USB_CONFIG_ATTR_BUS_POWERED) + +//! USB Device string definitions (Optional) +#ifndef USB_DEVICE_MANUFACTURE_NAME +# define USB_DEVICE_MANUFACTURE_NAME "Adafruit Industries" +#endif + +#ifndef USB_DEVICE_PRODUCT_NAME +# define USB_DEVICE_PRODUCT_NAME "ItsyBitsy M0" +#endif +// #define USB_DEVICE_SERIAL_NAME "12...EF" +#define USB_DEVICE_GET_SERIAL_NAME_POINTER serial_number +#define USB_DEVICE_GET_SERIAL_NAME_LENGTH 32 +extern char serial_number[USB_DEVICE_GET_SERIAL_NAME_LENGTH]; + +//! Control endpoint size +#define USB_DEVICE_EP_CTRL_SIZE 64 + +//! Interfaces for this device (CDC COM + CDC DATA + MSC + HID mouse + HID kbd) +#define USB_DEVICE_NB_INTERFACE 5 + +// (3 | USB_EP_DIR_IN) // CDC Notify endpoint +// (4 | USB_EP_DIR_IN) // CDC TX +// (5 | USB_EP_DIR_OUT) // CDC RX +// (1 | USB_EP_DIR_IN) // MSC IN +// (2 | USB_EP_DIR_OUT) // MSC OUT +// (6 | USB_EP_DIR_IN) // HID mouse report +// (7 | USB_EP_DIR_IN) // HID keyboard report +#define USB_DEVICE_MAX_EP 7 + +#define UDI_CDC_PORT_NB 1 +#define UDI_CDC_ENABLE_EXT(port) mp_cdc_enable(port) +extern bool mp_cdc_enable(uint8_t port); +#define UDI_CDC_DISABLE_EXT(port) mp_cdc_disable(port) +extern void mp_cdc_disable(uint8_t port); +#define UDI_CDC_LOW_RATE + +#define UDI_CDC_DEFAULT_RATE 115200 +#define UDI_CDC_DEFAULT_STOPBITS CDC_STOP_BITS_1 +#define UDI_CDC_DEFAULT_PARITY CDC_PAR_NONE +#define UDI_CDC_DEFAULT_DATABITS 8 + +#define UDI_CDC_RX_NOTIFY(port) usb_rx_notify() +void usb_rx_notify(void); + +#define UDI_CDC_SET_CODING_EXT(port,cfg) usb_coding_notify(port, cfg) +void usb_coding_notify(uint8_t port, usb_cdc_line_coding_t* coding); +#define UDI_CDC_SET_DTR_EXT(port,set) usb_dtr_notify(port, set) +void usb_dtr_notify(uint8_t port, bool set); +#define UDI_CDC_SET_RTS_EXT(port,set) usb_rts_notify(port, set) +void usb_rts_notify(uint8_t port, bool set); + +/** + * USB CDC low level configuration + * In standalone these configurations are defined by the CDC module. + * For composite device, these configuration must be defined here + * @{ + */ +//! Endpoint numbers definition + +#define UDI_CDC_COMM_EP_0 (3 | USB_EP_DIR_IN) // Notify endpoint +#define UDI_CDC_DATA_EP_IN_0 (4 | USB_EP_DIR_IN) // TX +#define UDI_CDC_DATA_EP_OUT_0 (5 | USB_EP_DIR_OUT) // RX + +//! Interface numbers +#define UDI_CDC_COMM_IFACE_NUMBER_0 0 +#define UDI_CDC_DATA_IFACE_NUMBER_0 1 + +/** + * Configuration of MSC interface + * @{ + */ +//! Vendor name and Product version of MSC interface +#define UDI_MSC_GLOBAL_VENDOR_ID \ + 'A', 'T', 'M', 'E', 'L', ' ', ' ', ' ' +#define UDI_MSC_GLOBAL_PRODUCT_VERSION \ + '1', '.', '0', '0' + +//! Interface callback definition +#define UDI_MSC_ENABLE_EXT() mp_msc_enable() +extern bool mp_msc_enable(void); +#define UDI_MSC_DISABLE_EXT() mp_msc_disable() +extern void mp_msc_disable(void); + +//! Enable id string of interface to add an extra USB string +#define UDI_MSC_STRING_ID 5 + +/** + * USB MSC low level configuration + * In standalone these configurations are defined by the MSC module. + * For composite device, these configuration must be defined here + * @{ + */ +//! Endpoint numbers definition +#define UDI_MSC_EP_IN (1 | USB_EP_DIR_IN) +#define UDI_MSC_EP_OUT (2 | USB_EP_DIR_OUT) + +//! Interface number +#define UDI_MSC_IFACE_NUMBER 2 +/** + * Configuration of HID Mouse interface + * @{ + */ +//! Interface callback definition +#define UDI_HID_MOUSE_ENABLE_EXT() mp_mouse_enable() +extern bool mp_mouse_enable(void); +#define UDI_HID_MOUSE_DISABLE_EXT() mp_mouse_disable() +extern void mp_mouse_disable(void); + +//! Enable id string of interface to add an extra USB string +#define UDI_HID_MOUSE_STRING_ID 6 + +/** + * USB HID Mouse low level configuration + * In standalone these configurations are defined by the HID Mouse module. + * For composite device, these configuration must be defined here + * @{ + */ +//! Endpoint numbers definition +#define UDI_HID_MOUSE_EP_IN (6 | USB_EP_DIR_IN) + +//! Interface number +#define UDI_HID_MOUSE_IFACE_NUMBER 3 +//@} +//@} + +/** + * Configuration of HID Keyboard interface + * @{ + */ +//! Interface callback definition +#define UDI_HID_KBD_ENABLE_EXT() mp_keyboard_enable() +extern bool mp_keyboard_enable(void); +#define UDI_HID_KBD_DISABLE_EXT() mp_keyboard_disable() +extern void mp_keyboard_disable(void); +#define UDI_HID_KBD_CHANGE_LED(value) mp_keyboard_led(value) +extern void mp_keyboard_led(uint8_t); + +//! Enable id string of interface to add an extra USB string +#define UDI_HID_KBD_STRING_ID 7 + +/** + * USB HID Keyboard low level configuration + * In standalone these configurations are defined by the HID Keyboard module. + * For composite device, these configuration must be defined here + * @{ + */ +//! Endpoint numbers definition +#define UDI_HID_KBD_EP_IN (7 | USB_EP_DIR_IN) + +//! Interface number +#define UDI_HID_KBD_IFACE_NUMBER 4 + +/** + * Description of Composite Device + * @{ + */ +//! USB Interfaces descriptor structure +#define UDI_COMPOSITE_DESC_T \ + usb_iad_desc_t udi_cdc_iad; \ + udi_cdc_comm_desc_t udi_cdc_comm; \ + udi_cdc_data_desc_t udi_cdc_data; \ + udi_msc_desc_t udi_msc; \ + udi_hid_mouse_desc_t udi_hid_mouse; \ + udi_hid_kbd_desc_t udi_hid_kbd + +//! USB Interfaces descriptor value for Full Speed +#define UDI_COMPOSITE_DESC_FS \ + .udi_cdc_iad = UDI_CDC_IAD_DESC_0, \ + .udi_cdc_comm = UDI_CDC_COMM_DESC_0, \ + .udi_cdc_data = UDI_CDC_DATA_DESC_0_FS, \ + .udi_msc = UDI_MSC_DESC_FS, \ + .udi_hid_mouse = UDI_HID_MOUSE_DESC, \ + .udi_hid_kbd = UDI_HID_KBD_DESC + +//! USB Interfaces descriptor value for High Speed +#define UDI_COMPOSITE_DESC_HS \ + .udi_cdc_iad = UDI_CDC_IAD_DESC_0, \ + .udi_cdc_comm = UDI_CDC_COMM_DESC_0, \ + .udi_cdc_data = UDI_CDC_DATA_DESC_0_HS, \ + .udi_msc = UDI_MSC_DESC_HS, \ + .udi_hid_mouse = UDI_HID_MOUSE_DESC, \ + .udi_hid_kbd = UDI_HID_KBD_DESC + +//! USB Interface APIs +#define UDI_COMPOSITE_API \ + &udi_api_cdc_comm, \ + &udi_api_cdc_data, \ + &udi_api_msc, \ + &udi_api_hid_mouse, \ + &udi_api_hid_kbd +//@} + +/** + * USB Device Driver Configuration + * @{ + */ +//@} + +//! The includes of classes and other headers must be done at the end of this file to avoid compile error +#include "udi_cdc.h" +#include "udi_msc.h" +#include "udi_hid_mouse.h" +#include "udi_hid_kbd.h" + +#endif diff --git a/ports/atmel-samd/boards/itsybitsy_m0/mpconfigboard.h b/ports/atmel-samd/boards/itsybitsy_m0/mpconfigboard.h new file mode 100644 index 0000000000..e9fd08a5f6 --- /dev/null +++ b/ports/atmel-samd/boards/itsybitsy_m0/mpconfigboard.h @@ -0,0 +1,36 @@ +#define USB_REPL + +#define MICROPY_HW_BOARD_NAME "Adafruit ItsyBitsy M0" +#define MICROPY_HW_MCU_NAME "samd21g18" + +#define CIRCUITPY_BITBANG_APA102 +#define MICROPY_HW_APA102_MOSI (&pin_PA01) +#define MICROPY_HW_APA102_SCK (&pin_PA00) + +#define MICROPY_PORT_A (PORT_PA00 | PORT_PA01 | PORT_PA27 | PORT_PA24 | PORT_PA25) +#define MICROPY_PORT_B (PORT_PB22 | PORT_PB23 | PORT_PB03 ) + +// Salae reads 12mhz which is the limit even though we set it to the safer 8mhz. +#define SPI_FLASH_BAUDRATE (8000000) + +#define SPI_FLASH_MUX_SETTING SPI_SIGNAL_MUX_SETTING_F +#define SPI_FLASH_PAD2_PINMUX PINMUX_PB22D_SERCOM5_PAD2 // MOSI +// Use default pinmux for the chip select since we manage it ourselves. +#define SPI_FLASH_PAD3_PINMUX PINMUX_PB23D_SERCOM5_PAD3 // SCK +#define SPI_FLASH_PAD1_PINMUX PINMUX_PB03D_SERCOM5_PAD1 // MISO +#define SPI_FLASH_PAD0_PINMUX PINMUX_UNUSED // +#define SPI_FLASH_SERCOM SERCOM5 + +#define SPI_FLASH_CS PIN_PA27 + + +#include "spi_flash.h" + +// If you change this, then make sure to update the linker scripts as well to +// make sure you don't overwrite code. +#define CIRCUITPY_INTERNAL_NVM_SIZE 256 +#define BOARD_FLASH_SIZE (0x00040000 - 0x2000 - CIRCUITPY_INTERNAL_NVM_SIZE) + +//#include "flash_S25FL216K.h" +#include "flash_W25Q80DV.h" +//#include "flash_GD25Q16C.h" diff --git a/ports/atmel-samd/boards/itsybitsy_m0/mpconfigboard.mk b/ports/atmel-samd/boards/itsybitsy_m0/mpconfigboard.mk new file mode 100644 index 0000000000..0fb0e38ed4 --- /dev/null +++ b/ports/atmel-samd/boards/itsybitsy_m0/mpconfigboard.mk @@ -0,0 +1,11 @@ +LD_FILE = boards/samd21x18-bootloader-external-flash-crystalless.ld +USB_VID = 0x239A +USB_PID = 0x8012 +USB_PRODUCT = "Itsy Bitsy M0 Express" +USB_MANUFACTURER = "Adafruit Industries LLC" + +SPI_FLASH_FILESYSTEM = 1 + +CHIP_VARIANT = SAMD21G18A +CHIP_FAMILY = samd21 + diff --git a/ports/atmel-samd/boards/itsybitsy_m0/pins.c b/ports/atmel-samd/boards/itsybitsy_m0/pins.c new file mode 100644 index 0000000000..b70bb6a76c --- /dev/null +++ b/ports/atmel-samd/boards/itsybitsy_m0/pins.c @@ -0,0 +1,42 @@ +#include "samd21_pins.h" + +STATIC const mp_rom_map_elem_t board_global_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_D0), MP_ROM_PTR(&pin_PA11) }, + { MP_ROM_QSTR(MP_QSTR_RX), MP_ROM_PTR(&pin_PA11) }, + + { MP_ROM_QSTR(MP_QSTR_D1), MP_ROM_PTR(&pin_PA10) }, + { MP_ROM_QSTR(MP_QSTR_TX), MP_ROM_PTR(&pin_PA10) }, + + { MP_ROM_QSTR(MP_QSTR_D2), MP_ROM_PTR(&pin_PA14) }, + { MP_ROM_QSTR(MP_QSTR_D3), MP_ROM_PTR(&pin_PA09) }, + { MP_ROM_QSTR(MP_QSTR_D4), MP_ROM_PTR(&pin_PA08) }, + { MP_ROM_QSTR(MP_QSTR_D5), MP_ROM_PTR(&pin_PA15) }, + { MP_ROM_QSTR(MP_QSTR_D6), MP_ROM_PTR(&pin_PA20) }, + { MP_ROM_QSTR(MP_QSTR_D7), MP_ROM_PTR(&pin_PA21) }, + { MP_ROM_QSTR(MP_QSTR_D8), MP_ROM_PTR(&pin_PA06) }, + { MP_ROM_QSTR(MP_QSTR_D9), MP_ROM_PTR(&pin_PA07) }, + { MP_ROM_QSTR(MP_QSTR_D10), MP_ROM_PTR(&pin_PA18) }, + { MP_ROM_QSTR(MP_QSTR_D11), MP_ROM_PTR(&pin_PA16) }, + { MP_ROM_QSTR(MP_QSTR_D12), MP_ROM_PTR(&pin_PA19) }, + + { MP_ROM_QSTR(MP_QSTR_D13), MP_ROM_PTR(&pin_PA17) }, + { MP_ROM_QSTR(MP_QSTR_L), MP_ROM_PTR(&pin_PA17) }, // a.k.a D13 + + { MP_ROM_QSTR(MP_QSTR_A0), MP_ROM_PTR(&pin_PA02) }, + { MP_ROM_QSTR(MP_QSTR_A1), MP_ROM_PTR(&pin_PB08) }, + { MP_ROM_QSTR(MP_QSTR_A2), MP_ROM_PTR(&pin_PB09) }, + { MP_ROM_QSTR(MP_QSTR_A3), MP_ROM_PTR(&pin_PA04) }, + { MP_ROM_QSTR(MP_QSTR_A4), MP_ROM_PTR(&pin_PA05) }, + { MP_ROM_QSTR(MP_QSTR_A5), MP_ROM_PTR(&pin_PB02) }, + + { MP_ROM_QSTR(MP_QSTR_MOSI), MP_ROM_PTR(&pin_PB10) }, + { MP_ROM_QSTR(MP_QSTR_MISO), MP_ROM_PTR(&pin_PA12) }, + { MP_ROM_QSTR(MP_QSTR_SCK), MP_ROM_PTR(&pin_PB11) }, + + { MP_ROM_QSTR(MP_QSTR_SCL), MP_ROM_PTR(&pin_PA23) }, + { MP_ROM_QSTR(MP_QSTR_SDA), MP_ROM_PTR(&pin_PA22) }, + + { MP_ROM_QSTR(MP_QSTR_APA102_MOSI), MP_ROM_PTR(&pin_PA01) }, + { MP_ROM_QSTR(MP_QSTR_APA102_SCK), MP_ROM_PTR(&pin_PA00) }, +}; +MP_DEFINE_CONST_DICT(board_module_globals, board_global_dict_table); diff --git a/ports/atmel-samd/boards/samd21x18-bootloader-crystalless.ld b/ports/atmel-samd/boards/samd21x18-bootloader-crystalless.ld index 56ae5feb46..1d54bb88ca 100644 --- a/ports/atmel-samd/boards/samd21x18-bootloader-crystalless.ld +++ b/ports/atmel-samd/boards/samd21x18-bootloader-crystalless.ld @@ -11,7 +11,8 @@ MEMORY } /* top end of the stack */ -_estack = ORIGIN(RAM) + LENGTH(RAM); +_estack = ORIGIN(RAM) + LENGTH(RAM) - 4; +_bootloader_dbl_tap = _estack; /* define output sections */ SECTIONS diff --git a/ports/atmel-samd/boards/samd21x18-bootloader-external-flash-crystalless.ld b/ports/atmel-samd/boards/samd21x18-bootloader-external-flash-crystalless.ld index 1c04247473..81c1e84501 100644 --- a/ports/atmel-samd/boards/samd21x18-bootloader-external-flash-crystalless.ld +++ b/ports/atmel-samd/boards/samd21x18-bootloader-external-flash-crystalless.ld @@ -11,7 +11,8 @@ MEMORY } /* top end of the stack */ -_estack = ORIGIN(RAM) + LENGTH(RAM); +_estack = ORIGIN(RAM) + LENGTH(RAM) - 4; +_bootloader_dbl_tap = _estack; /* define output sections */ SECTIONS diff --git a/ports/atmel-samd/boards/samd21x18-bootloader-external-flash.ld b/ports/atmel-samd/boards/samd21x18-bootloader-external-flash.ld index 4346c170ce..8563ed3cb3 100644 --- a/ports/atmel-samd/boards/samd21x18-bootloader-external-flash.ld +++ b/ports/atmel-samd/boards/samd21x18-bootloader-external-flash.ld @@ -10,7 +10,8 @@ MEMORY } /* top end of the stack */ -_estack = ORIGIN(RAM) + LENGTH(RAM); +_estack = ORIGIN(RAM) + LENGTH(RAM) - 4; +_bootloader_dbl_tap = _estack; /* define output sections */ SECTIONS diff --git a/ports/atmel-samd/boards/samd21x18-bootloader.ld b/ports/atmel-samd/boards/samd21x18-bootloader.ld index 13a3f75c18..4d2005518f 100644 --- a/ports/atmel-samd/boards/samd21x18-bootloader.ld +++ b/ports/atmel-samd/boards/samd21x18-bootloader.ld @@ -11,7 +11,8 @@ MEMORY } /* top end of the stack */ -_estack = ORIGIN(RAM) + LENGTH(RAM); +_estack = ORIGIN(RAM) + LENGTH(RAM) - 4; +_bootloader_dbl_tap = _estack; /* define output sections */ SECTIONS diff --git a/ports/atmel-samd/boards/samd21x18-external-flash.ld b/ports/atmel-samd/boards/samd21x18-external-flash.ld index f5797cf6f5..629e190b1c 100644 --- a/ports/atmel-samd/boards/samd21x18-external-flash.ld +++ b/ports/atmel-samd/boards/samd21x18-external-flash.ld @@ -12,6 +12,7 @@ MEMORY /* top end of the stack */ _estack = ORIGIN(RAM) + LENGTH(RAM); +_bootloader_dbl_tap = 0; /* define output sections */ SECTIONS diff --git a/ports/atmel-samd/boards/samd21x18.ld b/ports/atmel-samd/boards/samd21x18.ld index a68094758f..9e318e9482 100644 --- a/ports/atmel-samd/boards/samd21x18.ld +++ b/ports/atmel-samd/boards/samd21x18.ld @@ -12,6 +12,7 @@ MEMORY /* top end of the stack */ _estack = ORIGIN(RAM) + LENGTH(RAM); +_bootloader_dbl_tap = 0; /* define output sections */ SECTIONS diff --git a/ports/atmel-samd/boards/samd51x18-bootloader-external-flash.ld b/ports/atmel-samd/boards/samd51x18-bootloader-external-flash.ld index f4ad37c20f..73012b2008 100644 --- a/ports/atmel-samd/boards/samd51x18-bootloader-external-flash.ld +++ b/ports/atmel-samd/boards/samd51x18-bootloader-external-flash.ld @@ -10,7 +10,8 @@ MEMORY } /* top end of the stack */ -_estack = ORIGIN(RAM) + LENGTH(RAM); +_estack = ORIGIN(RAM) + LENGTH(RAM) - 4; +_bootloader_dbl_tap = _estack; /* define output sections */ SECTIONS diff --git a/ports/atmel-samd/boards/samd51x19-bootloader-external-flash.ld b/ports/atmel-samd/boards/samd51x19-bootloader-external-flash.ld index 4e4e8b002d..c9247ec73b 100644 --- a/ports/atmel-samd/boards/samd51x19-bootloader-external-flash.ld +++ b/ports/atmel-samd/boards/samd51x19-bootloader-external-flash.ld @@ -10,7 +10,8 @@ MEMORY } /* top end of the stack */ -_estack = ORIGIN(RAM) + LENGTH(RAM); +_estack = ORIGIN(RAM) + LENGTH(RAM) - 4; +_bootloader_dbl_tap = _estack; /* define output sections */ SECTIONS diff --git a/ports/atmel-samd/boards/samd51x19-bootloader.ld b/ports/atmel-samd/boards/samd51x19-bootloader.ld index 63aada4080..02f38f39fc 100644 --- a/ports/atmel-samd/boards/samd51x19-bootloader.ld +++ b/ports/atmel-samd/boards/samd51x19-bootloader.ld @@ -10,7 +10,8 @@ MEMORY } /* top end of the stack */ -_estack = ORIGIN(RAM) + LENGTH(RAM); +_estack = ORIGIN(RAM) + LENGTH(RAM) - 4; +_bootloader_dbl_tap = _estack; /* define output sections */ SECTIONS diff --git a/ports/atmel-samd/boards/samd51x20-bootloader-external-flash.ld b/ports/atmel-samd/boards/samd51x20-bootloader-external-flash.ld index 57bf299fb4..bae25385af 100644 --- a/ports/atmel-samd/boards/samd51x20-bootloader-external-flash.ld +++ b/ports/atmel-samd/boards/samd51x20-bootloader-external-flash.ld @@ -10,7 +10,8 @@ MEMORY } /* top end of the stack */ -_estack = ORIGIN(RAM) + LENGTH(RAM); +_estack = ORIGIN(RAM) + LENGTH(RAM) - 4; +_bootloader_dbl_tap = _estack; /* define output sections */ SECTIONS diff --git a/ports/atmel-samd/boards/samd51x20-bootloader.ld b/ports/atmel-samd/boards/samd51x20-bootloader.ld index 3d6621a5a9..ee0dcfd7ae 100644 --- a/ports/atmel-samd/boards/samd51x20-bootloader.ld +++ b/ports/atmel-samd/boards/samd51x20-bootloader.ld @@ -10,7 +10,8 @@ MEMORY } /* top end of the stack */ -_estack = ORIGIN(RAM) + LENGTH(RAM); +_estack = ORIGIN(RAM) + LENGTH(RAM) - 4; +_bootloader_dbl_tap = _estack; /* define output sections */ SECTIONS diff --git a/ports/atmel-samd/boards/samd51x20-external-flash.ld b/ports/atmel-samd/boards/samd51x20-external-flash.ld index b0a118507a..4889700a4a 100644 --- a/ports/atmel-samd/boards/samd51x20-external-flash.ld +++ b/ports/atmel-samd/boards/samd51x20-external-flash.ld @@ -11,6 +11,7 @@ MEMORY /* top end of the stack */ _estack = ORIGIN(RAM) + LENGTH(RAM); +_bootloader_dbl_tap = 0; /* define output sections */ SECTIONS diff --git a/ports/atmel-samd/boards/samd51x20.ld b/ports/atmel-samd/boards/samd51x20.ld index ed26425f3f..a30f4525b3 100644 --- a/ports/atmel-samd/boards/samd51x20.ld +++ b/ports/atmel-samd/boards/samd51x20.ld @@ -11,6 +11,7 @@ MEMORY /* top end of the stack */ _estack = ORIGIN(RAM) + LENGTH(RAM); +_bootloader_dbl_tap = 0; /* define output sections */ SECTIONS diff --git a/ports/atmel-samd/boards/trinket_m0_haxpress/mpconfigboard.mk b/ports/atmel-samd/boards/trinket_m0_haxpress/mpconfigboard.mk index 04dc9e4015..a904b2837c 100644 --- a/ports/atmel-samd/boards/trinket_m0_haxpress/mpconfigboard.mk +++ b/ports/atmel-samd/boards/trinket_m0_haxpress/mpconfigboard.mk @@ -4,8 +4,7 @@ USB_PID = 0x801F USB_PRODUCT="Trinket M0 Haxpress" USB_MANUFACTURER="Radomir Dopieralski" -#SPI_FLASH_FILESYSTEM = 1 -INTERNAL_FLASH_FILESYSTEM = 1 +SPI_FLASH_FILESYSTEM = 1 CHIP_VARIANT = SAMD21E18A CHIP_FAMILY = samd21 diff --git a/ports/atmel-samd/boards/ugame/board.c b/ports/atmel-samd/boards/ugame/board.c new file mode 100644 index 0000000000..d7e856d611 --- /dev/null +++ b/ports/atmel-samd/boards/ugame/board.c @@ -0,0 +1,37 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 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 "boards/board.h" + +void board_init(void) { +} + +bool board_requests_safe_mode(void) { + return false; +} + +void reset_board(void) { +} diff --git a/ports/atmel-samd/boards/ugame/conf_access.h b/ports/atmel-samd/boards/ugame/conf_access.h new file mode 100644 index 0000000000..2326bfcdf2 --- /dev/null +++ b/ports/atmel-samd/boards/ugame/conf_access.h @@ -0,0 +1,115 @@ +/** + * \file + * + * \brief Memory access control configuration file. + * + * Copyright (c) 2014-2015 Atmel Corporation. All rights reserved. + * + * \asf_license_start + * + * \page License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 4. This software may only be redistributed and used in connection with an + * Atmel microcontroller product. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * \asf_license_stop + * + */ +/* + * Support and FAQ: visit Atmel Support + */ + +#ifndef _CONF_ACCESS_H_ +#define _CONF_ACCESS_H_ + +#include "compiler.h" +#include "board.h" + + +/*! \name Activation of Logical Unit Numbers + */ +//! @{ +#define LUN_0 ENABLE //!< On-Chip Virtual Memory. +#define LUN_1 DISABLE //!< AT45DBX Data Flash. +#define LUN_2 DISABLE //!< SD/MMC Card over SPI. +#define LUN_3 DISABLE //!< SD/MMC Card over MCI Slot 0. +#define LUN_4 DISABLE +#define LUN_5 DISABLE +#define LUN_6 DISABLE +#define LUN_7 DISABLE +#define LUN_USB DISABLE //!< Host Mass-Storage Memory. +//! @} + +/*! \name LUN 0 Definitions + */ +//! @{ +#define LUN_0_INCLUDE "access_vfs.h" +#define Lun_0_test_unit_ready vfs_test_unit_ready +#define Lun_0_read_capacity vfs_read_capacity +#define Lun_0_unload NULL +#define Lun_0_wr_protect vfs_wr_protect +#define Lun_0_removal vfs_removal +#define Lun_0_usb_read_10 vfs_usb_read_10 +#define Lun_0_usb_write_10 vfs_usb_write_10 +#define LUN_0_NAME "\"CircuitPython VFS[0]\"" +//! @} + +#define MEM_USB LUN_USB + +/*! \name Actions Associated with Memory Accesses + * + * Write here the action to associate with each memory access. + * + * \warning Be careful not to waste time in order not to disturb the functions. + */ +//! @{ +#define memory_start_read_action(nb_sectors) +#define memory_stop_read_action() +#define memory_start_write_action(nb_sectors) +#define memory_stop_write_action() +//! @} + +/*! \name Activation of Interface Features + */ +//! @{ +#define ACCESS_USB true //!< MEM <-> USB interface. +#define ACCESS_MEM_TO_RAM false //!< MEM <-> RAM interface. +#define ACCESS_STREAM false //!< Streaming MEM <-> MEM interface. +#define ACCESS_STREAM_RECORD false //!< Streaming MEM <-> MEM interface in record mode. +#define ACCESS_MEM_TO_MEM false //!< MEM <-> MEM interface. +#define ACCESS_CODEC false //!< Codec interface. +//! @} + +/*! \name Specific Options for Access Control + */ +//! @{ +#define GLOBAL_WR_PROTECT false //!< Management of a global write protection. +//! @} + + +#endif // _CONF_ACCESS_H_ diff --git a/ports/atmel-samd/boards/ugame/conf_board.h b/ports/atmel-samd/boards/ugame/conf_board.h new file mode 100644 index 0000000000..7b88c97fc2 --- /dev/null +++ b/ports/atmel-samd/boards/ugame/conf_board.h @@ -0,0 +1,14 @@ +/** + * \file + * + * \brief User board configuration template + * + */ +/* + * Support and FAQ: visit Atmel Support + */ + +#ifndef CONF_BOARD_H +#define CONF_BOARD_H + +#endif // CONF_BOARD_H diff --git a/ports/atmel-samd/boards/ugame/conf_clocks.h b/ports/atmel-samd/boards/ugame/conf_clocks.h new file mode 100644 index 0000000000..9e4f7876be --- /dev/null +++ b/ports/atmel-samd/boards/ugame/conf_clocks.h @@ -0,0 +1 @@ +#include "conf_clocks_crystalless.h" diff --git a/ports/atmel-samd/boards/ugame/conf_usb.h b/ports/atmel-samd/boards/ugame/conf_usb.h new file mode 100644 index 0000000000..b881ed1499 --- /dev/null +++ b/ports/atmel-samd/boards/ugame/conf_usb.h @@ -0,0 +1,221 @@ + +#include +#include + +#include "asf/common/services/usb/class/cdc/usb_protocol_cdc.h" + +#ifndef CONF_USB_H_INCLUDED +#define CONF_USB_H_INCLUDED + +#define USB_DEVICE_MAJOR_VERSION 1 +#define USB_DEVICE_MINOR_VERSION 0 +#define USB_DEVICE_POWER 100 // Consumption on Vbus line (mA) +#define USB_DEVICE_ATTR \ + (USB_CONFIG_ATTR_BUS_POWERED) +// (USB_CONFIG_ATTR_REMOTE_WAKEUP|USB_CONFIG_ATTR_SELF_POWERED) +// (USB_CONFIG_ATTR_REMOTE_WAKEUP|USB_CONFIG_ATTR_BUS_POWERED) + +//! USB Device string definitions (Optional) +#ifndef USB_DEVICE_MANUFACTURE_NAME +# define USB_DEVICE_MANUFACTURE_NAME "Radomir Dopieralski" +#endif + +#ifndef USB_DEVICE_PRODUCT_NAME +# define USB_DEVICE_PRODUCT_NAME "uGame" +#endif +// #define USB_DEVICE_SERIAL_NAME "12...EF" +#define USB_DEVICE_GET_SERIAL_NAME_POINTER serial_number +#define USB_DEVICE_GET_SERIAL_NAME_LENGTH 32 +extern char serial_number[USB_DEVICE_GET_SERIAL_NAME_LENGTH]; + +//! Control endpoint size +#define USB_DEVICE_EP_CTRL_SIZE 64 + +//! Interfaces for this device (CDC COM + CDC DATA + MSC + HID mouse + HID kbd) +#define USB_DEVICE_NB_INTERFACE 5 + +// (3 | USB_EP_DIR_IN) // CDC Notify endpoint +// (4 | USB_EP_DIR_IN) // CDC TX +// (5 | USB_EP_DIR_OUT) // CDC RX +// (1 | USB_EP_DIR_IN) // MSC IN +// (2 | USB_EP_DIR_OUT) // MSC OUT +// (6 | USB_EP_DIR_IN) // HID mouse report +// (7 | USB_EP_DIR_IN) // HID keyboard report +#define USB_DEVICE_MAX_EP 7 + +#define UDI_CDC_PORT_NB 1 +#define UDI_CDC_ENABLE_EXT(port) mp_cdc_enable(port) +extern bool mp_cdc_enable(uint8_t port); +#define UDI_CDC_DISABLE_EXT(port) mp_cdc_disable(port) +extern void mp_cdc_disable(uint8_t port); +#define UDI_CDC_LOW_RATE + +#define UDI_CDC_DEFAULT_RATE 115200 +#define UDI_CDC_DEFAULT_STOPBITS CDC_STOP_BITS_1 +#define UDI_CDC_DEFAULT_PARITY CDC_PAR_NONE +#define UDI_CDC_DEFAULT_DATABITS 8 + +#define UDI_CDC_RX_NOTIFY(port) usb_rx_notify() +void usb_rx_notify(void); + +#define UDI_CDC_SET_CODING_EXT(port,cfg) usb_coding_notify(port, cfg) +void usb_coding_notify(uint8_t port, usb_cdc_line_coding_t* coding); +#define UDI_CDC_SET_DTR_EXT(port,set) usb_dtr_notify(port, set) +void usb_dtr_notify(uint8_t port, bool set); +#define UDI_CDC_SET_RTS_EXT(port,set) usb_rts_notify(port, set) +void usb_rts_notify(uint8_t port, bool set); + +/** + * USB CDC low level configuration + * In standalone these configurations are defined by the CDC module. + * For composite device, these configuration must be defined here + * @{ + */ +//! Endpoint numbers definition + +#define UDI_CDC_COMM_EP_0 (3 | USB_EP_DIR_IN) // Notify endpoint +#define UDI_CDC_DATA_EP_IN_0 (4 | USB_EP_DIR_IN) // TX +#define UDI_CDC_DATA_EP_OUT_0 (5 | USB_EP_DIR_OUT) // RX + +//! Interface numbers +#define UDI_CDC_COMM_IFACE_NUMBER_0 0 +#define UDI_CDC_DATA_IFACE_NUMBER_0 1 + +/** + * Configuration of MSC interface + * @{ + */ +//! Vendor name and Product version of MSC interface +#define UDI_MSC_GLOBAL_VENDOR_ID \ + 'A', 'T', 'M', 'E', 'L', ' ', ' ', ' ' +#define UDI_MSC_GLOBAL_PRODUCT_VERSION \ + '1', '.', '0', '0' + +//! Interface callback definition +#define UDI_MSC_ENABLE_EXT() mp_msc_enable() +extern bool mp_msc_enable(void); +#define UDI_MSC_DISABLE_EXT() mp_msc_disable() +extern void mp_msc_disable(void); + +//! Enable id string of interface to add an extra USB string +#define UDI_MSC_STRING_ID 5 + +/** + * USB MSC low level configuration + * In standalone these configurations are defined by the MSC module. + * For composite device, these configuration must be defined here + * @{ + */ +//! Endpoint numbers definition +#define UDI_MSC_EP_IN (1 | USB_EP_DIR_IN) +#define UDI_MSC_EP_OUT (2 | USB_EP_DIR_OUT) + +//! Interface number +#define UDI_MSC_IFACE_NUMBER 2 +/** + * Configuration of HID Mouse interface + * @{ + */ +//! Interface callback definition +#define UDI_HID_MOUSE_ENABLE_EXT() mp_mouse_enable() +extern bool mp_mouse_enable(void); +#define UDI_HID_MOUSE_DISABLE_EXT() mp_mouse_disable() +extern void mp_mouse_disable(void); + +//! Enable id string of interface to add an extra USB string +#define UDI_HID_MOUSE_STRING_ID 6 + +/** + * USB HID Mouse low level configuration + * In standalone these configurations are defined by the HID Mouse module. + * For composite device, these configuration must be defined here + * @{ + */ +//! Endpoint numbers definition +#define UDI_HID_MOUSE_EP_IN (6 | USB_EP_DIR_IN) + +//! Interface number +#define UDI_HID_MOUSE_IFACE_NUMBER 3 +//@} +//@} + +/** + * Configuration of HID Keyboard interface + * @{ + */ +//! Interface callback definition +#define UDI_HID_KBD_ENABLE_EXT() mp_keyboard_enable() +extern bool mp_keyboard_enable(void); +#define UDI_HID_KBD_DISABLE_EXT() mp_keyboard_disable() +extern void mp_keyboard_disable(void); +#define UDI_HID_KBD_CHANGE_LED(value) mp_keyboard_led(value) +extern void mp_keyboard_led(uint8_t); + +//! Enable id string of interface to add an extra USB string +#define UDI_HID_KBD_STRING_ID 7 + +/** + * USB HID Keyboard low level configuration + * In standalone these configurations are defined by the HID Keyboard module. + * For composite device, these configuration must be defined here + * @{ + */ +//! Endpoint numbers definition +#define UDI_HID_KBD_EP_IN (7 | USB_EP_DIR_IN) + +//! Interface number +#define UDI_HID_KBD_IFACE_NUMBER 4 + +/** + * Description of Composite Device + * @{ + */ +//! USB Interfaces descriptor structure +#define UDI_COMPOSITE_DESC_T \ + usb_iad_desc_t udi_cdc_iad; \ + udi_cdc_comm_desc_t udi_cdc_comm; \ + udi_cdc_data_desc_t udi_cdc_data; \ + udi_msc_desc_t udi_msc; \ + udi_hid_mouse_desc_t udi_hid_mouse; \ + udi_hid_kbd_desc_t udi_hid_kbd + +//! USB Interfaces descriptor value for Full Speed +#define UDI_COMPOSITE_DESC_FS \ + .udi_cdc_iad = UDI_CDC_IAD_DESC_0, \ + .udi_cdc_comm = UDI_CDC_COMM_DESC_0, \ + .udi_cdc_data = UDI_CDC_DATA_DESC_0_FS, \ + .udi_msc = UDI_MSC_DESC_FS, \ + .udi_hid_mouse = UDI_HID_MOUSE_DESC, \ + .udi_hid_kbd = UDI_HID_KBD_DESC + +//! USB Interfaces descriptor value for High Speed +#define UDI_COMPOSITE_DESC_HS \ + .udi_cdc_iad = UDI_CDC_IAD_DESC_0, \ + .udi_cdc_comm = UDI_CDC_COMM_DESC_0, \ + .udi_cdc_data = UDI_CDC_DATA_DESC_0_HS, \ + .udi_msc = UDI_MSC_DESC_HS, \ + .udi_hid_mouse = UDI_HID_MOUSE_DESC, \ + .udi_hid_kbd = UDI_HID_KBD_DESC + +//! USB Interface APIs +#define UDI_COMPOSITE_API \ + &udi_api_cdc_comm, \ + &udi_api_cdc_data, \ + &udi_api_msc, \ + &udi_api_hid_mouse, \ + &udi_api_hid_kbd +//@} + +/** + * USB Device Driver Configuration + * @{ + */ +//@} + +//! The includes of classes and other headers must be done at the end of this file to avoid compile error +#include "udi_cdc.h" +#include "udi_msc.h" +#include "udi_hid_mouse.h" +#include "udi_hid_kbd.h" + +#endif diff --git a/ports/atmel-samd/boards/ugame/mpconfigboard.h b/ports/atmel-samd/boards/ugame/mpconfigboard.h new file mode 100644 index 0000000000..17baf9b0f8 --- /dev/null +++ b/ports/atmel-samd/boards/ugame/mpconfigboard.h @@ -0,0 +1,48 @@ +#define USB_REPL + +#define MICROPY_HW_BOARD_NAME "uGame" +#define MICROPY_HW_MCU_NAME "samd21e18" + +#if 1 +// Salae reads 12mhz which is the limit even though we set it to the +// safer 8mhz. +#define SPI_FLASH_BAUDRATE (8000000) + +#define SPI_FLASH_MUX_SETTING SPI_SIGNAL_MUX_SETTING_D +#define SPI_FLASH_PAD0_PINMUX PINMUX_PA16D_SERCOM3_PAD0 // MOSI +#define SPI_FLASH_PAD1_PINMUX PINMUX_PA17D_SERCOM3_PAD1 // SCK +#define SPI_FLASH_PAD2_PINMUX PINMUX_UNUSED // Use default pinmux for the chip + // select since we manage it + // ourselves. +#define SPI_FLASH_PAD3_PINMUX PINMUX_PA19D_SERCOM3_PAD3 // MISO +#define SPI_FLASH_SERCOM SERCOM3 + +#define SPI_FLASH_CS PIN_PA11 + +#define MICROPY_PORT_A (PORT_PA11 | PORT_PA16 |\ + PORT_PA17 | PORT_PA18 | PORT_PA19 | PORT_PA24 |\ + PORT_PA25) +#define MICROPY_PORT_B (0) + +#define CALIBRATE_CRYSTALLESS 1 + +#include "spi_flash.h" + +#define CIRCUITPY_INTERNAL_NVM_SIZE 256 +#define BOARD_FLASH_SIZE (0x00040000 - 0x2000 - CIRCUITPY_INTERNAL_NVM_SIZE) + +//#include "flash_W25Q32BV.h" +#include "flash_S25FL216K.h" + +#else + +#define MICROPY_PORT_A (PORT_PA24 | PORT_PA25) +#define MICROPY_PORT_B (0) + +#include "internal_flash.h" + +#define CIRCUITPY_INTERNAL_NVM_SIZE 0 +#define BOARD_FLASH_SIZE (0x00040000 - 0x2000 - 0x010000) + +#endif + diff --git a/ports/atmel-samd/boards/ugame/mpconfigboard.mk b/ports/atmel-samd/boards/ugame/mpconfigboard.mk new file mode 100644 index 0000000000..40f1bc06f8 --- /dev/null +++ b/ports/atmel-samd/boards/ugame/mpconfigboard.mk @@ -0,0 +1,11 @@ +LD_FILE = boards/samd21x18-bootloader-external-flash-crystalless.ld +#LD_FILE = boards/samd21x18-bootloader.ld +USB_VID = 0x239A +USB_PID = 0x801F +USB_PRODUCT = "UGame" +USB_MANUFACTURER = "Radomir Dopieralski" + +SPI_FLASH_FILESYSTEM = 1 + +CHIP_VARIANT = SAMD21E18A +CHIP_FAMILY = samd21 diff --git a/ports/atmel-samd/boards/ugame/pins.c b/ports/atmel-samd/boards/ugame/pins.c new file mode 100644 index 0000000000..b9c8f2386e --- /dev/null +++ b/ports/atmel-samd/boards/ugame/pins.c @@ -0,0 +1,18 @@ +#include "samd21_pins.h" + +STATIC const mp_rom_map_elem_t board_global_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_X), MP_ROM_PTR(&pin_PA00) }, + { MP_ROM_QSTR(MP_QSTR_O), MP_ROM_PTR(&pin_PA01) }, + + { MP_ROM_QSTR(MP_QSTR_SPEAKER), MP_ROM_PTR(&pin_PA02) }, + + { MP_ROM_QSTR(MP_QSTR_UP), MP_ROM_PTR(&pin_PA03) }, + { MP_ROM_QSTR(MP_QSTR_LEFT), MP_ROM_PTR(&pin_PA04) }, + { MP_ROM_QSTR(MP_QSTR_DOWN), MP_ROM_PTR(&pin_PA23) }, + { MP_ROM_QSTR(MP_QSTR_RIGHT), MP_ROM_PTR(&pin_PA05) }, + + { MP_ROM_QSTR(MP_QSTR_MOSI), MP_ROM_PTR(&pin_PA06) }, + { MP_ROM_QSTR(MP_QSTR_SCK), MP_ROM_PTR(&pin_PA07) }, + { MP_ROM_QSTR(MP_QSTR_DC), MP_ROM_PTR(&pin_PA08) }, +}; +MP_DEFINE_CONST_DICT(board_module_globals, board_global_dict_table); diff --git a/ports/atmel-samd/common-hal/analogio/AnalogIn.c b/ports/atmel-samd/common-hal/analogio/AnalogIn.c index 03c502dff7..cbb9f5de51 100644 --- a/ports/atmel-samd/common-hal/analogio/AnalogIn.c +++ b/ports/atmel-samd/common-hal/analogio/AnalogIn.c @@ -74,8 +74,10 @@ uint16_t common_hal_analogio_analogin_get_value(analogio_analogin_obj_t *self) { config_adc.reference = ADC_REFERENCE_INTVCC1; config_adc.gain_factor = ADC_GAIN_FACTOR_DIV2; config_adc.positive_input = self->pin->adc_input; - config_adc.resolution = ADC_RESOLUTION_16BIT; - config_adc.clock_prescaler = ADC_CLOCK_PRESCALER_DIV128; + config_adc.resolution = ADC_RESOLUTION_12BIT; + // Default input clock is GCLK0 (48 MHz) + // 48Mhz / 32 = 1.5MHz. Max ADC clock is 2.1MHz + config_adc.clock_prescaler = ADC_CLOCK_PRESCALER_DIV32; struct adc_module adc_instance; // ADC must have been disabled before adc_init() is called. @@ -108,7 +110,8 @@ uint16_t common_hal_analogio_analogin_get_value(analogio_analogin_obj_t *self) { } adc_disable(&adc_instance); - return data; + // Scale to 16 bits. In the future we might make this be this be under API control. + return data * 16; } float common_hal_analogio_analogin_get_reference_voltage(analogio_analogin_obj_t *self) { diff --git a/ports/atmel-samd/common-hal/audiobusio/PDMIn.c b/ports/atmel-samd/common-hal/audiobusio/PDMIn.c index db671f213f..50d3b180ce 100644 --- a/ports/atmel-samd/common-hal/audiobusio/PDMIn.c +++ b/ports/atmel-samd/common-hal/audiobusio/PDMIn.c @@ -26,6 +26,7 @@ #include #include +#include #include "py/gc.h" #include "py/mperrno.h" @@ -42,6 +43,12 @@ #include "shared_dma.h" #include "tick.h" +#define OVERSAMPLING 64 +#define SAMPLES_PER_BUFFER 32 + +// MEMS microphones must be clocked at at least 1MHz. +#define MIN_MIC_CLOCK 1000000 + void pdmin_reset(void) { while (I2S->SYNCBUSY.reg & I2S_SYNCBUSY_ENABLE) {} I2S->INTENCLR.reg = I2S_INTENCLR_MASK; @@ -96,8 +103,8 @@ void common_hal_audiobusio_pdmin_construct(audiobusio_pdmin_obj_t* self, mp_raise_RuntimeError("Unable to allocate audio DMA block counter."); } - if (!(bit_depth == 16 || bit_depth == 8) || !mono || oversample != 64) { - mp_raise_NotImplementedError("Only 8 or 16 bit mono with 64 oversample is supported."); + if (!(bit_depth == 16 || bit_depth == 8) || !mono || oversample != OVERSAMPLING) { + mp_raise_NotImplementedError("Only 8 or 16 bit mono with " MP_STRINGIFY(OVERSAMPLING) "x oversampling is supported."); } // TODO(tannewt): Use the DPLL to get a more precise sampling rate. @@ -112,12 +119,17 @@ void common_hal_audiobusio_pdmin_construct(audiobusio_pdmin_obj_t* self, config_clock_unit.clock.mck_out_enable = false; config_clock_unit.clock.sck_src = I2S_SERIAL_CLOCK_SOURCE_MCKDIV; - config_clock_unit.clock.sck_div = 8000000 / frequency / oversample; - self->frequency = 8000000 / config_clock_unit.clock.sck_div / oversample; + uint32_t clock_divisor = (uint32_t) roundf( 8000000.0f / frequency / oversample); + config_clock_unit.clock.sck_div = clock_divisor; + float mic_clock_freq = 8000000.0f / clock_divisor; + self->frequency = mic_clock_freq / oversample; + if (mic_clock_freq < MIN_MIC_CLOCK || clock_divisor == 0 || clock_divisor > 255) { + mp_raise_ValueError("sampling frequency out of range"); + } config_clock_unit.frame.number_slots = 2; config_clock_unit.frame.slot_size = I2S_SLOT_SIZE_16_BIT; - config_clock_unit.frame.data_delay = I2S_DATA_DELAY_1; + config_clock_unit.frame.data_delay = I2S_DATA_DELAY_0; config_clock_unit.frame.frame_sync.width = I2S_FRAME_SYNC_WIDTH_SLOT; @@ -141,6 +153,10 @@ void common_hal_audiobusio_pdmin_construct(audiobusio_pdmin_obj_t* self, i2s_serializer_set_config(&self->i2s_instance, self->serializer, &config_serializer); i2s_enable(&self->i2s_instance); + // Run the serializer all the time. This eliminates startup delay for the microphone. + i2s_clock_unit_enable(&self->i2s_instance, self->clock_unit); + i2s_serializer_enable(&self->i2s_instance, self->serializer); + self->bytes_per_sample = oversample >> 3; self->bit_depth = bit_depth; } @@ -154,6 +170,8 @@ void common_hal_audiobusio_pdmin_deinit(audiobusio_pdmin_obj_t* self) { return; } i2s_disable(&self->i2s_instance); + i2s_serializer_disable(&self->i2s_instance, self->serializer); + i2s_clock_unit_disable(&self->i2s_instance, self->clock_unit); i2s_reset(&self->i2s_instance); reset_pin(self->clock_pin->pin); reset_pin(self->data_pin->pin); @@ -195,11 +213,15 @@ static void setup_dma(audiobusio_pdmin_obj_t* self, uint32_t length, } dma_descriptor_create(audio_dma.descriptor, &descriptor_config); + // Do we need more values than will fit in the first buffer? + // If so, set up a second buffer chained to be filled after the first buffer. if (length * words_per_sample > words_per_buffer) { block_transfer_count = words_per_buffer; descriptor_config.next_descriptor_address = ((uint32_t)audio_dma.descriptor); if (length * words_per_sample < 2 * words_per_buffer) { - block_transfer_count = 2 * words_per_buffer - length * words_per_sample; + // Length needed is more than one buffer but less than two. + // Subtract off the size of the first buffer, and what remains is the count we need. + block_transfer_count = length * words_per_sample - words_per_buffer; descriptor_config.next_descriptor_address = 0; } descriptor_config.block_transfer_count = block_transfer_count; @@ -213,117 +235,150 @@ static void setup_dma(audiobusio_pdmin_obj_t* self, uint32_t length, void start_dma(audiobusio_pdmin_obj_t* self) { dma_start_transfer_job(&audio_dma); tc_start_counter(MP_STATE_VM(audiodma_block_counter)); - i2s_clock_unit_enable(&self->i2s_instance, self->clock_unit); - i2s_serializer_enable(&self->i2s_instance, self->serializer); I2S->DATA[1].reg = I2S->DATA[1].reg; } void stop_dma(audiobusio_pdmin_obj_t* self) { - // Turn off the I2S clock and serializer. Peripheral is still enabled. - i2s_serializer_disable(&self->i2s_instance, self->serializer); - i2s_clock_unit_disable(&self->i2s_instance, self->clock_unit); - - // Shutdown the DMA + // Shutdown the DMA: serializer keeps running. tc_stop_counter(MP_STATE_VM(audiodma_block_counter)); dma_abort_job(&audio_dma); } -static const uint16_t sinc_filter[64] = { - 0, 1, 6, 16, 29, 49, 75, 108, - 149, 200, 261, 334, 418, 514, 622, 742, - 872, 1012, 1161, 1315, 1472, 1631, 1787, 1938, - 2081, 2212, 2329, 2429, 2509, 2568, 2604, 2616, - 2604, 2568, 2509, 2429, 2329, 2212, 2081, 1938, - 1787, 1631, 1472, 1315, 1161, 1012, 872, 742, - 622, 514, 418, 334, 261, 200, 149, 108, - 75, 49, 29, 16, 6, 1, 0, 0 +// a windowed sinc filter for 44 khz, 64 samples +// +// This filter is good enough to use for lower sample rates as +// well. It does not increase the noise enough to be a problem. +// +// In the long run we could use a fast filter like this to do the +// decimation and initial filtering in real time, filtering to a +// higher sample rate than specified. Then after the audio is +// recorded, a more expensive filter non-real-time filter could be +// used to down-sample and low-pass. +uint16_t sinc_filter [OVERSAMPLING] = { + 0, 2, 9, 21, 39, 63, 94, 132, + 179, 236, 302, 379, 467, 565, 674, 792, + 920, 1055, 1196, 1341, 1487, 1633, 1776, 1913, + 2042, 2159, 2263, 2352, 2422, 2474, 2506, 2516, + 2506, 2474, 2422, 2352, 2263, 2159, 2042, 1913, + 1776, 1633, 1487, 1341, 1196, 1055, 920, 792, + 674, 565, 467, 379, 302, 236, 179, 132, + 94, 63, 39, 21, 9, 2, 0, 0 }; +#define REPEAT_16_TIMES(X) X X X X X X X X X X X X X X X X + static uint16_t filter_sample(uint32_t pdm_samples[4]) { - uint16_t sample = 0; - for (uint8_t i = 0; i < 4; i++) { - uint16_t pdm = pdm_samples[i] & 0xffff; - for (uint8_t j = 0; j < 16; j++) { - if ((pdm & 0x8000) != 0) { - sample += sinc_filter[i * 16 + j]; + uint16_t running_sum = 0; + const uint16_t *filter_ptr = sinc_filter; + for (uint8_t i = 0; i < OVERSAMPLING/16; i++) { + // The sample is 16-bits right channel in the upper two bytes and 16-bits left channel + // in the lower two bytes. + // We just ignore the upper bits + uint32_t pdm_sample = pdm_samples[i]; + REPEAT_16_TIMES( { + if (pdm_sample & 0x8000) { + running_sum += *filter_ptr; + } + filter_ptr++; + pdm_sample <<= 1; } - pdm <<= 1; - } + ) } - return sample; + return running_sum; } +// output_buffer may be a byte buffer or a halfword buffer. +// output_buffer_length is the number of slots, not the number of bytes. uint32_t common_hal_audiobusio_pdmin_record_to_buffer(audiobusio_pdmin_obj_t* self, - uint16_t* output_buffer, uint32_t length) { - // Write the wave file header. - - // We allocate two 256 byte buffers on the stack to use for double buffering. - // Our oversample rate is 64 (bits) so each buffer produces 32 samples. - // TODO(tannewt): Can the compiler optimize better if we fix the size of - // these buffers? - uint8_t samples_per_buffer = 32; + uint16_t* output_buffer, uint32_t output_buffer_length) { + // We allocate two buffers on the stack to use for double buffering. + const uint8_t samples_per_buffer = SAMPLES_PER_BUFFER; // For every word we record, we throw away 2 bytes of a phantom second channel. - uint8_t words_per_sample = self->bytes_per_sample / 2; - uint8_t words_per_buffer = samples_per_buffer * words_per_sample; + const uint8_t words_per_sample = self->bytes_per_sample / 2; + const uint8_t words_per_buffer = samples_per_buffer * words_per_sample; uint32_t first_buffer[words_per_buffer]; uint32_t second_buffer[words_per_buffer]; COMPILER_ALIGNED(16) DmacDescriptor second_descriptor; - setup_dma(self, length, &second_descriptor, words_per_buffer, + setup_dma(self, output_buffer_length, &second_descriptor, words_per_buffer, words_per_sample, first_buffer, second_buffer); start_dma(self); // Record uint32_t buffers_processed = 0; - uint32_t total_bytes = 0; + uint32_t values_output = 0; - uint64_t start_ticks = ticks_ms; - while (total_bytes < length) { + uint32_t remaining_samples_needed = output_buffer_length; + while (values_output < output_buffer_length) { // Wait for the next buffer to fill - while (tc_get_count_value(MP_STATE_VM(audiodma_block_counter)) == buffers_processed) { + uint32_t block_counter; + while ((block_counter = tc_get_count_value(MP_STATE_VM(audiodma_block_counter))) == buffers_processed) { #ifdef MICROPY_VM_HOOK_LOOP MICROPY_VM_HOOK_LOOP #endif } - if (tc_get_count_value(MP_STATE_VM(audiodma_block_counter)) != (buffers_processed + 1)) { + if (block_counter != (buffers_processed + 1)) { + // Looks like we aren't keeping up. We shouldn't skip a buffer. break; } - // Throw away the first ~10ms of data because thats during mic start up. - if (ticks_ms - start_ticks < 10) { - buffers_processed++; - continue; - } - uint32_t* buffer = first_buffer; + + // The mic is running all the time, so we don't need to wait the usual 10msec or 100msec + // for it to start up. + + // Flip back and forth between processing the first and second buffers. + uint32_t *buffer = first_buffer; DmacDescriptor* descriptor = audio_dma.descriptor; if (buffers_processed % 2 == 1) { buffer = second_buffer; descriptor = &second_descriptor; } - // Decimate and filter the last buffer - int32_t samples_gathered = descriptor->BTCNT.reg / words_per_sample; - for (uint16_t i = 0; i < samples_gathered; i++) { + // Decimate and filter the buffer that was just filled. + uint32_t samples_gathered = descriptor->BTCNT.reg / words_per_sample; + // Don't run off the end of output buffer. Process only as many as needed. + uint32_t samples_to_process = min(remaining_samples_needed, samples_gathered); + for (uint32_t i = 0; i < samples_to_process; i++) { + // Call filter_sample just one place so it can be inlined. + uint16_t value = filter_sample(buffer + i * words_per_sample); if (self->bit_depth == 8) { - ((uint8_t*) output_buffer)[total_bytes] = filter_sample(buffer + i * words_per_sample) >> 8; - total_bytes += 1; - } else if (self->bit_depth == 16) { - output_buffer[total_bytes / 2] = filter_sample(buffer + i * words_per_sample); - total_bytes += 2; + // Truncate to 8 bits. + ((uint8_t*) output_buffer)[values_output] = value >> 8; + } else { + output_buffer[values_output] = value; } + values_output++; } + buffers_processed++; - if (length - total_bytes < samples_per_buffer) { - descriptor->BTCNT.reg = (length - total_bytes) * words_per_sample; - descriptor->DSTADDR.reg = ((uint32_t) buffer) + (length - total_bytes) * self->bytes_per_sample; + // Compute how many more samples we need, and if the last buffer is the last + // set of samples needed, adjust the DMA count to only fetch as necessary. + remaining_samples_needed = output_buffer_length - values_output; + if (remaining_samples_needed <= samples_per_buffer*2 && + remaining_samples_needed > samples_per_buffer) { + // Adjust the DMA settings for the current buffer, which will be processed + // after the other buffer, which is now receiving samples via DMA. + // We don't adjust the DMA in progress, but the one after that. + // Timeline: + // 1. current buffer (already processed) + // 2. alternate buffer (DMA in progress) + // 3. current buffer (last set of samples needed) + + // Set up to receive the last set of samples (don't include the alternate buffer, now in use). + uint32_t samples_needed_for_last_buffer = remaining_samples_needed - samples_per_buffer; + descriptor->BTCNT.reg = samples_needed_for_last_buffer * words_per_sample; + descriptor->DSTADDR.reg = ((uint32_t) buffer) + + samples_needed_for_last_buffer * words_per_sample * sizeof(buffer[0]); + + // Break chain to alternate buffer. descriptor->DESCADDR.reg = 0; } } stop_dma(self); - return total_bytes; + return values_output; } void common_hal_audiobusio_pdmin_record_to_file(audiobusio_pdmin_obj_t* self, uint8_t* buffer, uint32_t length) { diff --git a/ports/atmel-samd/common-hal/busio/SPI.c b/ports/atmel-samd/common-hal/busio/SPI.c index cb6a165def..4414d7ca91 100644 --- a/ports/atmel-samd/common-hal/busio/SPI.c +++ b/ports/atmel-samd/common-hal/busio/SPI.c @@ -262,3 +262,20 @@ bool common_hal_busio_spi_read(busio_spi_obj_t *self, // } return status >= 0; // Status is number of chars read or an error code < 0. } + +bool common_hal_busio_spi_transfer(busio_spi_obj_t *self, uint8_t *data_out, uint8_t *data_in, size_t len) { + if (len == 0) { + return true; + } + int32_t status; +// if (len >= 16) { +// status = shared_dma_transfer(self->spi_master_instance.hw, data_out, data_in, len, 0 /*ignored*/); +// } else { + struct spi_xfer xfer; + xfer.txbuf = data_out; + xfer.rxbuf = data_in; + xfer.size = len; + status = spi_m_sync_transfer(&self->spi_desc, &xfer); +// } + return status >= 0; // Status is number of chars read or an error code < 0. +} diff --git a/ports/atmel-samd/common-hal/digitalio/DigitalInOut.c b/ports/atmel-samd/common-hal/digitalio/DigitalInOut.c index c5fff4ba29..109f14b04d 100644 --- a/ports/atmel-samd/common-hal/digitalio/DigitalInOut.c +++ b/ports/atmel-samd/common-hal/digitalio/DigitalInOut.c @@ -58,7 +58,7 @@ void common_hal_digitalio_digitalinout_deinit(digitalio_digitalinout_obj_t* self } void common_hal_digitalio_digitalinout_switch_to_input( - digitalio_digitalinout_obj_t* self, enum digitalio_pull_t pull) { + digitalio_digitalinout_obj_t* self, digitalio_pull_t pull) { self->output = false; common_hal_digitalio_digitalinout_set_pull(self, pull); @@ -66,7 +66,7 @@ void common_hal_digitalio_digitalinout_switch_to_input( void common_hal_digitalio_digitalinout_switch_to_output( digitalio_digitalinout_obj_t* self, bool value, - enum digitalio_drive_mode_t drive_mode) { + digitalio_drive_mode_t drive_mode) { const uint8_t pin = self->pin->pin; gpio_set_pin_pull_mode(pin, GPIO_PULL_OFF); gpio_set_pin_direction(pin, GPIO_DIRECTION_OUT); @@ -79,7 +79,7 @@ void common_hal_digitalio_digitalinout_switch_to_output( common_hal_digitalio_digitalinout_set_value(self, value); } -enum digitalio_direction_t common_hal_digitalio_digitalinout_get_direction( +digitalio_direction_t common_hal_digitalio_digitalinout_get_direction( digitalio_digitalinout_obj_t* self) { return self->output? DIRECTION_OUTPUT : DIRECTION_INPUT; } @@ -115,7 +115,7 @@ bool common_hal_digitalio_digitalinout_get_value( void common_hal_digitalio_digitalinout_set_drive_mode( digitalio_digitalinout_obj_t* self, - enum digitalio_drive_mode_t drive_mode) { + digitalio_drive_mode_t drive_mode) { bool value = common_hal_digitalio_digitalinout_get_value(self); self->open_drain = drive_mode == DRIVE_MODE_OPEN_DRAIN; // True is implemented differently between modes so reset the value to make @@ -125,7 +125,7 @@ void common_hal_digitalio_digitalinout_set_drive_mode( } } -enum digitalio_drive_mode_t common_hal_digitalio_digitalinout_get_drive_mode( +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; @@ -135,7 +135,7 @@ enum digitalio_drive_mode_t common_hal_digitalio_digitalinout_get_drive_mode( } void common_hal_digitalio_digitalinout_set_pull( - digitalio_digitalinout_obj_t* self, enum digitalio_pull_t pull) { + digitalio_digitalinout_obj_t* self, digitalio_pull_t pull) { enum gpio_pull_mode asf_pull = GPIO_PULL_OFF; switch (pull) { case PULL_UP: @@ -151,7 +151,7 @@ void common_hal_digitalio_digitalinout_set_pull( gpio_set_pin_pull_mode(self->pin->pin, asf_pull); } -enum digitalio_pull_t common_hal_digitalio_digitalinout_get_pull( +digitalio_pull_t common_hal_digitalio_digitalinout_get_pull( digitalio_digitalinout_obj_t* self) { uint32_t pin = self->pin->pin; if (self->output) { diff --git a/ports/atmel-samd/common-hal/microcontroller/__init__.c b/ports/atmel-samd/common-hal/microcontroller/__init__.c index 5c119c439c..614fac870b 100644 --- a/ports/atmel-samd/common-hal/microcontroller/__init__.c +++ b/ports/atmel-samd/common-hal/microcontroller/__init__.c @@ -27,10 +27,13 @@ #include "py/mphal.h" #include "py/obj.h" #include "hal/include/hal_atomic.h" +#include "py/runtime.h" +#include "reset.h" #include "samd21_pins.h" #include "shared-bindings/nvm/ByteArray.h" +#include "shared-bindings/microcontroller/__init__.h" #include "shared-bindings/microcontroller/Processor.h" void common_hal_mcu_delay_us(uint32_t delay) { @@ -48,9 +51,32 @@ void common_hal_mcu_enable_interrupts(void) { atomic_leave_critical(&flags); } +extern uint32_t _ezero; + +void common_hal_mcu_on_next_reset(mcu_runmode_t runmode) { + // Set up the defaults. + _bootloader_dbl_tap = DBL_TAP_MAGIC; + _ezero = CIRCUITPY_CANARY_WORD; + + if (runmode == RUNMODE_BOOTLOADER) { + if (!bootloader_available()) { + mp_raise_ValueError("Cannot reset into bootloader because no bootloader is present."); + } + // Pretend to be the first of the two reset presses needed to enter the + // bootloader. That way one reset will end in the bootloader. + _bootloader_dbl_tap = DBL_TAP_MAGIC; + } else if (runmode == RUNMODE_SAFE_MODE) { + _ezero = CIRCUITPY_SOFTWARE_SAFE_MODE; + } +} + +void common_hal_mcu_reset(void) { + reset(); +} + // The singleton microcontroller.Processor object, bound to microcontroller.cpu // It currently only has properties, and no state. -mcu_processor_obj_t common_hal_mcu_processor_obj = { +const mcu_processor_obj_t common_hal_mcu_processor_obj = { .base = { .type = &mcu_processor_type, }, @@ -59,7 +85,7 @@ mcu_processor_obj_t common_hal_mcu_processor_obj = { // NVM is only available on Express boards for now. #if CIRCUITPY_INTERNAL_NVM_SIZE > 0 // The singleton nvm.ByteArray object. -// nvm_bytearray_obj_t common_hal_mcu_nvm_obj = { +// const nvm_bytearray_obj_t common_hal_mcu_nvm_obj = { // .base = { // .type = &nvm_bytearray_type, // }, diff --git a/ports/atmel-samd/reset.c b/ports/atmel-samd/reset.c index ab940285bb..ba5bf9ba1f 100644 --- a/ports/atmel-samd/reset.c +++ b/ports/atmel-samd/reset.c @@ -24,23 +24,22 @@ * THE SOFTWARE. */ -#include "reset.h" - #include "include/sam.h" + +#include "reset.h" #include "supervisor/filesystem.h" -// Copied from inc/uf2.h in https://github.com/Microsoft/uf2-samd21 -#ifdef SAMD21 -#define DBL_TAP_PTR ((volatile uint32_t *)(HMCRAMC0_ADDR + HMCRAMC0_SIZE - 4)) -#else - #ifdef SAMD51 - #define DBL_TAP_PTR ((volatile uint32_t *)(HSRAM_ADDR + HSRAM_SIZE - 4)) - #endif -#endif -#define DBL_TAP_MAGIC 0xf01669ef // Randomly selected, adjusted to have first and last bit set - -void reset_to_bootloader(void) { +void reset(void) { filesystem_flush(); - *DBL_TAP_PTR = DBL_TAP_MAGIC; NVIC_SystemReset(); } + +void reset_to_bootloader(void) { + _bootloader_dbl_tap = DBL_TAP_MAGIC; + reset(); +} + +extern uint32_t _srelocate; +bool bootloader_available(void) { + return &_bootloader_dbl_tap >= &_srelocate; +} diff --git a/ports/atmel-samd/reset.h b/ports/atmel-samd/reset.h index 88140f3b83..ea955c655d 100644 --- a/ports/atmel-samd/reset.h +++ b/ports/atmel-samd/reset.h @@ -26,6 +26,16 @@ #ifndef MICROPY_INCLUDED_ATMEL_SAMD_RESET_H #define MICROPY_INCLUDED_ATMEL_SAMD_RESET_H +#include +#include + +// Copied from inc/uf2.h in https://github.com/Microsoft/uf2-samd21 +#define DBL_TAP_MAGIC 0xf01669ef // Randomly selected, adjusted to have first and last bit set + +extern uint32_t _bootloader_dbl_tap; + void reset_to_bootloader(void); +void reset(void); +bool bootloader_available(void); #endif // MICROPY_INCLUDED_ATMEL_SAMD_RESET_H diff --git a/ports/atmel-samd/shared_dma.c b/ports/atmel-samd/shared_dma.c index f8cef0992c..59fca30c81 100644 --- a/ports/atmel-samd/shared_dma.c +++ b/ports/atmel-samd/shared_dma.c @@ -106,7 +106,7 @@ int32_t shared_dma_write(Sercom* sercom, const uint8_t* buffer, uint32_t length) } dma_configure(general_dma_tx.channel_id, sercom_index(sercom) * 2 + 2, false); - // Set up TX second. + // Set up TX. There is no RX job. struct dma_descriptor_config descriptor_config; dma_descriptor_get_config_defaults(&descriptor_config); descriptor_config.beat_size = DMA_BEAT_SIZE_BYTE; @@ -141,6 +141,11 @@ int32_t shared_dma_write(Sercom* sercom, const uint8_t* buffer, uint32_t length) int32_t shared_dma_read(Sercom* sercom, uint8_t* buffer, uint32_t length, uint8_t tx) { if (general_dma_tx.job_status != ERR_NONE) { +} + +// Do write and read simultaneously. If buffer_out is NULL, write the tx byte over and over. +// If buffer_out is a real buffer, ignore tx. +enum status_code shared_dma_transfer(Sercom* sercom, uint8_t* buffer_out, uint8_t* buffer_in, uint32_t length, uint8_t tx) { return general_dma_tx.job_status; } @@ -156,17 +161,19 @@ int32_t shared_dma_read(Sercom* sercom, uint8_t* buffer, uint32_t length, uint8_ descriptor_config.block_transfer_count = length; // DATA register is consistently addressed across all SERCOM modes. descriptor_config.source_address = ((uint32_t)&sercom->SPI.DATA.reg); - descriptor_config.destination_address = ((uint32_t)buffer + length); + descriptor_config.destination_address = ((uint32_t)buffer_in + length); dma_descriptor_create(general_dma_rx.descriptor, &descriptor_config); - // Set up TX to retransmit the same byte over and over. + // Set up TX second. dma_descriptor_get_config_defaults(&descriptor_config); descriptor_config.beat_size = DMA_BEAT_SIZE_BYTE; - descriptor_config.src_increment_enable = false; + // Increment write address only if we have a real buffer. + descriptor_config.src_increment_enable = buffer_out != NULL; descriptor_config.dst_increment_enable = false; descriptor_config.block_transfer_count = length; - descriptor_config.source_address = ((uint32_t)&tx); + // + descriptor_config.source_address = ((uint32_t) (buffer_out != NULL ? buffer_out + length : &tx)); // DATA register is consistently addressed across all SERCOM modes. descriptor_config.destination_address = ((uint32_t)&sercom->SPI.DATA.reg); diff --git a/ports/atmel-samd/shared_dma.h b/ports/atmel-samd/shared_dma.h index 1e9240338f..2ddd81c4e4 100644 --- a/ports/atmel-samd/shared_dma.h +++ b/ports/atmel-samd/shared_dma.h @@ -37,6 +37,7 @@ void init_shared_dma(void); enum status_code shared_dma_write(Sercom* sercom, const uint8_t* buffer, uint32_t length); enum status_code shared_dma_read(Sercom* sercom, uint8_t* buffer, uint32_t length, uint8_t tx); +enum status_code shared_dma_transfer(Sercom* sercom, uint8_t* buffer_out, uint8_t* buffer_in, uint32_t length, uint8_t tx); // Allocate a counter to track how far along we are in a DMA double buffer. bool allocate_block_counter(void); diff --git a/ports/esp8266/Makefile b/ports/esp8266/Makefile index ebb8981ef5..70c5c96773 100644 --- a/ports/esp8266/Makefile +++ b/ports/esp8266/Makefile @@ -130,6 +130,7 @@ SRC_BINDINGS_ENUMS = \ digitalio/DriveMode.c \ digitalio/Pull.c \ math/__init__.c \ + microcontroller/RunMode.c \ util.c SRC_COMMON_HAL_EXPANDED = $(addprefix shared-bindings/, $(SRC_COMMON_HAL)) \ diff --git a/ports/esp8266/common-hal/busio/SPI.c b/ports/esp8266/common-hal/busio/SPI.c index 50ad03460e..aa2b3a3547 100644 --- a/ports/esp8266/common-hal/busio/SPI.c +++ b/ports/esp8266/common-hal/busio/SPI.c @@ -185,3 +185,23 @@ bool common_hal_busio_spi_read(busio_spi_obj_t *self, } return true; } + +bool common_hal_busio_spi_transfer(busio_spi_obj_t *self, uint8_t *data_out, uint8_t *data_in, size_t len) { + // Process data in chunks, let the pending tasks run in between + size_t chunk_size = 1024; // TODO this should depend on baudrate + size_t count = len / chunk_size; + size_t i = 0; + for (size_t j = 0; j < count; ++j) { + for (size_t k = 0; k < chunk_size; ++k) { + data_in[i] = spi_transaction(HSPI, 0, 0, 0, 0, 8, data_out[i], 8, 0); + ++i; + } + ets_loop_iter(); + } + while (i < len) { + data_in[i] = spi_transaction(HSPI, 0, 0, 0, 0, 8, data_out[i], 8, 0); + ++i; + } + return true; + +} diff --git a/ports/esp8266/common-hal/digitalio/DigitalInOut.c b/ports/esp8266/common-hal/digitalio/DigitalInOut.c index 70ed207d59..7101e64145 100644 --- a/ports/esp8266/common-hal/digitalio/DigitalInOut.c +++ b/ports/esp8266/common-hal/digitalio/DigitalInOut.c @@ -59,7 +59,7 @@ void common_hal_digitalio_digitalinout_deinit(digitalio_digitalinout_obj_t* self } void common_hal_digitalio_digitalinout_switch_to_input( - digitalio_digitalinout_obj_t* self, enum digitalio_pull_t pull) { + digitalio_digitalinout_obj_t* self, digitalio_pull_t pull) { self->output = false; if (self->pin->gpio_number == 16) { @@ -75,7 +75,7 @@ void common_hal_digitalio_digitalinout_switch_to_input( void common_hal_digitalio_digitalinout_switch_to_output( digitalio_digitalinout_obj_t* self, bool value, - enum digitalio_drive_mode_t drive_mode) { + digitalio_drive_mode_t drive_mode) { self->output = true; self->open_drain = drive_mode == DRIVE_MODE_OPEN_DRAIN; if (self->pin->gpio_number == 16) { @@ -89,7 +89,7 @@ void common_hal_digitalio_digitalinout_switch_to_output( common_hal_digitalio_digitalinout_set_value(self, value); } -enum digitalio_direction_t common_hal_digitalio_digitalinout_get_direction( +digitalio_direction_t common_hal_digitalio_digitalinout_get_direction( digitalio_digitalinout_obj_t* self) { return self->output? DIRECTION_OUTPUT : DIRECTION_INPUT; } @@ -136,7 +136,7 @@ bool common_hal_digitalio_digitalinout_get_value( void common_hal_digitalio_digitalinout_set_drive_mode( digitalio_digitalinout_obj_t* self, - enum digitalio_drive_mode_t drive_mode) { + digitalio_drive_mode_t drive_mode) { bool value = common_hal_digitalio_digitalinout_get_value(self); self->open_drain = drive_mode == DRIVE_MODE_OPEN_DRAIN; // True is implemented differently between modes so reset the value to make @@ -146,7 +146,7 @@ void common_hal_digitalio_digitalinout_set_drive_mode( } } -enum digitalio_drive_mode_t common_hal_digitalio_digitalinout_get_drive_mode( +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; @@ -156,7 +156,7 @@ enum digitalio_drive_mode_t common_hal_digitalio_digitalinout_get_drive_mode( } void common_hal_digitalio_digitalinout_set_pull( - digitalio_digitalinout_obj_t* self, enum digitalio_pull_t pull) { + digitalio_digitalinout_obj_t* self, digitalio_pull_t pull) { if (pull == PULL_DOWN) { nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "ESP8266 does not support pull down.")); @@ -174,7 +174,7 @@ void common_hal_digitalio_digitalinout_set_pull( } } -enum digitalio_pull_t common_hal_digitalio_digitalinout_get_pull( +digitalio_pull_t common_hal_digitalio_digitalinout_get_pull( digitalio_digitalinout_obj_t* self) { if (self->pin->gpio_number < 16 && (READ_PERI_REG(self->pin->peripheral) & PERIPHS_IO_MUX_PULLUP) != 0) { diff --git a/ports/esp8266/common-hal/microcontroller/__init__.c b/ports/esp8266/common-hal/microcontroller/__init__.c index 6aef23761c..6d446ceacb 100644 --- a/ports/esp8266/common-hal/microcontroller/__init__.c +++ b/ports/esp8266/common-hal/microcontroller/__init__.c @@ -24,9 +24,12 @@ * THE SOFTWARE. */ +#include "py/runtime.h" + #include "common-hal/microcontroller/Pin.h" #include "common-hal/microcontroller/Processor.h" +#include "shared-bindings/microcontroller/__init__.h" #include "shared-bindings/microcontroller/Pin.h" #include "shared-bindings/microcontroller/Processor.h" @@ -34,6 +37,7 @@ #include "ets_alt_task.h" #include "etshal.h" #include "osapi.h" +#include "user_interface.h" #include "xtirq.h" #define ETS_LOOP_ITER_BIT (12) @@ -54,9 +58,21 @@ void common_hal_mcu_enable_interrupts() { enable_irq(saved_interrupt_state & ~(1 << ETS_LOOP_ITER_BIT)); } +void common_hal_mcu_on_next_reset(mcu_runmode_t runmode) { + if (runmode == RUNMODE_BOOTLOADER) { + mp_raise_ValueError("Cannot reset into bootloader because no bootloader is present."); + } else if (runmode == RUNMODE_SAFE_MODE) { + mp_raise_ValueError("ESP8226 does not support safe mode."); + } +} + +void common_hal_mcu_reset(void) { + system_restart(); +} + // The singleton microcontroller.Processor object, returned by microcontroller.cpu // It currently only has properties, and no state. -mcu_processor_obj_t common_hal_mcu_processor_obj = { +const mcu_processor_obj_t common_hal_mcu_processor_obj = { .base = { .type = &mcu_processor_type, }, diff --git a/ports/nrf/mpconfigport.mk b/ports/nrf/mpconfigport.mk index dc29a92cf5..17304b783b 100644 --- a/ports/nrf/mpconfigport.mk +++ b/ports/nrf/mpconfigport.mk @@ -2,3 +2,6 @@ # $(MPY-TOOL) needs to know what kind of longint to use (if any) to freeze long integers. # This should correspond to the MICROPY_LONGINT_IMPL definition in mpconfigport.h. MPY_TOOL_LONGINT_IMPL = -mlongint-impl=mpz + +INTERNAL_LIBM = (1) + diff --git a/py/makeversionhdr.py b/py/makeversionhdr.py index 30995f9372..ebd887445b 100644 --- a/py/makeversionhdr.py +++ b/py/makeversionhdr.py @@ -86,6 +86,7 @@ def make_version_header(filename): #define MICROPY_VERSION_MINOR (%s) #define MICROPY_VERSION_MICRO (%s) #define MICROPY_VERSION_STRING "%s" +#define MICROPY_FULL_VERSION_INFO ("Adafruit CircuitPython " MICROPY_GIT_TAG " on " MICROPY_BUILD_DATE "; " MICROPY_HW_BOARD_NAME " with " MICROPY_HW_MCU_NAME) """ % (git_tag, git_hash, datetime.date.today().strftime("%Y-%m-%d"), ver[0].replace('v', ''), ver[1], ver[2], version_string) diff --git a/py/mkenv.mk b/py/mkenv.mk index 5a118854aa..5f8cd902bf 100644 --- a/py/mkenv.mk +++ b/py/mkenv.mk @@ -70,6 +70,7 @@ endif MAKE_FROZEN = $(TOP)/tools/make-frozen.py MPY_CROSS = $(TOP)/mpy-cross/mpy-cross MPY_TOOL = $(TOP)/tools/mpy-tool.py +PREPROCESS_FROZEN_MODULES = PYTHONPATH=$(TOP)/tools/python-semver $(TOP)/tools/preprocess_frozen_modules.py all: .PHONY: all diff --git a/py/mkrules.mk b/py/mkrules.mk index a7a2d492a4..7385ad57ac 100644 --- a/py/mkrules.mk +++ b/py/mkrules.mk @@ -114,13 +114,13 @@ $(MPY_CROSS): $(TOP)/py/*.[ch] $(TOP)/mpy-cross/*.[ch] $(TOP)/ports/windows/fmod $(Q)$(MAKE) -C $(TOP)/mpy-cross # Copy all the modules and single python files to freeze to a common area, omitting top-level dirs (the repo names). -# Remove any conf.py (sphinx config) and setup.py (module install info) files, which are not meant to be frozen. +# Do any preprocessing necessary: currently, this adds version information, removes examples, and +# non-library .py files in the modules (setup.py and conf.py) # Then compile .mpy files from all the .py files, placing them in the same directories as the .py files. $(BUILD)/frozen_mpy: $(FROZEN_MPY_DIRS) $(ECHO) FREEZE $(FROZEN_MPY_DIRS) $(Q)$(MKDIR) -p $@ - $(Q)$(RSYNC) -rL --include="*/" --include='*.py' --exclude="*" $(addsuffix /*,$(FROZEN_MPY_DIRS)) $@ - $(Q)$(RM) -f $@/conf.py $@/setup.py + $(Q)$(PREPROCESS_FROZEN_MODULES) -o $@ $(FROZEN_MPY_DIRS) $(Q)$(CD) $@ && \ $(FIND) -L . -type f -name '*.py' | sed 's=^\./==' | \ xargs -n1 $(abspath $(MPY_CROSS)) $(MPY_CROSS_FLAGS) diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index 75df61718c..0000000000 --- a/requirements.txt +++ /dev/null @@ -1 +0,0 @@ -# dummy file to work around readthedocs bug: https://github.com/rtfd/readthedocs.org/issues/2855 diff --git a/shared-bindings/_stage/Layer.c b/shared-bindings/_stage/Layer.c new file mode 100644 index 0000000000..3e615c4977 --- /dev/null +++ b/shared-bindings/_stage/Layer.c @@ -0,0 +1,130 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 Radomir Dopieralski + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include + +#include "__init__.h" +#include "Layer.h" + +//| .. currentmodule:: _stage +//| +//| :class:`Layer` -- Keep information about a single layer of graphics +//| =================================================================== +//| +//| .. class:: Layer(width, height, graphic, palette, [grid]) +//| +//| Keep internal information about a layer of graphics (either a +//| ``Grid`` or a ``Sprite``) in a format suitable for fast rendering +//| with the ``render()`` function. +//| +//| :param int width: The width of the grid in tiles, or 1 for sprites. +//| :param int height: The height of the grid in tiles, or 1 for sprites. +//| :param bytearray graphic: The graphic data of the tiles. +//| :param bytearray palette: The color palette to be used. +//| :param bytearray grid: The contents of the grid map. +//| +//| This class is intended for internal use in the ``stage`` library and +//| it shouldn't be used on its own. +//| +STATIC mp_obj_t layer_make_new(const mp_obj_type_t *type, size_t n_args, + size_t n_kw, const mp_obj_t *args) { + mp_arg_check_num(n_args, n_kw, 4, 5, false); + + layer_obj_t *self = m_new_obj(layer_obj_t); + self->base.type = type; + + self->width = mp_obj_get_int(args[0]); + self->height = mp_obj_get_int(args[1]); + self->x = 0; + self->y = 0; + self->frame = 0; + self->rotation = false; + + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(args[2], &bufinfo, MP_BUFFER_READ); + self->graphic = bufinfo.buf; + if (bufinfo.len != 2048) { + mp_raise_ValueError("graphic must be 2048 bytes long"); + } + + mp_get_buffer_raise(args[3], &bufinfo, MP_BUFFER_READ); + self->palette = bufinfo.buf; + if (bufinfo.len != 32) { + mp_raise_ValueError("palette must be 32 bytes long"); + } + + if (n_args > 4) { + mp_get_buffer_raise(args[4], &bufinfo, MP_BUFFER_READ); + self->map = bufinfo.buf; + if (bufinfo.len < (self->width * self->height) / 2) { + mp_raise_ValueError("map buffer too small"); + } + } else { + self-> map = NULL; + } + + return MP_OBJ_FROM_PTR(self); +} + +//| .. method:: move(x, y) +//| +//| Set the offset of the layer to the specified values. +//| +STATIC mp_obj_t layer_move(mp_obj_t self_in, mp_obj_t x_in, mp_obj_t y_in) { + layer_obj_t *self = MP_OBJ_TO_PTR(self_in); + self->x = mp_obj_get_int(x_in); + self->y = mp_obj_get_int(y_in); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_3(layer_move_obj, layer_move); + +//| .. method:: frame(frame, rotation) +//| +//| Set the animation frame of the sprite, and optionally rotation its +//| graphic. +//| +STATIC mp_obj_t layer_frame(mp_obj_t self_in, mp_obj_t frame_in, + mp_obj_t rotation_in) { + layer_obj_t *self = MP_OBJ_TO_PTR(self_in); + self->frame = mp_obj_get_int(frame_in); + self->rotation = mp_obj_get_int(rotation_in); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_3(layer_frame_obj, layer_frame); + + +STATIC const mp_rom_map_elem_t layer_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_move), MP_ROM_PTR(&layer_move_obj) }, + { MP_ROM_QSTR(MP_QSTR_frame), MP_ROM_PTR(&layer_frame_obj) }, +}; +STATIC MP_DEFINE_CONST_DICT(layer_locals_dict, layer_locals_dict_table); + +const mp_obj_type_t mp_type_layer = { + { &mp_type_type }, + .name = MP_QSTR_Layer, + .make_new = layer_make_new, + .locals_dict = (mp_obj_dict_t*)&layer_locals_dict, +}; diff --git a/shared-bindings/_stage/Layer.h b/shared-bindings/_stage/Layer.h new file mode 100644 index 0000000000..6d15dfb288 --- /dev/null +++ b/shared-bindings/_stage/Layer.h @@ -0,0 +1,34 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 Radomir Dopieralski + * + * 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__STAGE_LAYER_H +#define MICROPY_INCLUDED__STAGE_LAYER_H + +#include "shared-module/_stage/Layer.h" + +extern const mp_obj_type_t mp_type_layer; + +#endif // MICROPY_INCLUDED__STAGE_LAYER diff --git a/shared-bindings/_stage/Text.c b/shared-bindings/_stage/Text.c new file mode 100644 index 0000000000..c62d22afee --- /dev/null +++ b/shared-bindings/_stage/Text.c @@ -0,0 +1,109 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 Radomir Dopieralski + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include + +#include "__init__.h" +#include "Text.h" + +//| .. currentmodule:: _stage +//| +//| :class:`Text` -- Keep information about a single text of text +//| ============================================================== +//| +//| .. class:: Text(width, height, font, palette, chars) +//| +//| Keep internal information about a text of text +//| in a format suitable for fast rendering +//| with the ``render()`` function. +//| +//| :param int width: The width of the grid in tiles, or 1 for sprites. +//| :param int height: The height of the grid in tiles, or 1 for sprites. +//| :param bytearray font: The font data of the characters. +//| :param bytearray palette: The color palette to be used. +//| :param bytearray chars: The contents of the character grid. +//| +//| This class is intended for internal use in the ``stage`` library and +//| it shouldn't be used on its own. +//| +STATIC mp_obj_t text_make_new(const mp_obj_type_t *type, size_t n_args, + size_t n_kw, const mp_obj_t *args) { + mp_arg_check_num(n_args, n_kw, 5, 5, false); + + text_obj_t *self = m_new_obj(text_obj_t); + self->base.type = type; + + self->width = mp_obj_get_int(args[0]); + self->height = mp_obj_get_int(args[1]); + self->x = 0; + self->y = 0; + + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(args[2], &bufinfo, MP_BUFFER_READ); + self->font = bufinfo.buf; + if (bufinfo.len != 2048) { + mp_raise_ValueError("font must be 2048 bytes long"); + } + + mp_get_buffer_raise(args[3], &bufinfo, MP_BUFFER_READ); + self->palette = bufinfo.buf; + if (bufinfo.len != 32) { + mp_raise_ValueError("palette must be 32 bytes long"); + } + + mp_get_buffer_raise(args[4], &bufinfo, MP_BUFFER_READ); + self->chars = bufinfo.buf; + if (bufinfo.len < self->width * self->height) { + mp_raise_ValueError("chars buffer too small"); + } + + return MP_OBJ_FROM_PTR(self); +} + +//| .. method:: move(x, y) +//| +//| Set the offset of the text to the specified values. +//| +STATIC mp_obj_t text_move(mp_obj_t self_in, mp_obj_t x_in, mp_obj_t y_in) { + text_obj_t *self = MP_OBJ_TO_PTR(self_in); + self->x = mp_obj_get_int(x_in); + self->y = mp_obj_get_int(y_in); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_3(text_move_obj, text_move); + + +STATIC const mp_rom_map_elem_t text_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_move), MP_ROM_PTR(&text_move_obj) }, +}; +STATIC MP_DEFINE_CONST_DICT(text_locals_dict, text_locals_dict_table); + +const mp_obj_type_t mp_type_text = { + { &mp_type_type }, + .name = MP_QSTR_Text, + .make_new = text_make_new, + .locals_dict = (mp_obj_dict_t*)&text_locals_dict, +}; diff --git a/shared-bindings/_stage/Text.h b/shared-bindings/_stage/Text.h new file mode 100644 index 0000000000..77de62a110 --- /dev/null +++ b/shared-bindings/_stage/Text.h @@ -0,0 +1,34 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 Radomir Dopieralski + * + * 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__STAGE_TEXT_H +#define MICROPY_INCLUDED__STAGE_TEXT_H + +#include "shared-module/_stage/Text.h" + +extern const mp_obj_type_t mp_type_text; + +#endif // MICROPY_INCLUDED__STAGE_TEXT diff --git a/shared-bindings/_stage/__init__.c b/shared-bindings/_stage/__init__.c new file mode 100644 index 0000000000..16e0b58d94 --- /dev/null +++ b/shared-bindings/_stage/__init__.c @@ -0,0 +1,97 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 Radomir Dopieralski + * + * 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 "__init__.h" +#include "py/mperrno.h" +#include "py/runtime.h" +#include "shared-bindings/busio/SPI.h" +#include "shared-module/_stage/__init__.h" +#include "Layer.h" +#include "Text.h" + +//| .. currentmodule:: _stage +//| +//| .. function:: render(x0, y0, x1, y1, layers, buffer, spi) +//| +//| Render and send to the display a fragment of the screen. +//| +//| :param int x0: Left edge of the fragment. +//| :param int y0: Top edge of the fragment. +//| :param int x1: Right edge of the fragment. +//| :param int y1: Bottom edge of the fragment. +//| :param list layers: A list of the `Layer` objects. +//| :param bytearray buffer: A buffer to use for rendering. +//| :param SPI spi: The SPI device to use. +//| +//| Note that this function only sends the raw pixel data. Setting up +//| the display for receiving it and handling the chip-select and +//| data-command pins has to be done outside of it. +//| There are also no sanity checks, outside of the basic overflow +//| checking. The caller is responsible for making the passed parameters +//| valid. +//| +//| This function is intended for internal use in the ``stage`` library +//| and all the necessary checks are performed there. +STATIC mp_obj_t stage_render(size_t n_args, const mp_obj_t *args) { + uint8_t x0 = mp_obj_get_int(args[0]); + uint8_t y0 = mp_obj_get_int(args[1]); + uint8_t x1 = mp_obj_get_int(args[2]); + uint8_t y1 = mp_obj_get_int(args[3]); + + size_t layers_size = 0; + mp_obj_t *layers; + mp_obj_get_array(args[4], &layers_size, &layers); + + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(args[5], &bufinfo, MP_BUFFER_WRITE); + uint16_t *buffer = bufinfo.buf; + size_t buffer_size = bufinfo.len / 2; // 16-bit indexing + + busio_spi_obj_t *spi = MP_OBJ_TO_PTR(args[6]); + + if (!render_stage(x0, y0, x1, y1, layers, layers_size, + buffer, buffer_size, spi)) { + mp_raise_OSError(MP_EIO); + } + + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(stage_render_obj, 7, 7, stage_render); + + +STATIC const mp_rom_map_elem_t stage_module_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR__stage) }, + { MP_ROM_QSTR(MP_QSTR_Layer), MP_ROM_PTR(&mp_type_layer) }, + { MP_ROM_QSTR(MP_QSTR_Text), MP_ROM_PTR(&mp_type_text) }, + { MP_ROM_QSTR(MP_QSTR_render), MP_ROM_PTR(&stage_render_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(stage_module_globals, stage_module_globals_table); + +const mp_obj_module_t stage_module = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&stage_module_globals, +}; diff --git a/shared-bindings/_stage/__init__.h b/shared-bindings/_stage/__init__.h new file mode 100644 index 0000000000..2df81cb3b2 --- /dev/null +++ b/shared-bindings/_stage/__init__.h @@ -0,0 +1,32 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 Radomir Dopieralski + * + * 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__STAGE_H +#define MICROPY_INCLUDED__STAGE_H + +#include "shared-module/_stage/__init__.h" + +#endif // MICROPY_INCLUDED__STAGE diff --git a/shared-bindings/audiobusio/PDMIn.c b/shared-bindings/audiobusio/PDMIn.c index b43adecba3..f273c7a3d5 100644 --- a/shared-bindings/audiobusio/PDMIn.c +++ b/shared-bindings/audiobusio/PDMIn.c @@ -28,6 +28,7 @@ #include "lib/utils/context_manager_helpers.h" #include "py/binary.h" +#include "py/mphal.h" #include "py/objproperty.h" #include "py/runtime.h" #include "shared-bindings/microcontroller/Pin.h" @@ -41,7 +42,7 @@ //| //| PDMIn can be used to record an input audio signal on a given set of pins. //| -//| .. class:: PDMIn(clock_pin, data_pin, \*, frequency=8000, bit_depth=8, mono=True, oversample=64) +//| .. class:: PDMIn(clock_pin, data_pin, \*, frequency=16000, bit_depth=8, mono=True, oversample=64, startup_delay=0.11) //| //| Create a PDMIn object associated with the given pins. This allows you to //| record audio signals from the given pins. Individual ports may put further @@ -51,11 +52,16 @@ //| //| :param ~microcontroller.Pin clock_pin: The pin to output the clock to //| :param ~microcontroller.Pin data_pin: The pin to read the data from -//| :param int frequency: Target frequency in Hz of the resulting samples. Check `frequency` for real value +//| :param int frequency: Target frequency of the resulting samples. Check `frequency` for actual value. +//| Minimum frequency is about 16000 Hz. //| :param int bit_depth: Final number of bits per sample. Must be divisible by 8 //| :param bool mono: True when capturing a single channel of audio, captures two channels otherwise //| :param int oversample: Number of single bit samples to decimate into a final sample. Must be divisible by 8 +//| :param float startup_delay: seconds to wait after starting microphone clock +//| to allow microphone to turn on. Most require only 0.01s; some require 0.1s. Longer is safer. +//| Must be in range 0.0-1.0 seconds. //| + //| Record 8-bit unsigned samples to buffer:: //| //| import audiobusio @@ -81,15 +87,19 @@ //| mic.record(b, len(b)) //| STATIC mp_obj_t audiobusio_pdmin_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *pos_args) { - enum { ARG_frequency, ARG_bit_depth, ARG_mono, ARG_oversample }; + enum { ARG_frequency, ARG_bit_depth, ARG_mono, ARG_oversample, ARG_startup_delay }; mp_map_t kw_args; mp_map_init_fixed_table(&kw_args, n_kw, pos_args + n_args); static const mp_arg_t allowed_args[] = { - { MP_QSTR_frequency, MP_ARG_INT, {.u_int = 8000} }, - { MP_QSTR_bit_depth, MP_ARG_INT, {.u_int = 8} }, - { MP_QSTR_mono, MP_ARG_BOOL,{.u_bool = true} }, - { MP_QSTR_oversample, MP_ARG_INT, {.u_int = 64} }, + { MP_QSTR_frequency, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 16000} }, + { MP_QSTR_bit_depth, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 8} }, + { MP_QSTR_mono, MP_ARG_KW_ONLY | MP_ARG_BOOL,{.u_bool = true} }, + { MP_QSTR_oversample, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 64} }, + { MP_QSTR_startup_delay, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, }; + // Default microphone startup delay is 110msecs. Have seen mics that need 100 msecs plus a bit. + static const float STARTUP_DELAY_DEFAULT = 0.110F; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; mp_arg_parse_all(n_args - 2, pos_args + 2, &kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); @@ -118,8 +128,18 @@ STATIC mp_obj_t audiobusio_pdmin_make_new(const mp_obj_type_t *type, size_t n_ar } bool mono = args[ARG_mono].u_bool; + float startup_delay = (args[ARG_startup_delay].u_obj == MP_OBJ_NULL) + ? STARTUP_DELAY_DEFAULT + : mp_obj_get_float(args[ARG_startup_delay].u_obj); + if (startup_delay < 0.0 || startup_delay > 1.0) { + mp_raise_ValueError("Microphone startup delay must be in range 0.0 to 1.0"); + } + common_hal_audiobusio_pdmin_construct(self, clock_pin, data_pin, frequency, - bit_depth, mono, oversample); + bit_depth, mono, oversample); + + // Wait for the microphone to start up. Some start in 10 msecs; some take as much as 100 msecs. + mp_hal_delay_ms(startup_delay * 1000); return MP_OBJ_FROM_PTR(self); } @@ -162,11 +182,14 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(audiobusio_pdmin___exit___obj, 4, 4, //| audio at the given rate. For internal flash, writing all 1s to the file //| before recording is recommended to speed up writes. //| +//| :return: The number of samples recorded. If this is less than `destination_length`, +//| some samples were missed due to processing time. +//| STATIC mp_obj_t audiobusio_pdmin_obj_record(mp_obj_t self_obj, mp_obj_t destination, mp_obj_t destination_length) { audiobusio_pdmin_obj_t *self = MP_OBJ_TO_PTR(self_obj); raise_error_if_deinited(common_hal_audiobusio_pdmin_deinited(self)); - if (!MP_OBJ_IS_SMALL_INT(destination_length)) { - mp_raise_TypeError("destination_length must be int"); + if (!MP_OBJ_IS_SMALL_INT(destination_length) || MP_OBJ_SMALL_INT_VALUE(destination_length) < 0) { + mp_raise_TypeError("destination_length must be an int >= 0"); } uint32_t length = MP_OBJ_SMALL_INT_VALUE(destination_length); @@ -174,8 +197,8 @@ STATIC mp_obj_t audiobusio_pdmin_obj_record(mp_obj_t self_obj, mp_obj_t destinat if (MP_OBJ_IS_TYPE(destination, &fatfs_type_fileio)) { mp_raise_NotImplementedError(""); } else if (mp_get_buffer(destination, &bufinfo, MP_BUFFER_WRITE)) { - if (bufinfo.len < length) { - mp_raise_ValueError("Target buffer cannot hold destination_length bytes."); + if (bufinfo.len / mp_binary_get_size('@', bufinfo.typecode, NULL) < length) { + mp_raise_ValueError("Destination capacity is smaller than destination_length."); } uint8_t bit_depth = common_hal_audiobusio_pdmin_get_bit_depth(self); if (bufinfo.typecode != 'H' && bit_depth == 16) { @@ -183,12 +206,10 @@ STATIC mp_obj_t audiobusio_pdmin_obj_record(mp_obj_t self_obj, mp_obj_t destinat } else if (bufinfo.typecode != 'B' && bufinfo.typecode != BYTEARRAY_TYPECODE && bit_depth == 8) { mp_raise_ValueError("destination buffer must be a bytearray or array of type 'B' for bit_depth = 8"); } - length *= bit_depth / 8; + // length is the buffer length in slots, not bytes. uint32_t length_written = common_hal_audiobusio_pdmin_record_to_buffer(self, bufinfo.buf, length); - if (length_written != length) { - mp_printf(&mp_plat_print, "length mismatch %d %d\n", length_written, length); - } + return MP_OBJ_NEW_SMALL_INT(length_written); } return mp_const_none; } diff --git a/shared-bindings/bitbangio/I2C.c b/shared-bindings/bitbangio/I2C.c index 80718090ab..f8f60210e6 100644 --- a/shared-bindings/bitbangio/I2C.c +++ b/shared-bindings/bitbangio/I2C.c @@ -157,6 +157,7 @@ MP_DEFINE_CONST_FUN_OBJ_1(bitbangio_i2c_unlock_obj, bitbangio_i2c_obj_unlock); //| //| Read into ``buffer`` from the slave specified by ``address``. //| The number of bytes read will be the length of ``buffer``. +//| At least one byte must be read. //| //| If ``start`` or ``end`` is provided, then the buffer will be sliced //| as if ``buffer[start:end]``. This will not cause an allocation like @@ -186,6 +187,9 @@ STATIC mp_obj_t bitbangio_i2c_readfrom_into(size_t n_args, const mp_obj_t *pos_a int32_t start = args[ARG_start].u_int; uint32_t length = bufinfo.len; normalize_buffer_bounds(&start, args[ARG_end].u_int, &length); + if (length == 0) { + mp_raise_ValueError("Buffer must be at least length 1"); + } uint8_t status = shared_module_bitbangio_i2c_read(self, args[ARG_address].u_int, ((uint8_t*)bufinfo.buf) + start, @@ -206,6 +210,9 @@ MP_DEFINE_CONST_FUN_OBJ_KW(bitbangio_i2c_readfrom_into_obj, 3, bitbangio_i2c_rea //| as if ``buffer[start:end]``. This will not cause an allocation like //| ``buffer[start:end]`` will so it saves memory. //| +//| Writing a buffer or slice of length zero is permitted, as it can be used +//| to poll for the existence of a device. +//| //| :param int address: 7-bit device address //| :param bytearray buffer: buffer containing the bytes to write //| :param int start: Index to start writing from diff --git a/shared-bindings/bitbangio/SPI.c b/shared-bindings/bitbangio/SPI.c index 6c7bac3e51..5442b9ea26 100644 --- a/shared-bindings/bitbangio/SPI.c +++ b/shared-bindings/bitbangio/SPI.c @@ -191,6 +191,7 @@ MP_DEFINE_CONST_FUN_OBJ_1(bitbangio_spi_unlock_obj, bitbangio_spi_obj_unlock); //| .. method:: SPI.write(buf) //| //| Write the data contained in ``buf``. Requires the SPI being locked. +//| If the buffer is empty, nothing happens. //| // TODO(tannewt): Add support for start and end kwargs. STATIC mp_obj_t bitbangio_spi_write(mp_obj_t self_in, mp_obj_t wr_buf) { @@ -198,6 +199,9 @@ STATIC mp_obj_t bitbangio_spi_write(mp_obj_t self_in, mp_obj_t wr_buf) { raise_error_if_deinited(shared_module_bitbangio_spi_deinited(self)); mp_buffer_info_t src; mp_get_buffer_raise(wr_buf, &src, MP_BUFFER_READ); + if (src.len == 0) { + return mp_const_none; + } check_lock(self); bool ok = shared_module_bitbangio_spi_write(self, src.buf, src.len); if (!ok) { @@ -210,7 +214,9 @@ MP_DEFINE_CONST_FUN_OBJ_2(bitbangio_spi_write_obj, bitbangio_spi_write); //| .. method:: SPI.readinto(buf) //| -//| Read into the buffer specified by ``buf`` while writing zeroes. Requires the SPI being locked. +//| Read into the buffer specified by ``buf`` while writing zeroes. +//| Requires the SPI being locked. +//| If the number of bytes to read is 0, nothing happens. //| // TODO(tannewt): Add support for start and end kwargs. STATIC mp_obj_t bitbangio_spi_readinto(size_t n_args, const mp_obj_t *args) { @@ -218,6 +224,9 @@ STATIC mp_obj_t bitbangio_spi_readinto(size_t n_args, const mp_obj_t *args) { raise_error_if_deinited(shared_module_bitbangio_spi_deinited(self)); mp_buffer_info_t bufinfo; mp_get_buffer_raise(args[1], &bufinfo, MP_BUFFER_WRITE); + if (bufinfo.len == 0) { + return mp_const_none; + } check_lock(args[0]); bool ok = shared_module_bitbangio_spi_read(self, bufinfo.buf, bufinfo.len); if (!ok) { diff --git a/shared-bindings/busio/I2C.c b/shared-bindings/busio/I2C.c index cdc960f803..b0954d6c8a 100644 --- a/shared-bindings/busio/I2C.c +++ b/shared-bindings/busio/I2C.c @@ -171,6 +171,7 @@ MP_DEFINE_CONST_FUN_OBJ_1(busio_i2c_unlock_obj, busio_i2c_obj_unlock); //| //| Read into ``buffer`` from the slave specified by ``address``. //| The number of bytes read will be the length of ``buffer``. +//| At least one byte must be read. //| //| If ``start`` or ``end`` is provided, then the buffer will be sliced //| as if ``buffer[start:end]``. This will not cause an allocation like @@ -201,6 +202,10 @@ STATIC mp_obj_t busio_i2c_readfrom_into(size_t n_args, const mp_obj_t *pos_args, int32_t start = args[ARG_start].u_int; uint32_t length = bufinfo.len; normalize_buffer_bounds(&start, args[ARG_end].u_int, &length); + if (length == 0) { + mp_raise_ValueError("Buffer must be at least length 1"); + } + uint8_t status = common_hal_busio_i2c_read(self, args[ARG_address].u_int, ((uint8_t*)bufinfo.buf) + start, length); if (status != 0) { mp_raise_OSError(status); @@ -219,6 +224,9 @@ MP_DEFINE_CONST_FUN_OBJ_KW(busio_i2c_readfrom_into_obj, 3, busio_i2c_readfrom_in //| as if ``buffer[start:end]``. This will not cause an allocation like //| ``buffer[start:end]`` will so it saves memory. //| +//| Writing a buffer or slice of length zero is permitted, as it can be used +//| to poll for the existence of a device. +//| //| :param int address: 7-bit device address //| :param bytearray buffer: buffer containing the bytes to write //| :param int start: Index to start writing from diff --git a/shared-bindings/busio/SPI.c b/shared-bindings/busio/SPI.c index 12f888f23d..c4c139105f 100644 --- a/shared-bindings/busio/SPI.c +++ b/shared-bindings/busio/SPI.c @@ -206,11 +206,12 @@ MP_DEFINE_CONST_FUN_OBJ_1(busio_spi_unlock_obj, busio_spi_obj_unlock); //| .. method:: SPI.write(buffer, \*, start=0, end=len(buffer)) //| -//| Write the data contained in ``buf``. Requires the SPI being locked. +//| Write the data contained in ``buffer``. The SPI object must be locked. +//| If the buffer is empty, nothing happens. //| -//| :param bytearray buffer: buffer containing the bytes to write -//| :param int start: Index to start writing from -//| :param int end: Index to read up to but not include +//| :param bytearray buffer: Write out the data in this buffer +//| :param int start: Start of the slice of ``buffer`` to write out: ``buffer[start:end]`` +//| :param int end: End of the slice; this index is not included //| STATIC mp_obj_t busio_spi_write(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { enum { ARG_buffer, ARG_start, ARG_end }; @@ -231,6 +232,10 @@ STATIC mp_obj_t busio_spi_write(size_t n_args, const mp_obj_t *pos_args, mp_map_ uint32_t length = bufinfo.len; normalize_buffer_bounds(&start, args[ARG_end].u_int, &length); + if (length == 0) { + return mp_const_none; + } + bool ok = common_hal_busio_spi_write(self, ((uint8_t*)bufinfo.buf) + start, length); if (!ok) { mp_raise_OSError(MP_EIO); @@ -242,12 +247,14 @@ MP_DEFINE_CONST_FUN_OBJ_KW(busio_spi_write_obj, 2, busio_spi_write); //| .. method:: SPI.readinto(buffer, \*, start=0, end=len(buffer), write_value=0) //| -//| Read into the buffer specified by ``buf`` while writing zeroes. Requires the SPI being locked. +//| Read into ``buffer`` while writing ``write_value`` for each byte read. +//| The SPI object must be locked. +//| If the number of bytes to read is 0, nothing happens. //| -//| :param bytearray buffer: buffer to write into -//| :param int start: Index to start writing at -//| :param int end: Index to write up to but not include -//| :param int write_value: Value to write reading. (Usually ignored.) +//| :param bytearray buffer: Read data into this buffer +//| :param int start: Start of the slice of ``buffer`` to read into: ``buffer[start:end]`` +//| :param int end: End of the slice; this index is not included +//| :param int write_value: Value to write while reading. (Usually ignored.) //| STATIC mp_obj_t busio_spi_readinto(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { enum { ARG_buffer, ARG_start, ARG_end, ARG_write_value }; @@ -269,6 +276,10 @@ STATIC mp_obj_t busio_spi_readinto(size_t n_args, const mp_obj_t *pos_args, mp_m uint32_t length = bufinfo.len; normalize_buffer_bounds(&start, args[ARG_end].u_int, &length); + if (length == 0) { + return mp_const_none; + } + bool ok = common_hal_busio_spi_read(self, ((uint8_t*)bufinfo.buf) + start, length, args[ARG_write_value].u_int); if (!ok) { mp_raise_OSError(MP_EIO); @@ -277,6 +288,68 @@ STATIC mp_obj_t busio_spi_readinto(size_t n_args, const mp_obj_t *pos_args, mp_m } MP_DEFINE_CONST_FUN_OBJ_KW(busio_spi_readinto_obj, 2, busio_spi_readinto); +//| .. method:: SPI.write_readinto(buffer_out, buffer_in, \*, out_start=0, out_end=len(buffer_out), in_start=0, in_end=len(buffer_in)) +//| +//| Write out the data in ``buffer_out`` while simultaneously reading data into ``buffer_in``. +//| The SPI object must be locked. +//| The lengths of the slices defined by ``buffer_out[out_start:out_end]`` and ``buffer_in[in_start:in_end]`` +//| must be equal. +//| If buffer slice lengths are both 0, nothing happens. +//| +//| :param bytearray buffer_out: Write out the data in this buffer +//| :param bytearray buffer_in: Read data into this buffer +//| :param int out_start: Start of the slice of buffer_out to write out: ``buffer_out[out_start:out_end]`` +//| :param int out_end: End of the slice; this index is not included +//| :param int in_start: Start of the slice of ``buffer_in`` to read into: ``buffer_in[in_start:in_end]`` +//| :param int in_end: End of the slice; this index is not included +//| +STATIC mp_obj_t busio_spi_write_readinto(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_buffer_out, ARG_buffer_in, ARG_out_start, ARG_out_end, ARG_in_start, ARG_in_end }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_buffer_out, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_buffer_in, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_out_start, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_out_end, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = INT_MAX} }, + { MP_QSTR_in_start, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_in_end, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = INT_MAX} }, + }; + busio_spi_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); + raise_error_if_deinited(common_hal_busio_spi_deinited(self)); + check_lock(self); + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + mp_buffer_info_t buf_out_info; + mp_get_buffer_raise(args[ARG_buffer_out].u_obj, &buf_out_info, MP_BUFFER_READ); + int32_t out_start = args[ARG_out_start].u_int; + uint32_t out_length = buf_out_info.len; + normalize_buffer_bounds(&out_start, args[ARG_out_end].u_int, &out_length); + + mp_buffer_info_t buf_in_info; + mp_get_buffer_raise(args[ARG_buffer_in].u_obj, &buf_in_info, MP_BUFFER_WRITE); + int32_t in_start = args[ARG_in_start].u_int; + uint32_t in_length = buf_in_info.len; + normalize_buffer_bounds(&in_start, args[ARG_in_end].u_int, &in_length); + + if (out_length != in_length) { + mp_raise_ValueError("buffer slices must be of equal length"); + } + + if (out_length == 0) { + return mp_const_none; + } + + bool ok = common_hal_busio_spi_transfer(self, + ((uint8_t*)buf_out_info.buf) + out_start, + ((uint8_t*)buf_in_info.buf) + in_start, + out_length); + if (!ok) { + mp_raise_OSError(MP_EIO); + } + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_KW(busio_spi_write_readinto_obj, 2, busio_spi_write_readinto); + STATIC const mp_rom_map_elem_t busio_spi_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&busio_spi_deinit_obj) }, { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) }, @@ -288,6 +361,7 @@ STATIC const mp_rom_map_elem_t busio_spi_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&busio_spi_readinto_obj) }, { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&busio_spi_write_obj) }, + { MP_ROM_QSTR(MP_QSTR_write_readinto), MP_ROM_PTR(&busio_spi_write_readinto_obj) }, }; STATIC MP_DEFINE_CONST_DICT(busio_spi_locals_dict, busio_spi_locals_dict_table); diff --git a/shared-bindings/busio/SPI.h b/shared-bindings/busio/SPI.h index ac31d5060d..b6e5c9b1b3 100644 --- a/shared-bindings/busio/SPI.h +++ b/shared-bindings/busio/SPI.h @@ -55,4 +55,7 @@ extern bool common_hal_busio_spi_write(busio_spi_obj_t *self, const uint8_t *dat // Reads in len bytes while outputting zeroes. extern bool common_hal_busio_spi_read(busio_spi_obj_t *self, uint8_t *data, size_t len, uint8_t write_value); +// Reads and write len bytes simultaneously. +extern bool common_hal_busio_spi_transfer(busio_spi_obj_t *self, uint8_t *data_out, uint8_t *data_in, size_t len); + #endif // MICROPY_INCLUDED_SHARED_BINDINGS_BUSIO_SPI_H diff --git a/shared-bindings/digitalio/DigitalInOut.c b/shared-bindings/digitalio/DigitalInOut.c index ea2ba0b893..008883b8bd 100644 --- a/shared-bindings/digitalio/DigitalInOut.c +++ b/shared-bindings/digitalio/DigitalInOut.c @@ -124,7 +124,7 @@ STATIC mp_obj_t digitalio_digitalinout_switch_to_output(size_t n_args, const mp_ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - enum digitalio_drive_mode_t drive_mode = DRIVE_MODE_PUSH_PULL; + digitalio_drive_mode_t drive_mode = DRIVE_MODE_PUSH_PULL; if (args[ARG_drive_mode].u_rom_obj == &digitalio_drive_mode_open_drain_obj) { drive_mode = DRIVE_MODE_OPEN_DRAIN; } @@ -161,7 +161,7 @@ STATIC mp_obj_t digitalio_digitalinout_switch_to_input(size_t n_args, const mp_o mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - enum digitalio_pull_t pull = PULL_NONE; + digitalio_pull_t pull = PULL_NONE; if (args[ARG_pull].u_rom_obj == &digitalio_pull_up_obj) { pull = PULL_UP; }else if (args[ARG_pull].u_rom_obj == &digitalio_pull_down_obj) { @@ -191,7 +191,7 @@ extern const digitalio_digitalio_direction_obj_t digitalio_digitalio_direction_o STATIC mp_obj_t digitalio_digitalinout_obj_get_direction(mp_obj_t self_in) { digitalio_digitalinout_obj_t *self = MP_OBJ_TO_PTR(self_in); raise_error_if_deinited(common_hal_digitalio_digitalinout_deinited(self)); - enum digitalio_direction_t direction = common_hal_digitalio_digitalinout_get_direction(self); + digitalio_direction_t direction = common_hal_digitalio_digitalinout_get_direction(self); if (direction == DIRECTION_INPUT) { return (mp_obj_t)&digitalio_direction_input_obj; } @@ -262,7 +262,7 @@ STATIC mp_obj_t digitalio_digitalinout_obj_get_drive_mode(mp_obj_t self_in) { mp_raise_AttributeError("Drive mode not used when direction is input."); return mp_const_none; } - enum digitalio_drive_mode_t drive_mode = common_hal_digitalio_digitalinout_get_drive_mode(self); + digitalio_drive_mode_t drive_mode = common_hal_digitalio_digitalinout_get_drive_mode(self); if (drive_mode == DRIVE_MODE_PUSH_PULL) { return (mp_obj_t)&digitalio_drive_mode_push_pull_obj; } @@ -277,7 +277,7 @@ STATIC mp_obj_t digitalio_digitalinout_obj_set_drive_mode(mp_obj_t self_in, mp_o mp_raise_AttributeError("Drive mode not used when direction is input."); return mp_const_none; } - enum digitalio_drive_mode_t c_drive_mode = DRIVE_MODE_PUSH_PULL; + digitalio_drive_mode_t c_drive_mode = DRIVE_MODE_PUSH_PULL; if (drive_mode == &digitalio_drive_mode_open_drain_obj) { c_drive_mode = DRIVE_MODE_OPEN_DRAIN; } @@ -307,7 +307,7 @@ STATIC mp_obj_t digitalio_digitalinout_obj_get_pull(mp_obj_t self_in) { mp_raise_AttributeError("Pull not used when direction is output."); return mp_const_none; } - enum digitalio_pull_t pull = common_hal_digitalio_digitalinout_get_pull(self); + digitalio_pull_t pull = common_hal_digitalio_digitalinout_get_pull(self); if (pull == PULL_UP) { return (mp_obj_t)&digitalio_pull_up_obj; } else if (pull == PULL_DOWN) { @@ -324,7 +324,7 @@ STATIC mp_obj_t digitalio_digitalinout_obj_set_pull(mp_obj_t self_in, mp_obj_t p mp_raise_AttributeError("Pull not used when direction is output."); return mp_const_none; } - enum digitalio_pull_t pull = PULL_NONE; + digitalio_pull_t pull = PULL_NONE; if (pull_obj == &digitalio_pull_up_obj) { pull = PULL_UP; } else if (pull_obj == &digitalio_pull_down_obj) { diff --git a/shared-bindings/digitalio/DigitalInOut.h b/shared-bindings/digitalio/DigitalInOut.h index 74970881b8..2aaa31b7f4 100644 --- a/shared-bindings/digitalio/DigitalInOut.h +++ b/shared-bindings/digitalio/DigitalInOut.h @@ -43,14 +43,14 @@ typedef enum { digitalinout_result_t common_hal_digitalio_digitalinout_construct(digitalio_digitalinout_obj_t* self, const mcu_pin_obj_t* pin); void common_hal_digitalio_digitalinout_deinit(digitalio_digitalinout_obj_t* self); bool common_hal_digitalio_digitalinout_deinited(digitalio_digitalinout_obj_t* self); -void common_hal_digitalio_digitalinout_switch_to_input(digitalio_digitalinout_obj_t* self, enum digitalio_pull_t pull); -void common_hal_digitalio_digitalinout_switch_to_output(digitalio_digitalinout_obj_t* self, bool value, enum digitalio_drive_mode_t drive_mode); -enum digitalio_direction_t common_hal_digitalio_digitalinout_get_direction(digitalio_digitalinout_obj_t* self); +void common_hal_digitalio_digitalinout_switch_to_input(digitalio_digitalinout_obj_t* self, digitalio_pull_t pull); +void common_hal_digitalio_digitalinout_switch_to_output(digitalio_digitalinout_obj_t* self, bool value, digitalio_drive_mode_t drive_mode); +digitalio_direction_t common_hal_digitalio_digitalinout_get_direction(digitalio_digitalinout_obj_t* self); void common_hal_digitalio_digitalinout_set_value(digitalio_digitalinout_obj_t* self, bool value); bool common_hal_digitalio_digitalinout_get_value(digitalio_digitalinout_obj_t* self); -void common_hal_digitalio_digitalinout_set_drive_mode(digitalio_digitalinout_obj_t* self, enum digitalio_drive_mode_t drive_mode); -enum digitalio_drive_mode_t common_hal_digitalio_digitalinout_get_drive_mode(digitalio_digitalinout_obj_t* self); -void common_hal_digitalio_digitalinout_set_pull(digitalio_digitalinout_obj_t* self, enum digitalio_pull_t pull); -enum digitalio_pull_t common_hal_digitalio_digitalinout_get_pull(digitalio_digitalinout_obj_t* self); +void common_hal_digitalio_digitalinout_set_drive_mode(digitalio_digitalinout_obj_t* self, digitalio_drive_mode_t drive_mode); +digitalio_drive_mode_t common_hal_digitalio_digitalinout_get_drive_mode(digitalio_digitalinout_obj_t* self); +void common_hal_digitalio_digitalinout_set_pull(digitalio_digitalinout_obj_t* self, digitalio_pull_t pull); +digitalio_pull_t common_hal_digitalio_digitalinout_get_pull(digitalio_digitalinout_obj_t* self); #endif // MICROPY_INCLUDED_SHARED_BINDINGS_DIGITALIO_DIGITALINOUT_H diff --git a/shared-bindings/digitalio/Direction.h b/shared-bindings/digitalio/Direction.h index e8fbf181d2..d71f48c2ed 100644 --- a/shared-bindings/digitalio/Direction.h +++ b/shared-bindings/digitalio/Direction.h @@ -29,10 +29,10 @@ #include "py/obj.h" -enum digitalio_direction_t { +typedef enum { DIRECTION_INPUT, DIRECTION_OUTPUT -}; +} digitalio_direction_t; typedef struct { mp_obj_base_t base; } digitalio_direction_obj_t; diff --git a/shared-bindings/digitalio/DriveMode.h b/shared-bindings/digitalio/DriveMode.h index 959885b1b9..47d036b3ae 100644 --- a/shared-bindings/digitalio/DriveMode.h +++ b/shared-bindings/digitalio/DriveMode.h @@ -29,10 +29,10 @@ #include "py/obj.h" -enum digitalio_drive_mode_t { +typedef enum { DRIVE_MODE_PUSH_PULL, DRIVE_MODE_OPEN_DRAIN -}; +} digitalio_drive_mode_t; typedef struct { mp_obj_base_t base; diff --git a/shared-bindings/digitalio/Pull.h b/shared-bindings/digitalio/Pull.h index 8c88d8673e..22fb6cd0e7 100644 --- a/shared-bindings/digitalio/Pull.h +++ b/shared-bindings/digitalio/Pull.h @@ -29,11 +29,11 @@ #include "py/obj.h" -enum digitalio_pull_t { +typedef enum _digitalio_pull_t { PULL_NONE, PULL_UP, PULL_DOWN -}; +} digitalio_pull_t; const mp_obj_type_t digitalio_pull_type; diff --git a/shared-bindings/microcontroller/RunMode.c b/shared-bindings/microcontroller/RunMode.c new file mode 100644 index 0000000000..b27a3c0909 --- /dev/null +++ b/shared-bindings/microcontroller/RunMode.c @@ -0,0 +1,90 @@ +/* + * This file is part of the Micro Python project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 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/RunMode.h" + +//| .. currentmodule:: microcontroller +//| +//| :class:`RunMode` -- run state of the microcontroller +//| ============================================================= +//| +//| .. class:: microcontroller.RunMode +//| +//| Enum-like class to define the run mode of the microcontroller and +//| CircuitPython. +//| +//| .. data:: NORMAL +//| +//| Run CircuitPython as normal. +//| +//| .. data:: SAFE_MODE +//| +//| Run CircuitPython in safe mode. User code will not be run and the +//| file system will be writeable over USB. +//| +//| .. data:: BOOTLOADER +//| +//| Run the bootloader. +//| +const mp_obj_type_t mcu_runmode_type; + +const mcu_runmode_obj_t mcu_runmode_normal_obj = { + { &mcu_runmode_type }, +}; + +const mcu_runmode_obj_t mcu_runmode_safe_mode_obj = { + { &mcu_runmode_type }, +}; + +const mcu_runmode_obj_t mcu_runmode_bootloader_obj = { + { &mcu_runmode_type }, +}; + +STATIC const mp_rom_map_elem_t mcu_runmode_locals_dict_table[] = { + {MP_ROM_QSTR(MP_QSTR_NORMAL), MP_ROM_PTR(&mcu_runmode_normal_obj)}, + {MP_ROM_QSTR(MP_QSTR_SAFE_MODE), MP_ROM_PTR(&mcu_runmode_safe_mode_obj)}, + {MP_ROM_QSTR(MP_QSTR_BOOTLOADER), MP_ROM_PTR(&mcu_runmode_bootloader_obj)}, +}; +STATIC MP_DEFINE_CONST_DICT(mcu_runmode_locals_dict, mcu_runmode_locals_dict_table); + +STATIC void mcu_runmode_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + qstr runmode = MP_QSTR_NORMAL; + if (MP_OBJ_TO_PTR(self_in) == MP_ROM_PTR(&mcu_runmode_safe_mode_obj)) { + runmode = MP_QSTR_SAFE_MODE; + } else if (MP_OBJ_TO_PTR(self_in) == + MP_ROM_PTR(&mcu_runmode_bootloader_obj)) { + runmode = MP_QSTR_SAFE_MODE; + } + mp_printf(print, "%q.%q.%q", MP_QSTR_microcontroller, MP_QSTR_RunMode, + runmode); +} + +const mp_obj_type_t mcu_runmode_type = { + { &mp_type_type }, + .name = MP_QSTR_RunMode, + .print = mcu_runmode_print, + .locals_dict = (mp_obj_t)&mcu_runmode_locals_dict, +}; diff --git a/shared-bindings/microcontroller/RunMode.h b/shared-bindings/microcontroller/RunMode.h new file mode 100644 index 0000000000..5e8b6e6465 --- /dev/null +++ b/shared-bindings/microcontroller/RunMode.h @@ -0,0 +1,47 @@ +/* + * This file is part of the Micro Python project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 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_SHARED_BINDINGS_MICROCONTROLLER_RUNMODE_H +#define MICROPY_INCLUDED_SHARED_BINDINGS_MICROCONTROLLER_RUNMODE_H + +#include "py/obj.h" + +typedef enum { + RUNMODE_NORMAL, + RUNMODE_SAFE_MODE, + RUNMODE_BOOTLOADER +} mcu_runmode_t; + +const mp_obj_type_t mcu_runmode_type; + +typedef struct { + mp_obj_base_t base; +} mcu_runmode_obj_t; +extern const mcu_runmode_obj_t mcu_runmode_normal_obj; +extern const mcu_runmode_obj_t mcu_runmode_safe_mode_obj; +extern const mcu_runmode_obj_t mcu_runmode_bootloader_obj; + +#endif // MICROPY_INCLUDED_SHARED_BINDINGS_MICROCONTROLLER_RUNMODE_H diff --git a/shared-bindings/microcontroller/__init__.c b/shared-bindings/microcontroller/__init__.c index 58ed876c27..f261178f0e 100644 --- a/shared-bindings/microcontroller/__init__.c +++ b/shared-bindings/microcontroller/__init__.c @@ -106,6 +106,47 @@ STATIC mp_obj_t mcu_enable_interrupts(void) { } STATIC MP_DEFINE_CONST_FUN_OBJ_0(mcu_enable_interrupts_obj, mcu_enable_interrupts); +//| .. method:: on_next_reset(run_mode) +//| +//| Configure the run mode used the next time the microcontroller is reset but +//| not powered down. +//| +//| :param ~microcontroller.RunMode run_mode: The next run mode +//| +STATIC mp_obj_t mcu_on_next_reset(mp_obj_t run_mode_obj) { + mcu_runmode_t run_mode; + if (run_mode_obj == &mcu_runmode_normal_obj) { + run_mode = RUNMODE_NORMAL; + } else if (run_mode_obj == &mcu_runmode_safe_mode_obj) { + run_mode = RUNMODE_SAFE_MODE; + } else if (run_mode_obj == &mcu_runmode_bootloader_obj) { + run_mode = RUNMODE_BOOTLOADER; + } else { + mp_raise_ValueError("Invalid run mode."); + } + + common_hal_mcu_on_next_reset(run_mode); + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(mcu_on_next_reset_obj, mcu_on_next_reset); + +//| .. method:: reset() +//| +//| Reset the microcontroller. After reset, the microcontroller will enter the +//| run mode last set by `one_next_reset`. +//| +//| .. warning:: This may result in file system corruption when connected to a +//| host computer. Be very careful when calling this! Make sure the device +//| "Safely removed" on Windows or "ejected" on Mac OSX and Linux. +//| +STATIC mp_obj_t mcu_reset(void) { + common_hal_mcu_reset(); + // We won't actually get here because we're resetting. + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(mcu_reset_obj, mcu_reset); + //| .. attribute:: nvm //| //| Available non-volatile memory. @@ -132,11 +173,14 @@ STATIC const mp_rom_map_elem_t mcu_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_delay_us), MP_ROM_PTR(&mcu_delay_us_obj) }, { MP_ROM_QSTR(MP_QSTR_disable_interrupts), MP_ROM_PTR(&mcu_disable_interrupts_obj) }, { MP_ROM_QSTR(MP_QSTR_enable_interrupts), MP_ROM_PTR(&mcu_enable_interrupts_obj) }, + { MP_ROM_QSTR(MP_QSTR_on_next_reset), MP_ROM_PTR(&mcu_on_next_reset_obj) }, + { MP_ROM_QSTR(MP_QSTR_reset), MP_ROM_PTR(&mcu_reset_obj) }, #if CIRCUITPY_INTERNAL_NVM_SIZE > 0 { MP_ROM_QSTR(MP_QSTR_nvm), MP_ROM_PTR(&common_hal_mcu_nvm_obj) }, #else { MP_ROM_QSTR(MP_QSTR_nvm), MP_ROM_PTR(&mp_const_none_obj) }, #endif + { MP_ROM_QSTR(MP_QSTR_RunMode), MP_ROM_PTR(&mcu_runmode_type) }, { MP_ROM_QSTR(MP_QSTR_Pin), MP_ROM_PTR(&mcu_pin_type) }, { MP_ROM_QSTR(MP_QSTR_pin), MP_ROM_PTR(&mcu_pin_module) }, { MP_ROM_QSTR(MP_QSTR_Processor), MP_ROM_PTR(&mcu_processor_type) }, diff --git a/shared-bindings/microcontroller/__init__.h b/shared-bindings/microcontroller/__init__.h index d43db4bf45..e1487c555a 100644 --- a/shared-bindings/microcontroller/__init__.h +++ b/shared-bindings/microcontroller/__init__.h @@ -33,11 +33,16 @@ #include "common-hal/microcontroller/Processor.h" +#include "shared-bindings/microcontroller/RunMode.h" + extern void common_hal_mcu_delay_us(uint32_t); extern void common_hal_mcu_disable_interrupts(void); extern void common_hal_mcu_enable_interrupts(void); +extern void common_hal_mcu_on_next_reset(mcu_runmode_t runmode); +extern void common_hal_mcu_reset(void); + extern const mp_obj_dict_t mcu_pin_globals; extern const mcu_processor_obj_t common_hal_mcu_processor_obj; diff --git a/shared-module/_stage/Layer.c b/shared-module/_stage/Layer.c new file mode 100644 index 0000000000..4c9c46d7c6 --- /dev/null +++ b/shared-module/_stage/Layer.c @@ -0,0 +1,105 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 Radomir Dopieralski + * + * 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 "Layer.h" +#include "__init__.h" + + +// Get the color of the pixel on the layer. +uint16_t get_layer_pixel(layer_obj_t *layer, int16_t x, uint16_t y) { + + // Shift by the layer's position offset. + x -= layer->x; + y -= layer->y; + + // Bounds check. + if ((x < 0) || (x >= layer->width << 4) || + (y < 0) || (y >= layer->height << 4)) { + return TRANSPARENT; + } + + // Get the tile from the grid location or from sprite frame. + uint8_t frame = layer->frame; + if (layer->map) { + uint8_t tx = x >> 4; + uint8_t ty = y >> 4; + + frame = layer->map[(ty * layer->width + tx) >> 1]; + if (tx & 0x01) { + frame &= 0x0f; + } else { + frame >>= 4; + } + } + + // Get the position within the tile. + x &= 0x0f; + y &= 0x0f; + + // Rotate the image. + uint8_t ty = y; // Temporary variable for swapping. + switch (layer->rotation) { + case 1: // 90 degrees clockwise + y = 15 - x; + x = ty; + break; + case 2: // 180 degrees + y = 15 - ty; + x = 15 - x; + break; + case 3: // 90 degrees counter-clockwise + y = x; + x = 15 - ty; + break; + case 4: // 0 degrees, mirrored + x = 15 - x; + break; + case 5: // 90 degrees clockwise, mirrored + y = x; + x = ty; + break; + case 6: // 180 degrees, mirrored + y = 15 - ty; + break; + case 7: // 90 degrees counter-clockwise, mirrored + y = 15 - x; + x = 15 - ty; + break; + default: // 0 degrees + break; + } + + // Get the value of the pixel. + uint8_t pixel = layer->graphic[(frame << 7) + (y << 3) + (x >> 1)]; + if (x & 0x01) { + pixel &= 0x0f; + } else { + pixel >>= 4; + } + + // Convert to 16-bit color using the palette. + return layer->palette[pixel << 1] | layer->palette[(pixel << 1) + 1] << 8; +} diff --git a/shared-module/_stage/Layer.h b/shared-module/_stage/Layer.h new file mode 100644 index 0000000000..c46f71349f --- /dev/null +++ b/shared-module/_stage/Layer.h @@ -0,0 +1,48 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 Radomir Dopieralski + * + * 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_SHARED_MODULE__STAGE_LAYER_H +#define MICROPY_INCLUDED_SHARED_MODULE__STAGE_LAYER_H + +#include +#include + +#include "py/obj.h" + +typedef struct { + mp_obj_base_t base; + uint8_t *map; + uint8_t *graphic; + uint8_t *palette; + int16_t x, y; + uint8_t width, height; + uint8_t frame; + uint8_t rotation; +} layer_obj_t; + +uint16_t get_layer_pixel(layer_obj_t *layer, int16_t x, uint16_t y); + +#endif // MICROPY_INCLUDED_SHARED_MODULE__STAGE_LAYER diff --git a/shared-module/_stage/Text.c b/shared-module/_stage/Text.c new file mode 100644 index 0000000000..307f9bbfa7 --- /dev/null +++ b/shared-module/_stage/Text.c @@ -0,0 +1,67 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 Radomir Dopieralski + * + * 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 "Text.h" +#include "__init__.h" + + +// Get the color of the pixel on the text. +uint16_t get_text_pixel(text_obj_t *text, int16_t x, uint16_t y) { + + // Shift by the text's position offset. + x -= text->x; + y -= text->y; + + // Bounds check. + if ((x < 0) || (x >= text->width << 3) || + (y < 0) || (y >= text->height << 3)) { + return TRANSPARENT; + } + + // Get the tile from the grid location or from sprite frame. + uint8_t tx = x >> 3; + uint8_t ty = y >> 3; + uint8_t c = text->chars[ty * text->width + tx]; + uint8_t color_offset = 0; + if (c & 0x80) { + color_offset = 4; + } + c &= 0x7f; + if (!c) { + return TRANSPARENT; + } + + // Get the position within the char. + x &= 0x07; + y &= 0x07; + + // Get the value of the pixel. + uint8_t pixel = text->font[(c << 4) + (y << 1) + (x >> 2)]; + pixel = ((pixel >> ((x & 0x03) << 1)) & 0x03) + color_offset; + + // Convert to 16-bit color using the palette. + return text->palette[pixel << 1] | text->palette[(pixel << 1) + 1] << 8; +} diff --git a/shared-module/_stage/Text.h b/shared-module/_stage/Text.h new file mode 100644 index 0000000000..bc111e49c1 --- /dev/null +++ b/shared-module/_stage/Text.h @@ -0,0 +1,46 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 Radomir Dopieralski + * + * 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_SHARED_MODULE__STAGE_TEXT_H +#define MICROPY_INCLUDED_SHARED_MODULE__STAGE_TEXT_H + +#include +#include + +#include "py/obj.h" + +typedef struct { + mp_obj_base_t base; + uint8_t *chars; + uint8_t *font; + uint8_t *palette; + int16_t x, y; + uint8_t width, height; +} text_obj_t; + +uint16_t get_text_pixel(text_obj_t *text, int16_t x, uint16_t y); + +#endif // MICROPY_INCLUDED_SHARED_MODULE__STAGE_TEXT diff --git a/shared-module/_stage/__init__.c b/shared-module/_stage/__init__.c new file mode 100644 index 0000000000..1931b89407 --- /dev/null +++ b/shared-module/_stage/__init__.c @@ -0,0 +1,76 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 Radomir Dopieralski + * + * 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 "Layer.h" +#include "Text.h" +#include "__init__.h" +#include "shared-bindings/_stage/Layer.h" +#include "shared-bindings/_stage/Text.h" + + +bool render_stage(uint8_t x0, uint8_t y0, uint8_t x1, uint8_t y1, + mp_obj_t *layers, size_t layers_size, + uint16_t *buffer, size_t buffer_size, + busio_spi_obj_t *spi) { + + // TODO(deshipu): Do a collision check of each layer with the + // rectangle, and only process the layers that overlap with it. + + size_t index = 0; + for (uint8_t y = y0; y < y1; ++y) { + for (uint8_t x = x0; x < x1; ++x) { + for (size_t layer = 0; layer < layers_size; ++layer) { + uint16_t c = TRANSPARENT; + layer_obj_t *obj = MP_OBJ_TO_PTR(layers[layer]); + if (obj->base.type == &mp_type_layer) { + c = get_layer_pixel(obj, x, y); + } else if (obj->base.type == &mp_type_text) { + c = get_text_pixel((text_obj_t *)obj, x, y); + } + if (c != TRANSPARENT) { + buffer[index] = c; + break; + } + } + index += 1; + // The buffer is full, send it. + if (index >= buffer_size) { + if (!common_hal_busio_spi_write(spi, + ((uint8_t*)buffer), buffer_size * 2)) { + return false; + } + index = 0; + } + } + } + // Send the remaining data. + if (index) { + if (!common_hal_busio_spi_write(spi, ((uint8_t*)buffer), index * 2)) { + return false; + } + } + return true; +} diff --git a/shared-module/_stage/__init__.h b/shared-module/_stage/__init__.h new file mode 100644 index 0000000000..326c725599 --- /dev/null +++ b/shared-module/_stage/__init__.h @@ -0,0 +1,42 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 Radomir Dopieralski + * + * 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_SHARED_MODULE__STAGE_H +#define MICROPY_INCLUDED_SHARED_MODULE__STAGE_H + +#include "shared-bindings/busio/SPI.h" +#include +#include +#include "py/obj.h" + +#define TRANSPARENT (0x1ff8) + +bool render_stage(uint8_t x0, uint8_t y0, uint8_t x1, uint8_t y1, + mp_obj_t *layers, size_t layers_size, + uint16_t *buffer, size_t buffer_size, + busio_spi_obj_t *spi); + +#endif // MICROPY_INCLUDED_SHARED_MODULE__STAGE diff --git a/tools/build_adafruit_bins.sh b/tools/build_adafruit_bins.sh index ae9c256d24..4c5be2c85a 100755 --- a/tools/build_adafruit_bins.sh +++ b/tools/build_adafruit_bins.sh @@ -2,7 +2,7 @@ rm -rf ports/atmel-samd/build* rm -rf ports/esp8266/build* rm -rf ports/nrf/build* -ATMEL_BOARDS="arduino_zero circuitplayground_express feather_m0_basic feather_m0_adalogger feather_m0_express metro_m0_express metro_m4_express trinket_m0 gemma_m0 feather52" +ATMEL_BOARDS="arduino_zero circuitplayground_express feather_m0_basic feather_m0_adalogger itsybitsy_m0 feather_m0_express metro_m0_express metro_m4_express trinket_m0 gemma_m0 feather52" ROSIE_SETUPS="rosie-ci" PARALLEL="-j 5" diff --git a/tools/preprocess_frozen_modules.py b/tools/preprocess_frozen_modules.py new file mode 100755 index 0000000000..0233fba614 --- /dev/null +++ b/tools/preprocess_frozen_modules.py @@ -0,0 +1,71 @@ +#!/usr/bin/env python3 +import argparse +import os +import os.path +from pathlib import Path +import semver +import subprocess + +# Compatible with Python 3.4 due to travis using trusty as default. + +def version_string(path=None, *, valid_semver=False): + version = None + try: + tag = subprocess.check_output('git describe --tags --exact-match', shell=True, cwd=path) + version = tag.strip().decode("utf-8", "strict") + except subprocess.CalledProcessError: + describe = subprocess.check_output("git describe --tags", shell=True, cwd=path) + tag, additional_commits, commitish = describe.strip().decode("utf-8", "strict").rsplit("-", maxsplit=2) + commitish = commitish[1:] + if valid_semver: + version_info = semver.parse_version_info(tag) + if not version_info.prerelease: + version = semver.bump_patch(tag) + "-alpha.0.plus." + additional_commits + "+" + commitish + else: + version = tag + ".plus." + additional_commits + "+" + commitish + else: + version = commitish + return version + +# Visit all the .py files in topdir. Replace any __version__ = "0.0.0-auto.0" type of info +# with actual version info derived from git. +def copy_and_process(in_dir, out_dir): + for root, subdirs, files in os.walk(in_dir): + + # Skip library examples directories. + if Path(root).name == 'examples': + continue + + for file in files: + # Skip top-level setup.py (module install info) and conf.py (sphinx config), + # which are not part of the library + if (root == in_dir) and file in ('conf.py', 'setup.py'): + continue + + input_file_path = Path(root, file) + output_file_path = Path(out_dir, input_file_path.relative_to(in_dir)) + + if file.endswith(".py"): + if not output_file_path.parent.exists(): + output_file_path.parent.mkdir(parents=True) + with input_file_path.open("r") as input, output_file_path.open("w") as output: + for line in input: + if line.startswith("__version__"): + module_version = version_string(root, valid_semver=True) + line = line.replace("0.0.0-auto.0", module_version) + output.write(line) + +if __name__ == '__main__': + argparser = argparse.ArgumentParser(description="""\ + Copy and pre-process .py files into output directory, before freezing. + 1. Remove top-level repo directory. + 2. Update __version__ info. + 3. Remove examples. + 4. Remove non-library setup.py and conf.py""") + argparser.add_argument("in_dirs", metavar="input-dir", nargs="+", + help="top-level code dirs (may be git repo dirs)") + argparser.add_argument("-o", "--out_dir", help="output directory") + args = argparser.parse_args() + + for in_dir in args.in_dirs: + copy_and_process(in_dir, args.out_dir) diff --git a/tools/python-semver b/tools/python-semver new file mode 160000 index 0000000000..2001c62d1a --- /dev/null +++ b/tools/python-semver @@ -0,0 +1 @@ +Subproject commit 2001c62d1a0361c44acc7076d8ce91e1d1c66141