merge from 2.2.0 + fix up board defs

This commit is contained in:
Dan Halbert 2018-01-02 21:25:41 -05:00
parent ce81c8dda9
commit 065e82015f
96 changed files with 3105 additions and 194 deletions

3
.gitmodules vendored
View File

@ -26,6 +26,9 @@
[submodule "frozen/Adafruit_CircuitPython_BusDevice"] [submodule "frozen/Adafruit_CircuitPython_BusDevice"]
path = frozen/Adafruit_CircuitPython_BusDevice path = frozen/Adafruit_CircuitPython_BusDevice
url = https://github.com/adafruit/Adafruit_CircuitPython_BusDevice.git 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"] [submodule "lib/stm32lib"]
path = lib/stm32lib path = lib/stm32lib
url = https://github.com/micropython/stm32lib url = https://github.com/micropython/stm32lib

2
.readthedocs.yml Normal file
View File

@ -0,0 +1,2 @@
python:
version: 3

View File

@ -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 before being reset by the button or being disconnected from USB. This can also
happen on Linux and Mac OSX but its less likely. 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), **For boards with** ``CIRCUITPY`` **stored on a separate SPI flash chip,
follow the process below. It's important to note that **any files stored on the such as Feather M0 Express, Metro M0 Express and Circuit Playground Express:**
``CIRCUITPY`` drive will be erased**.
#. Download the appropriate flash erase uf2 from `here <https://github.com/adafruit/Adafruit_SPIFlash/tree/master/examples/flash_erase_express>`_.
#. Download the appropriate flash .erase uf2 from `here <https://github.com/adafruit/Adafruit_SPIFlash/tree/master/examples/flash_erase_express>`_.
#. Double-click the reset button. #. Double-click the reset button.
#. Copy the appropriate .uf2 to the xxxBOOT drive. #. Copy the appropriate .uf2 to the xxxBOOT drive.
#. The on-board NeoPixel will turn blue, indicating the erase has started. #. 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. #. 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 <https://github.com/adafruit/circuitpython/releases/latest>`_. #. Double-click again and load the appropriate `CircuitPython .uf2 <https://github.com/adafruit/circuitpython/releases/latest>`_.
**For boards without SPI flash, such as Feather M0 Proto, Gemma M0 and, Trinket M0:**
#. Download the appropriate erase .uf2 from `here <https://github.com/adafruit/Adafruit_Learning_System_Guides/tree/master/uf2_flash_erasers>`_.
#. 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 <https://github.com/adafruit/circuitpython/releases/latest>`_.
ValueError: Incompatible ``.mpy`` file. 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 (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 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 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 newer version of the library that triggered the error on ``import``. They are
all available in the all available in the
`Adafruit bundle <https://github.com/adafruit/Adafruit_CircuitPython_Bundle/releases/latest>`_ `Adafruit bundle <https://github.com/adafruit/Adafruit_CircuitPython_Bundle/releases/latest>`_

View File

@ -18,7 +18,7 @@ float nearbyintf(float x)
#pragma GCC diagnostic push #pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wfloat-equal" #pragma GCC diagnostic ignored "-Wfloat-equal"
if (y == 0) if (y == 0)
#pragma GCC diagnostic pop
return s ? -0.0f : 0.0f; return s ? -0.0f : 0.0f;
#pragma GCC diagnostic pop
return y; return y;
} }

View File

@ -255,7 +255,8 @@ STATIC int pyexec_friendly_repl_process_char(int c) {
} else if (ret == CHAR_CTRL_B) { } else if (ret == CHAR_CTRL_B) {
// reset friendly REPL // reset friendly REPL
mp_hal_stdout_tx_str("\r\n"); 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"); // mp_hal_stdout_tx_str("Type \"help()\" for more information.\r\n");
goto input_restart; goto input_restart;
} else if (ret == CHAR_CTRL_C) { } else if (ret == CHAR_CTRL_C) {
@ -394,7 +395,9 @@ int pyexec_friendly_repl(void) {
#endif #endif
friendly_repl_reset: 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"); // mp_hal_stdout_tx_str("Type \"help()\" for more information.\r\n");
// to test ctrl-C // to test ctrl-C

View File

@ -76,6 +76,9 @@ BASE_CFLAGS = \
-ffunction-sections \ -ffunction-sections \
-fdata-sections \ -fdata-sections \
-fshort-enums \ -fshort-enums \
-DCIRCUITPY_SOFTWARE_SAFE_MODE=0x0ADABEEF \
-DCIRCUITPY_CANARY_WORD=0xADAF00 \
-DCIRCUITPY_SAFE_RESTART_WORD=0xDEADBEEF \
--param max-inline-insns-single=500 --param max-inline-insns-single=500
# NDEBUG disables assert() statements. This reduces code size pretty dramatically, per tannewt. # NDEBUG disables assert() statements. This reduces code size pretty dramatically, per tannewt.
@ -312,6 +315,7 @@ SRC_BINDINGS_ENUMS = \
digitalio/Direction.c \ digitalio/Direction.c \
digitalio/DriveMode.c \ digitalio/DriveMode.c \
digitalio/Pull.c \ digitalio/Pull.c \
microcontroller/RunMode.c \
help.c \ help.c \
math/__init__.c \ math/__init__.c \
supervisor/__init__.c \ supervisor/__init__.c \

View File

@ -10,16 +10,29 @@
#define SPI_FLASH_BAUDRATE (8000000) #define SPI_FLASH_BAUDRATE (8000000)
// On-board flash // On-board flash
#define SPI_FLASH_MUX_SETTING SPI_SIGNAL_MUX_SETTING_E #define SPI_FLASH_MOSI_PIN PIN_PA20
// Use default pinmux for the chip select since we manage it ourselves. #define SPI_FLASH_MISO_PIN PIN_PA16
#define SPI_FLASH_PAD0_PINMUX PINMUX_PA16D_SERCOM3_PAD0 // MISO #define SPI_FLASH_SCK_PIN PIN_PA21
#define SPI_FLASH_PAD1_PINMUX PINMUX_UNUSED // CS #define SPI_FLASH_CS_PIN PIN_PB22
#define SPI_FLASH_PAD2_PINMUX PINMUX_PA20D_SERCOM3_PAD2 // MOSI
#define SPI_FLASH_PAD3_PINMUX PINMUX_PA21D_SERCOM3_PAD3 // SCK
#define SPI_FLASH_CS PIN_PB22 #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 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
// <o> 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. // PA24 and PA25 are USB.
#define MICROPY_PORT_A (PORT_PA16 | PORT_PA20 | PORT_PA21 | PORT_PA24 | PORT_PA25) #define MICROPY_PORT_A (PORT_PA16 | PORT_PA20 | PORT_PA21 | PORT_PA24 | PORT_PA25)
#define MICROPY_PORT_B (PORT_PB22) #define MICROPY_PORT_B (PORT_PB22)
@ -27,8 +40,7 @@
#define SPEAKER_ENABLE_PIN (&pin_PA30) #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 // If you change this, then make sure to update the linker scripts as well to
// make sure you don't overwrite code. // make sure you don't overwrite code.

View File

@ -4,16 +4,13 @@ USB_PID = 0x8019
USB_PRODUCT = "CircuitPlayground Express" USB_PRODUCT = "CircuitPlayground Express"
USB_MANUFACTURER = "Adafruit Industries LLC" USB_MANUFACTURER = "Adafruit Industries LLC"
#SPI_FLASH_FILESYSTEM = 1 SPI_FLASH_FILESYSTEM = 1
INTERNAL_FLASH_FILESYSTEM = 1
CHIP_VARIANT = SAMD21G18A CHIP_VARIANT = SAMD21G18A
CHIP_FAMILY = samd21 CHIP_FAMILY = samd21
# Include these Python libraries in firmware. # 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 FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_BusDevice
### is in use FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_LIS3DH
###FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_BusDevice FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_NeoPixel
###FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_LIS3DH FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_Thermistor
###FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_NeoPixel
###FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_Thermistor

View File

@ -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) {
}

View File

@ -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 <a href="http://www.atmel.com/design-support/">Atmel Support</a>
*/
#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_

View File

@ -0,0 +1,14 @@
/**
* \file
*
* \brief User board configuration template
*
*/
/*
* Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a>
*/
#ifndef CONF_BOARD_H
#define CONF_BOARD_H
#endif // CONF_BOARD_H

View File

@ -0,0 +1 @@
#include "conf_clocks_external_32k.h"

View File

@ -0,0 +1,220 @@
#include <stdbool.h>
#include <stdint.h>
#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

View File

@ -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"

View File

@ -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

View File

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

View File

@ -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

View File

@ -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

View File

@ -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) {
}

View File

@ -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 <a href="http://www.atmel.com/design-support/">Atmel Support</a>
*/
#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_

View File

@ -0,0 +1,14 @@
/**
* \file
*
* \brief User board configuration template
*
*/
/*
* Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a>
*/
#ifndef CONF_BOARD_H
#define CONF_BOARD_H
#endif // CONF_BOARD_H

View File

@ -0,0 +1 @@
#include "conf_clocks_crystalless.h"

View File

@ -0,0 +1,221 @@
#include <stdbool.h>
#include <stdint.h>
#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

View File

@ -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"

View File

@ -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

View File

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

View File

@ -11,7 +11,8 @@ MEMORY
} }
/* top end of the stack */ /* top end of the stack */
_estack = ORIGIN(RAM) + LENGTH(RAM); _estack = ORIGIN(RAM) + LENGTH(RAM) - 4;
_bootloader_dbl_tap = _estack;
/* define output sections */ /* define output sections */
SECTIONS SECTIONS

View File

@ -11,7 +11,8 @@ MEMORY
} }
/* top end of the stack */ /* top end of the stack */
_estack = ORIGIN(RAM) + LENGTH(RAM); _estack = ORIGIN(RAM) + LENGTH(RAM) - 4;
_bootloader_dbl_tap = _estack;
/* define output sections */ /* define output sections */
SECTIONS SECTIONS

View File

@ -10,7 +10,8 @@ MEMORY
} }
/* top end of the stack */ /* top end of the stack */
_estack = ORIGIN(RAM) + LENGTH(RAM); _estack = ORIGIN(RAM) + LENGTH(RAM) - 4;
_bootloader_dbl_tap = _estack;
/* define output sections */ /* define output sections */
SECTIONS SECTIONS

View File

@ -11,7 +11,8 @@ MEMORY
} }
/* top end of the stack */ /* top end of the stack */
_estack = ORIGIN(RAM) + LENGTH(RAM); _estack = ORIGIN(RAM) + LENGTH(RAM) - 4;
_bootloader_dbl_tap = _estack;
/* define output sections */ /* define output sections */
SECTIONS SECTIONS

View File

@ -12,6 +12,7 @@ MEMORY
/* top end of the stack */ /* top end of the stack */
_estack = ORIGIN(RAM) + LENGTH(RAM); _estack = ORIGIN(RAM) + LENGTH(RAM);
_bootloader_dbl_tap = 0;
/* define output sections */ /* define output sections */
SECTIONS SECTIONS

View File

@ -12,6 +12,7 @@ MEMORY
/* top end of the stack */ /* top end of the stack */
_estack = ORIGIN(RAM) + LENGTH(RAM); _estack = ORIGIN(RAM) + LENGTH(RAM);
_bootloader_dbl_tap = 0;
/* define output sections */ /* define output sections */
SECTIONS SECTIONS

View File

@ -10,7 +10,8 @@ MEMORY
} }
/* top end of the stack */ /* top end of the stack */
_estack = ORIGIN(RAM) + LENGTH(RAM); _estack = ORIGIN(RAM) + LENGTH(RAM) - 4;
_bootloader_dbl_tap = _estack;
/* define output sections */ /* define output sections */
SECTIONS SECTIONS

View File

@ -10,7 +10,8 @@ MEMORY
} }
/* top end of the stack */ /* top end of the stack */
_estack = ORIGIN(RAM) + LENGTH(RAM); _estack = ORIGIN(RAM) + LENGTH(RAM) - 4;
_bootloader_dbl_tap = _estack;
/* define output sections */ /* define output sections */
SECTIONS SECTIONS

View File

@ -10,7 +10,8 @@ MEMORY
} }
/* top end of the stack */ /* top end of the stack */
_estack = ORIGIN(RAM) + LENGTH(RAM); _estack = ORIGIN(RAM) + LENGTH(RAM) - 4;
_bootloader_dbl_tap = _estack;
/* define output sections */ /* define output sections */
SECTIONS SECTIONS

View File

@ -10,7 +10,8 @@ MEMORY
} }
/* top end of the stack */ /* top end of the stack */
_estack = ORIGIN(RAM) + LENGTH(RAM); _estack = ORIGIN(RAM) + LENGTH(RAM) - 4;
_bootloader_dbl_tap = _estack;
/* define output sections */ /* define output sections */
SECTIONS SECTIONS

View File

@ -10,7 +10,8 @@ MEMORY
} }
/* top end of the stack */ /* top end of the stack */
_estack = ORIGIN(RAM) + LENGTH(RAM); _estack = ORIGIN(RAM) + LENGTH(RAM) - 4;
_bootloader_dbl_tap = _estack;
/* define output sections */ /* define output sections */
SECTIONS SECTIONS

View File

@ -11,6 +11,7 @@ MEMORY
/* top end of the stack */ /* top end of the stack */
_estack = ORIGIN(RAM) + LENGTH(RAM); _estack = ORIGIN(RAM) + LENGTH(RAM);
_bootloader_dbl_tap = 0;
/* define output sections */ /* define output sections */
SECTIONS SECTIONS

View File

@ -11,6 +11,7 @@ MEMORY
/* top end of the stack */ /* top end of the stack */
_estack = ORIGIN(RAM) + LENGTH(RAM); _estack = ORIGIN(RAM) + LENGTH(RAM);
_bootloader_dbl_tap = 0;
/* define output sections */ /* define output sections */
SECTIONS SECTIONS

View File

@ -4,8 +4,7 @@ USB_PID = 0x801F
USB_PRODUCT="Trinket M0 Haxpress" USB_PRODUCT="Trinket M0 Haxpress"
USB_MANUFACTURER="Radomir Dopieralski" USB_MANUFACTURER="Radomir Dopieralski"
#SPI_FLASH_FILESYSTEM = 1 SPI_FLASH_FILESYSTEM = 1
INTERNAL_FLASH_FILESYSTEM = 1
CHIP_VARIANT = SAMD21E18A CHIP_VARIANT = SAMD21E18A
CHIP_FAMILY = samd21 CHIP_FAMILY = samd21

View File

@ -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) {
}

View File

@ -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 <a href="http://www.atmel.com/design-support/">Atmel Support</a>
*/
#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_

View File

@ -0,0 +1,14 @@
/**
* \file
*
* \brief User board configuration template
*
*/
/*
* Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a>
*/
#ifndef CONF_BOARD_H
#define CONF_BOARD_H
#endif // CONF_BOARD_H

View File

@ -0,0 +1 @@
#include "conf_clocks_crystalless.h"

View File

@ -0,0 +1,221 @@
#include <stdbool.h>
#include <stdint.h>
#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

View File

@ -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

View File

@ -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

View File

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

View File

@ -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.reference = ADC_REFERENCE_INTVCC1;
config_adc.gain_factor = ADC_GAIN_FACTOR_DIV2; config_adc.gain_factor = ADC_GAIN_FACTOR_DIV2;
config_adc.positive_input = self->pin->adc_input; config_adc.positive_input = self->pin->adc_input;
config_adc.resolution = ADC_RESOLUTION_16BIT; config_adc.resolution = ADC_RESOLUTION_12BIT;
config_adc.clock_prescaler = ADC_CLOCK_PRESCALER_DIV128; // 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; struct adc_module adc_instance;
// ADC must have been disabled before adc_init() is called. // 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); 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) { float common_hal_analogio_analogin_get_reference_voltage(analogio_analogin_obj_t *self) {

View File

@ -26,6 +26,7 @@
#include <stdint.h> #include <stdint.h>
#include <string.h> #include <string.h>
#include <math.h>
#include "py/gc.h" #include "py/gc.h"
#include "py/mperrno.h" #include "py/mperrno.h"
@ -42,6 +43,12 @@
#include "shared_dma.h" #include "shared_dma.h"
#include "tick.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) { void pdmin_reset(void) {
while (I2S->SYNCBUSY.reg & I2S_SYNCBUSY_ENABLE) {} while (I2S->SYNCBUSY.reg & I2S_SYNCBUSY_ENABLE) {}
I2S->INTENCLR.reg = I2S_INTENCLR_MASK; 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."); mp_raise_RuntimeError("Unable to allocate audio DMA block counter.");
} }
if (!(bit_depth == 16 || bit_depth == 8) || !mono || oversample != 64) { if (!(bit_depth == 16 || bit_depth == 8) || !mono || oversample != OVERSAMPLING) {
mp_raise_NotImplementedError("Only 8 or 16 bit mono with 64 oversample is supported."); 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. // 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.mck_out_enable = false;
config_clock_unit.clock.sck_src = I2S_SERIAL_CLOCK_SOURCE_MCKDIV; config_clock_unit.clock.sck_src = I2S_SERIAL_CLOCK_SOURCE_MCKDIV;
config_clock_unit.clock.sck_div = 8000000 / frequency / oversample; uint32_t clock_divisor = (uint32_t) roundf( 8000000.0f / frequency / oversample);
self->frequency = 8000000 / config_clock_unit.clock.sck_div / 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.number_slots = 2;
config_clock_unit.frame.slot_size = I2S_SLOT_SIZE_16_BIT; 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; 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_serializer_set_config(&self->i2s_instance, self->serializer, &config_serializer);
i2s_enable(&self->i2s_instance); 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->bytes_per_sample = oversample >> 3;
self->bit_depth = bit_depth; self->bit_depth = bit_depth;
} }
@ -154,6 +170,8 @@ void common_hal_audiobusio_pdmin_deinit(audiobusio_pdmin_obj_t* self) {
return; return;
} }
i2s_disable(&self->i2s_instance); 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); i2s_reset(&self->i2s_instance);
reset_pin(self->clock_pin->pin); reset_pin(self->clock_pin->pin);
reset_pin(self->data_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); 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) { if (length * words_per_sample > words_per_buffer) {
block_transfer_count = words_per_buffer; block_transfer_count = words_per_buffer;
descriptor_config.next_descriptor_address = ((uint32_t)audio_dma.descriptor); descriptor_config.next_descriptor_address = ((uint32_t)audio_dma.descriptor);
if (length * words_per_sample < 2 * words_per_buffer) { 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.next_descriptor_address = 0;
} }
descriptor_config.block_transfer_count = block_transfer_count; 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) { void start_dma(audiobusio_pdmin_obj_t* self) {
dma_start_transfer_job(&audio_dma); dma_start_transfer_job(&audio_dma);
tc_start_counter(MP_STATE_VM(audiodma_block_counter)); 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; I2S->DATA[1].reg = I2S->DATA[1].reg;
} }
void stop_dma(audiobusio_pdmin_obj_t* self) { void stop_dma(audiobusio_pdmin_obj_t* self) {
// Turn off the I2S clock and serializer. Peripheral is still enabled. // Shutdown the DMA: serializer keeps running.
i2s_serializer_disable(&self->i2s_instance, self->serializer);
i2s_clock_unit_disable(&self->i2s_instance, self->clock_unit);
// Shutdown the DMA
tc_stop_counter(MP_STATE_VM(audiodma_block_counter)); tc_stop_counter(MP_STATE_VM(audiodma_block_counter));
dma_abort_job(&audio_dma); dma_abort_job(&audio_dma);
} }
static const uint16_t sinc_filter[64] = { // a windowed sinc filter for 44 khz, 64 samples
0, 1, 6, 16, 29, 49, 75, 108, //
149, 200, 261, 334, 418, 514, 622, 742, // This filter is good enough to use for lower sample rates as
872, 1012, 1161, 1315, 1472, 1631, 1787, 1938, // well. It does not increase the noise enough to be a problem.
2081, 2212, 2329, 2429, 2509, 2568, 2604, 2616, //
2604, 2568, 2509, 2429, 2329, 2212, 2081, 1938, // In the long run we could use a fast filter like this to do the
1787, 1631, 1472, 1315, 1161, 1012, 872, 742, // decimation and initial filtering in real time, filtering to a
622, 514, 418, 334, 261, 200, 149, 108, // higher sample rate than specified. Then after the audio is
75, 49, 29, 16, 6, 1, 0, 0 // 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]) { static uint16_t filter_sample(uint32_t pdm_samples[4]) {
uint16_t sample = 0; uint16_t running_sum = 0;
for (uint8_t i = 0; i < 4; i++) { const uint16_t *filter_ptr = sinc_filter;
uint16_t pdm = pdm_samples[i] & 0xffff; for (uint8_t i = 0; i < OVERSAMPLING/16; i++) {
for (uint8_t j = 0; j < 16; j++) { // The sample is 16-bits right channel in the upper two bytes and 16-bits left channel
if ((pdm & 0x8000) != 0) { // in the lower two bytes.
sample += sinc_filter[i * 16 + j]; // We just ignore the upper bits
uint32_t pdm_sample = pdm_samples[i];
REPEAT_16_TIMES( {
if (pdm_sample & 0x8000) {
running_sum += *filter_ptr;
} }
pdm <<= 1; filter_ptr++;
pdm_sample <<= 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, uint32_t common_hal_audiobusio_pdmin_record_to_buffer(audiobusio_pdmin_obj_t* self,
uint16_t* output_buffer, uint32_t length) { uint16_t* output_buffer, uint32_t output_buffer_length) {
// Write the wave file header. // We allocate two buffers on the stack to use for double buffering.
const uint8_t samples_per_buffer = SAMPLES_PER_BUFFER;
// 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;
// For every word we record, we throw away 2 bytes of a phantom second channel. // 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; const 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_buffer = samples_per_buffer * words_per_sample;
uint32_t first_buffer[words_per_buffer]; uint32_t first_buffer[words_per_buffer];
uint32_t second_buffer[words_per_buffer]; uint32_t second_buffer[words_per_buffer];
COMPILER_ALIGNED(16) DmacDescriptor second_descriptor; 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); words_per_sample, first_buffer, second_buffer);
start_dma(self); start_dma(self);
// Record // Record
uint32_t buffers_processed = 0; uint32_t buffers_processed = 0;
uint32_t total_bytes = 0; uint32_t values_output = 0;
uint64_t start_ticks = ticks_ms; uint32_t remaining_samples_needed = output_buffer_length;
while (total_bytes < length) { while (values_output < output_buffer_length) {
// Wait for the next buffer to fill // 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 #ifdef MICROPY_VM_HOOK_LOOP
MICROPY_VM_HOOK_LOOP MICROPY_VM_HOOK_LOOP
#endif #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; break;
} }
// Throw away the first ~10ms of data because thats during mic start up.
if (ticks_ms - start_ticks < 10) { // The mic is running all the time, so we don't need to wait the usual 10msec or 100msec
buffers_processed++; // for it to start up.
continue;
} // Flip back and forth between processing the first and second buffers.
uint32_t *buffer = first_buffer; uint32_t *buffer = first_buffer;
DmacDescriptor* descriptor = audio_dma.descriptor; DmacDescriptor* descriptor = audio_dma.descriptor;
if (buffers_processed % 2 == 1) { if (buffers_processed % 2 == 1) {
buffer = second_buffer; buffer = second_buffer;
descriptor = &second_descriptor; descriptor = &second_descriptor;
} }
// Decimate and filter the last buffer // Decimate and filter the buffer that was just filled.
int32_t samples_gathered = descriptor->BTCNT.reg / words_per_sample; uint32_t samples_gathered = descriptor->BTCNT.reg / words_per_sample;
for (uint16_t i = 0; i < samples_gathered; i++) { // 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) { if (self->bit_depth == 8) {
((uint8_t*) output_buffer)[total_bytes] = filter_sample(buffer + i * words_per_sample) >> 8; // Truncate to 8 bits.
total_bytes += 1; ((uint8_t*) output_buffer)[values_output] = value >> 8;
} else if (self->bit_depth == 16) { } else {
output_buffer[total_bytes / 2] = filter_sample(buffer + i * words_per_sample); output_buffer[values_output] = value;
total_bytes += 2;
} }
values_output++;
} }
buffers_processed++; buffers_processed++;
if (length - total_bytes < samples_per_buffer) { // Compute how many more samples we need, and if the last buffer is the last
descriptor->BTCNT.reg = (length - total_bytes) * words_per_sample; // set of samples needed, adjust the DMA count to only fetch as necessary.
descriptor->DSTADDR.reg = ((uint32_t) buffer) + (length - total_bytes) * self->bytes_per_sample; 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; descriptor->DESCADDR.reg = 0;
} }
} }
stop_dma(self); 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) { void common_hal_audiobusio_pdmin_record_to_file(audiobusio_pdmin_obj_t* self, uint8_t* buffer, uint32_t length) {

View File

@ -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. 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.
}

View File

@ -58,7 +58,7 @@ void common_hal_digitalio_digitalinout_deinit(digitalio_digitalinout_obj_t* self
} }
void common_hal_digitalio_digitalinout_switch_to_input( 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; self->output = false;
common_hal_digitalio_digitalinout_set_pull(self, pull); 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( void common_hal_digitalio_digitalinout_switch_to_output(
digitalio_digitalinout_obj_t* self, bool value, 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; const uint8_t pin = self->pin->pin;
gpio_set_pin_pull_mode(pin, GPIO_PULL_OFF); gpio_set_pin_pull_mode(pin, GPIO_PULL_OFF);
gpio_set_pin_direction(pin, GPIO_DIRECTION_OUT); 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); 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) { digitalio_digitalinout_obj_t* self) {
return self->output? DIRECTION_OUTPUT : DIRECTION_INPUT; 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( void common_hal_digitalio_digitalinout_set_drive_mode(
digitalio_digitalinout_obj_t* self, 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); bool value = common_hal_digitalio_digitalinout_get_value(self);
self->open_drain = drive_mode == DRIVE_MODE_OPEN_DRAIN; self->open_drain = drive_mode == DRIVE_MODE_OPEN_DRAIN;
// True is implemented differently between modes so reset the value to make // 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) { digitalio_digitalinout_obj_t* self) {
if (self->open_drain) { if (self->open_drain) {
return DRIVE_MODE_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( 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; enum gpio_pull_mode asf_pull = GPIO_PULL_OFF;
switch (pull) { switch (pull) {
case PULL_UP: case PULL_UP:
@ -151,7 +151,7 @@ void common_hal_digitalio_digitalinout_set_pull(
gpio_set_pin_pull_mode(self->pin->pin, asf_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) { digitalio_digitalinout_obj_t* self) {
uint32_t pin = self->pin->pin; uint32_t pin = self->pin->pin;
if (self->output) { if (self->output) {

View File

@ -27,10 +27,13 @@
#include "py/mphal.h" #include "py/mphal.h"
#include "py/obj.h" #include "py/obj.h"
#include "hal/include/hal_atomic.h" #include "hal/include/hal_atomic.h"
#include "py/runtime.h"
#include "reset.h"
#include "samd21_pins.h" #include "samd21_pins.h"
#include "shared-bindings/nvm/ByteArray.h" #include "shared-bindings/nvm/ByteArray.h"
#include "shared-bindings/microcontroller/__init__.h"
#include "shared-bindings/microcontroller/Processor.h" #include "shared-bindings/microcontroller/Processor.h"
void common_hal_mcu_delay_us(uint32_t delay) { void common_hal_mcu_delay_us(uint32_t delay) {
@ -48,9 +51,32 @@ void common_hal_mcu_enable_interrupts(void) {
atomic_leave_critical(&flags); 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 // The singleton microcontroller.Processor object, bound to microcontroller.cpu
// It currently only has properties, and no state. // 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 = { .base = {
.type = &mcu_processor_type, .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. // NVM is only available on Express boards for now.
#if CIRCUITPY_INTERNAL_NVM_SIZE > 0 #if CIRCUITPY_INTERNAL_NVM_SIZE > 0
// The singleton nvm.ByteArray object. // 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 = { // .base = {
// .type = &nvm_bytearray_type, // .type = &nvm_bytearray_type,
// }, // },

View File

@ -24,23 +24,22 @@
* THE SOFTWARE. * THE SOFTWARE.
*/ */
#include "reset.h"
#include "include/sam.h" #include "include/sam.h"
#include "reset.h"
#include "supervisor/filesystem.h" #include "supervisor/filesystem.h"
// Copied from inc/uf2.h in https://github.com/Microsoft/uf2-samd21 void reset(void) {
#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) {
filesystem_flush(); filesystem_flush();
*DBL_TAP_PTR = DBL_TAP_MAGIC;
NVIC_SystemReset(); 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;
}

View File

@ -26,6 +26,16 @@
#ifndef MICROPY_INCLUDED_ATMEL_SAMD_RESET_H #ifndef MICROPY_INCLUDED_ATMEL_SAMD_RESET_H
#define MICROPY_INCLUDED_ATMEL_SAMD_RESET_H #define MICROPY_INCLUDED_ATMEL_SAMD_RESET_H
#include <stdbool.h>
#include <stdint.h>
// 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_to_bootloader(void);
void reset(void);
bool bootloader_available(void);
#endif // MICROPY_INCLUDED_ATMEL_SAMD_RESET_H #endif // MICROPY_INCLUDED_ATMEL_SAMD_RESET_H

View File

@ -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); 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; struct dma_descriptor_config descriptor_config;
dma_descriptor_get_config_defaults(&descriptor_config); dma_descriptor_get_config_defaults(&descriptor_config);
descriptor_config.beat_size = DMA_BEAT_SIZE_BYTE; 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) { int32_t shared_dma_read(Sercom* sercom, uint8_t* buffer, uint32_t length, uint8_t tx) {
if (general_dma_tx.job_status != ERR_NONE) { 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; 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; descriptor_config.block_transfer_count = length;
// DATA register is consistently addressed across all SERCOM modes. // DATA register is consistently addressed across all SERCOM modes.
descriptor_config.source_address = ((uint32_t)&sercom->SPI.DATA.reg); 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); 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); dma_descriptor_get_config_defaults(&descriptor_config);
descriptor_config.beat_size = DMA_BEAT_SIZE_BYTE; 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.dst_increment_enable = false;
descriptor_config.block_transfer_count = length; 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. // DATA register is consistently addressed across all SERCOM modes.
descriptor_config.destination_address = ((uint32_t)&sercom->SPI.DATA.reg); descriptor_config.destination_address = ((uint32_t)&sercom->SPI.DATA.reg);

View File

@ -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_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_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. // Allocate a counter to track how far along we are in a DMA double buffer.
bool allocate_block_counter(void); bool allocate_block_counter(void);

View File

@ -130,6 +130,7 @@ SRC_BINDINGS_ENUMS = \
digitalio/DriveMode.c \ digitalio/DriveMode.c \
digitalio/Pull.c \ digitalio/Pull.c \
math/__init__.c \ math/__init__.c \
microcontroller/RunMode.c \
util.c util.c
SRC_COMMON_HAL_EXPANDED = $(addprefix shared-bindings/, $(SRC_COMMON_HAL)) \ SRC_COMMON_HAL_EXPANDED = $(addprefix shared-bindings/, $(SRC_COMMON_HAL)) \

View File

@ -185,3 +185,23 @@ bool common_hal_busio_spi_read(busio_spi_obj_t *self,
} }
return true; 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;
}

View File

@ -59,7 +59,7 @@ void common_hal_digitalio_digitalinout_deinit(digitalio_digitalinout_obj_t* self
} }
void common_hal_digitalio_digitalinout_switch_to_input( 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; self->output = false;
if (self->pin->gpio_number == 16) { 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( void common_hal_digitalio_digitalinout_switch_to_output(
digitalio_digitalinout_obj_t* self, bool value, digitalio_digitalinout_obj_t* self, bool value,
enum digitalio_drive_mode_t drive_mode) { digitalio_drive_mode_t drive_mode) {
self->output = true; self->output = true;
self->open_drain = drive_mode == DRIVE_MODE_OPEN_DRAIN; self->open_drain = drive_mode == DRIVE_MODE_OPEN_DRAIN;
if (self->pin->gpio_number == 16) { 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); 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) { digitalio_digitalinout_obj_t* self) {
return self->output? DIRECTION_OUTPUT : DIRECTION_INPUT; 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( void common_hal_digitalio_digitalinout_set_drive_mode(
digitalio_digitalinout_obj_t* self, 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); bool value = common_hal_digitalio_digitalinout_get_value(self);
self->open_drain = drive_mode == DRIVE_MODE_OPEN_DRAIN; self->open_drain = drive_mode == DRIVE_MODE_OPEN_DRAIN;
// True is implemented differently between modes so reset the value to make // 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) { digitalio_digitalinout_obj_t* self) {
if (self->open_drain) { if (self->open_drain) {
return DRIVE_MODE_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( 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) { if (pull == PULL_DOWN) {
nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError,
"ESP8266 does not support pull down.")); "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) { digitalio_digitalinout_obj_t* self) {
if (self->pin->gpio_number < 16 && if (self->pin->gpio_number < 16 &&
(READ_PERI_REG(self->pin->peripheral) & PERIPHS_IO_MUX_PULLUP) != 0) { (READ_PERI_REG(self->pin->peripheral) & PERIPHS_IO_MUX_PULLUP) != 0) {

View File

@ -24,9 +24,12 @@
* THE SOFTWARE. * THE SOFTWARE.
*/ */
#include "py/runtime.h"
#include "common-hal/microcontroller/Pin.h" #include "common-hal/microcontroller/Pin.h"
#include "common-hal/microcontroller/Processor.h" #include "common-hal/microcontroller/Processor.h"
#include "shared-bindings/microcontroller/__init__.h"
#include "shared-bindings/microcontroller/Pin.h" #include "shared-bindings/microcontroller/Pin.h"
#include "shared-bindings/microcontroller/Processor.h" #include "shared-bindings/microcontroller/Processor.h"
@ -34,6 +37,7 @@
#include "ets_alt_task.h" #include "ets_alt_task.h"
#include "etshal.h" #include "etshal.h"
#include "osapi.h" #include "osapi.h"
#include "user_interface.h"
#include "xtirq.h" #include "xtirq.h"
#define ETS_LOOP_ITER_BIT (12) #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)); 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 // The singleton microcontroller.Processor object, returned by microcontroller.cpu
// It currently only has properties, and no state. // 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 = { .base = {
.type = &mcu_processor_type, .type = &mcu_processor_type,
}, },

View File

@ -2,3 +2,6 @@
# $(MPY-TOOL) needs to know what kind of longint to use (if any) to freeze long integers. # $(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. # This should correspond to the MICROPY_LONGINT_IMPL definition in mpconfigport.h.
MPY_TOOL_LONGINT_IMPL = -mlongint-impl=mpz MPY_TOOL_LONGINT_IMPL = -mlongint-impl=mpz
INTERNAL_LIBM = (1)

View File

@ -86,6 +86,7 @@ def make_version_header(filename):
#define MICROPY_VERSION_MINOR (%s) #define MICROPY_VERSION_MINOR (%s)
#define MICROPY_VERSION_MICRO (%s) #define MICROPY_VERSION_MICRO (%s)
#define MICROPY_VERSION_STRING "%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"), """ % (git_tag, git_hash, datetime.date.today().strftime("%Y-%m-%d"),
ver[0].replace('v', ''), ver[1], ver[2], version_string) ver[0].replace('v', ''), ver[1], ver[2], version_string)

View File

@ -70,6 +70,7 @@ endif
MAKE_FROZEN = $(TOP)/tools/make-frozen.py MAKE_FROZEN = $(TOP)/tools/make-frozen.py
MPY_CROSS = $(TOP)/mpy-cross/mpy-cross MPY_CROSS = $(TOP)/mpy-cross/mpy-cross
MPY_TOOL = $(TOP)/tools/mpy-tool.py MPY_TOOL = $(TOP)/tools/mpy-tool.py
PREPROCESS_FROZEN_MODULES = PYTHONPATH=$(TOP)/tools/python-semver $(TOP)/tools/preprocess_frozen_modules.py
all: all:
.PHONY: all .PHONY: all

View File

@ -114,13 +114,13 @@ $(MPY_CROSS): $(TOP)/py/*.[ch] $(TOP)/mpy-cross/*.[ch] $(TOP)/ports/windows/fmod
$(Q)$(MAKE) -C $(TOP)/mpy-cross $(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). # 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. # 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) $(BUILD)/frozen_mpy: $(FROZEN_MPY_DIRS)
$(ECHO) FREEZE $(FROZEN_MPY_DIRS) $(ECHO) FREEZE $(FROZEN_MPY_DIRS)
$(Q)$(MKDIR) -p $@ $(Q)$(MKDIR) -p $@
$(Q)$(RSYNC) -rL --include="*/" --include='*.py' --exclude="*" $(addsuffix /*,$(FROZEN_MPY_DIRS)) $@ $(Q)$(PREPROCESS_FROZEN_MODULES) -o $@ $(FROZEN_MPY_DIRS)
$(Q)$(RM) -f $@/conf.py $@/setup.py
$(Q)$(CD) $@ && \ $(Q)$(CD) $@ && \
$(FIND) -L . -type f -name '*.py' | sed 's=^\./==' | \ $(FIND) -L . -type f -name '*.py' | sed 's=^\./==' | \
xargs -n1 $(abspath $(MPY_CROSS)) $(MPY_CROSS_FLAGS) xargs -n1 $(abspath $(MPY_CROSS)) $(MPY_CROSS_FLAGS)

View File

@ -1 +0,0 @@
# dummy file to work around readthedocs bug: https://github.com/rtfd/readthedocs.org/issues/2855

View File

@ -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 <py/runtime.h>
#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,
};

View File

@ -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

View File

@ -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 <py/runtime.h>
#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,
};

View File

@ -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

View File

@ -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,
};

View File

@ -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

View File

@ -28,6 +28,7 @@
#include "lib/utils/context_manager_helpers.h" #include "lib/utils/context_manager_helpers.h"
#include "py/binary.h" #include "py/binary.h"
#include "py/mphal.h"
#include "py/objproperty.h" #include "py/objproperty.h"
#include "py/runtime.h" #include "py/runtime.h"
#include "shared-bindings/microcontroller/Pin.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. //| 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 //| 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 //| 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 clock_pin: The pin to output the clock to
//| :param ~microcontroller.Pin data_pin: The pin to read the data from //| :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 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 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 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:: //| Record 8-bit unsigned samples to buffer::
//| //|
//| import audiobusio //| import audiobusio
@ -81,15 +87,19 @@
//| mic.record(b, len(b)) //| 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) { 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_t kw_args;
mp_map_init_fixed_table(&kw_args, n_kw, pos_args + n_args); mp_map_init_fixed_table(&kw_args, n_kw, pos_args + n_args);
static const mp_arg_t allowed_args[] = { static const mp_arg_t allowed_args[] = {
{ MP_QSTR_frequency, MP_ARG_INT, {.u_int = 8000} }, { MP_QSTR_frequency, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 16000} },
{ MP_QSTR_bit_depth, MP_ARG_INT, {.u_int = 8} }, { MP_QSTR_bit_depth, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 8} },
{ MP_QSTR_mono, MP_ARG_BOOL,{.u_bool = true} }, { MP_QSTR_mono, MP_ARG_KW_ONLY | MP_ARG_BOOL,{.u_bool = true} },
{ MP_QSTR_oversample, MP_ARG_INT, {.u_int = 64} }, { 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_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); mp_arg_parse_all(n_args - 2, pos_args + 2, &kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
@ -118,9 +128,19 @@ 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; 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, 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); 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 //| audio at the given rate. For internal flash, writing all 1s to the file
//| before recording is recommended to speed up writes. //| 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) { 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); audiobusio_pdmin_obj_t *self = MP_OBJ_TO_PTR(self_obj);
raise_error_if_deinited(common_hal_audiobusio_pdmin_deinited(self)); raise_error_if_deinited(common_hal_audiobusio_pdmin_deinited(self));
if (!MP_OBJ_IS_SMALL_INT(destination_length)) { if (!MP_OBJ_IS_SMALL_INT(destination_length) || MP_OBJ_SMALL_INT_VALUE(destination_length) < 0) {
mp_raise_TypeError("destination_length must be int"); mp_raise_TypeError("destination_length must be an int >= 0");
} }
uint32_t length = MP_OBJ_SMALL_INT_VALUE(destination_length); 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)) { if (MP_OBJ_IS_TYPE(destination, &fatfs_type_fileio)) {
mp_raise_NotImplementedError(""); mp_raise_NotImplementedError("");
} else if (mp_get_buffer(destination, &bufinfo, MP_BUFFER_WRITE)) { } else if (mp_get_buffer(destination, &bufinfo, MP_BUFFER_WRITE)) {
if (bufinfo.len < length) { if (bufinfo.len / mp_binary_get_size('@', bufinfo.typecode, NULL) < length) {
mp_raise_ValueError("Target buffer cannot hold destination_length bytes."); mp_raise_ValueError("Destination capacity is smaller than destination_length.");
} }
uint8_t bit_depth = common_hal_audiobusio_pdmin_get_bit_depth(self); uint8_t bit_depth = common_hal_audiobusio_pdmin_get_bit_depth(self);
if (bufinfo.typecode != 'H' && bit_depth == 16) { 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) { } 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"); 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 = uint32_t length_written =
common_hal_audiobusio_pdmin_record_to_buffer(self, bufinfo.buf, length); common_hal_audiobusio_pdmin_record_to_buffer(self, bufinfo.buf, length);
if (length_written != length) { return MP_OBJ_NEW_SMALL_INT(length_written);
mp_printf(&mp_plat_print, "length mismatch %d %d\n", length_written, length);
}
} }
return mp_const_none; return mp_const_none;
} }

View File

@ -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``. //| Read into ``buffer`` from the slave specified by ``address``.
//| The number of bytes read will be the length of ``buffer``. //| 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 //| If ``start`` or ``end`` is provided, then the buffer will be sliced
//| as if ``buffer[start:end]``. This will not cause an allocation like //| 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; int32_t start = args[ARG_start].u_int;
uint32_t length = bufinfo.len; uint32_t length = bufinfo.len;
normalize_buffer_bounds(&start, args[ARG_end].u_int, &length); 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, uint8_t status = shared_module_bitbangio_i2c_read(self,
args[ARG_address].u_int, args[ARG_address].u_int,
((uint8_t*)bufinfo.buf) + start, ((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 //| as if ``buffer[start:end]``. This will not cause an allocation like
//| ``buffer[start:end]`` will so it saves memory. //| ``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 int address: 7-bit device address
//| :param bytearray buffer: buffer containing the bytes to write //| :param bytearray buffer: buffer containing the bytes to write
//| :param int start: Index to start writing from //| :param int start: Index to start writing from

View File

@ -191,6 +191,7 @@ MP_DEFINE_CONST_FUN_OBJ_1(bitbangio_spi_unlock_obj, bitbangio_spi_obj_unlock);
//| .. method:: SPI.write(buf) //| .. method:: SPI.write(buf)
//| //|
//| Write the data contained in ``buf``. Requires the SPI being locked. //| 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. // 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) { 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)); raise_error_if_deinited(shared_module_bitbangio_spi_deinited(self));
mp_buffer_info_t src; mp_buffer_info_t src;
mp_get_buffer_raise(wr_buf, &src, MP_BUFFER_READ); mp_get_buffer_raise(wr_buf, &src, MP_BUFFER_READ);
if (src.len == 0) {
return mp_const_none;
}
check_lock(self); check_lock(self);
bool ok = shared_module_bitbangio_spi_write(self, src.buf, src.len); bool ok = shared_module_bitbangio_spi_write(self, src.buf, src.len);
if (!ok) { if (!ok) {
@ -210,7 +214,9 @@ MP_DEFINE_CONST_FUN_OBJ_2(bitbangio_spi_write_obj, bitbangio_spi_write);
//| .. method:: SPI.readinto(buf) //| .. 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. // 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) { 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)); raise_error_if_deinited(shared_module_bitbangio_spi_deinited(self));
mp_buffer_info_t bufinfo; mp_buffer_info_t bufinfo;
mp_get_buffer_raise(args[1], &bufinfo, MP_BUFFER_WRITE); mp_get_buffer_raise(args[1], &bufinfo, MP_BUFFER_WRITE);
if (bufinfo.len == 0) {
return mp_const_none;
}
check_lock(args[0]); check_lock(args[0]);
bool ok = shared_module_bitbangio_spi_read(self, bufinfo.buf, bufinfo.len); bool ok = shared_module_bitbangio_spi_read(self, bufinfo.buf, bufinfo.len);
if (!ok) { if (!ok) {

View File

@ -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``. //| Read into ``buffer`` from the slave specified by ``address``.
//| The number of bytes read will be the length of ``buffer``. //| 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 //| If ``start`` or ``end`` is provided, then the buffer will be sliced
//| as if ``buffer[start:end]``. This will not cause an allocation like //| 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; int32_t start = args[ARG_start].u_int;
uint32_t length = bufinfo.len; uint32_t length = bufinfo.len;
normalize_buffer_bounds(&start, args[ARG_end].u_int, &length); 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); uint8_t status = common_hal_busio_i2c_read(self, args[ARG_address].u_int, ((uint8_t*)bufinfo.buf) + start, length);
if (status != 0) { if (status != 0) {
mp_raise_OSError(status); 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 //| as if ``buffer[start:end]``. This will not cause an allocation like
//| ``buffer[start:end]`` will so it saves memory. //| ``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 int address: 7-bit device address
//| :param bytearray buffer: buffer containing the bytes to write //| :param bytearray buffer: buffer containing the bytes to write
//| :param int start: Index to start writing from //| :param int start: Index to start writing from

View File

@ -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)) //| .. 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 bytearray buffer: Write out the data in this buffer
//| :param int start: Index to start writing from //| :param int start: Start of the slice of ``buffer`` to write out: ``buffer[start:end]``
//| :param int end: Index to read up to but not include //| :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) { 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 }; 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; uint32_t length = bufinfo.len;
normalize_buffer_bounds(&start, args[ARG_end].u_int, &length); 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); bool ok = common_hal_busio_spi_write(self, ((uint8_t*)bufinfo.buf) + start, length);
if (!ok) { if (!ok) {
mp_raise_OSError(MP_EIO); 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) //| .. 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 bytearray buffer: Read data into this buffer
//| :param int start: Index to start writing at //| :param int start: Start of the slice of ``buffer`` to read into: ``buffer[start:end]``
//| :param int end: Index to write up to but not include //| :param int end: End of the slice; this index is not included
//| :param int write_value: Value to write reading. (Usually ignored.) //| :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) { 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 }; 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; uint32_t length = bufinfo.len;
normalize_buffer_bounds(&start, args[ARG_end].u_int, &length); 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); bool ok = common_hal_busio_spi_read(self, ((uint8_t*)bufinfo.buf) + start, length, args[ARG_write_value].u_int);
if (!ok) { if (!ok) {
mp_raise_OSError(MP_EIO); 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); 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[] = { 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_deinit), MP_ROM_PTR(&busio_spi_deinit_obj) },
{ MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___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_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), 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); STATIC MP_DEFINE_CONST_DICT(busio_spi_locals_dict, busio_spi_locals_dict_table);

View File

@ -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. // 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); 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 #endif // MICROPY_INCLUDED_SHARED_BINDINGS_BUSIO_SPI_H

View File

@ -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_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_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) { if (args[ARG_drive_mode].u_rom_obj == &digitalio_drive_mode_open_drain_obj) {
drive_mode = DRIVE_MODE_OPEN_DRAIN; 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_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_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) { if (args[ARG_pull].u_rom_obj == &digitalio_pull_up_obj) {
pull = PULL_UP; pull = PULL_UP;
}else if (args[ARG_pull].u_rom_obj == &digitalio_pull_down_obj) { }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) { 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); digitalio_digitalinout_obj_t *self = MP_OBJ_TO_PTR(self_in);
raise_error_if_deinited(common_hal_digitalio_digitalinout_deinited(self)); 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) { if (direction == DIRECTION_INPUT) {
return (mp_obj_t)&digitalio_direction_input_obj; 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."); mp_raise_AttributeError("Drive mode not used when direction is input.");
return mp_const_none; 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) { if (drive_mode == DRIVE_MODE_PUSH_PULL) {
return (mp_obj_t)&digitalio_drive_mode_push_pull_obj; 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."); mp_raise_AttributeError("Drive mode not used when direction is input.");
return mp_const_none; 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) { if (drive_mode == &digitalio_drive_mode_open_drain_obj) {
c_drive_mode = DRIVE_MODE_OPEN_DRAIN; 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."); mp_raise_AttributeError("Pull not used when direction is output.");
return mp_const_none; 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) { if (pull == PULL_UP) {
return (mp_obj_t)&digitalio_pull_up_obj; return (mp_obj_t)&digitalio_pull_up_obj;
} else if (pull == PULL_DOWN) { } 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."); mp_raise_AttributeError("Pull not used when direction is output.");
return mp_const_none; return mp_const_none;
} }
enum digitalio_pull_t pull = PULL_NONE; digitalio_pull_t pull = PULL_NONE;
if (pull_obj == &digitalio_pull_up_obj) { if (pull_obj == &digitalio_pull_up_obj) {
pull = PULL_UP; pull = PULL_UP;
} else if (pull_obj == &digitalio_pull_down_obj) { } else if (pull_obj == &digitalio_pull_down_obj) {

View File

@ -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); 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); void common_hal_digitalio_digitalinout_deinit(digitalio_digitalinout_obj_t* self);
bool common_hal_digitalio_digitalinout_deinited(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_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, enum digitalio_drive_mode_t drive_mode); void common_hal_digitalio_digitalinout_switch_to_output(digitalio_digitalinout_obj_t* self, bool value, digitalio_drive_mode_t drive_mode);
enum digitalio_direction_t common_hal_digitalio_digitalinout_get_direction(digitalio_digitalinout_obj_t* self); 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); 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); 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); void common_hal_digitalio_digitalinout_set_drive_mode(digitalio_digitalinout_obj_t* self, digitalio_drive_mode_t drive_mode);
enum digitalio_drive_mode_t common_hal_digitalio_digitalinout_get_drive_mode(digitalio_digitalinout_obj_t* self); 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); void common_hal_digitalio_digitalinout_set_pull(digitalio_digitalinout_obj_t* self, digitalio_pull_t pull);
enum digitalio_pull_t common_hal_digitalio_digitalinout_get_pull(digitalio_digitalinout_obj_t* self); digitalio_pull_t common_hal_digitalio_digitalinout_get_pull(digitalio_digitalinout_obj_t* self);
#endif // MICROPY_INCLUDED_SHARED_BINDINGS_DIGITALIO_DIGITALINOUT_H #endif // MICROPY_INCLUDED_SHARED_BINDINGS_DIGITALIO_DIGITALINOUT_H

View File

@ -29,10 +29,10 @@
#include "py/obj.h" #include "py/obj.h"
enum digitalio_direction_t { typedef enum {
DIRECTION_INPUT, DIRECTION_INPUT,
DIRECTION_OUTPUT DIRECTION_OUTPUT
}; } digitalio_direction_t;
typedef struct { typedef struct {
mp_obj_base_t base; mp_obj_base_t base;
} digitalio_direction_obj_t; } digitalio_direction_obj_t;

View File

@ -29,10 +29,10 @@
#include "py/obj.h" #include "py/obj.h"
enum digitalio_drive_mode_t { typedef enum {
DRIVE_MODE_PUSH_PULL, DRIVE_MODE_PUSH_PULL,
DRIVE_MODE_OPEN_DRAIN DRIVE_MODE_OPEN_DRAIN
}; } digitalio_drive_mode_t;
typedef struct { typedef struct {
mp_obj_base_t base; mp_obj_base_t base;

View File

@ -29,11 +29,11 @@
#include "py/obj.h" #include "py/obj.h"
enum digitalio_pull_t { typedef enum _digitalio_pull_t {
PULL_NONE, PULL_NONE,
PULL_UP, PULL_UP,
PULL_DOWN PULL_DOWN
}; } digitalio_pull_t;
const mp_obj_type_t digitalio_pull_type; const mp_obj_type_t digitalio_pull_type;

View File

@ -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,
};

View File

@ -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

View File

@ -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); 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 //| .. attribute:: nvm
//| //|
//| Available non-volatile memory. //| 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_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_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_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 #if CIRCUITPY_INTERNAL_NVM_SIZE > 0
{ MP_ROM_QSTR(MP_QSTR_nvm), MP_ROM_PTR(&common_hal_mcu_nvm_obj) }, { MP_ROM_QSTR(MP_QSTR_nvm), MP_ROM_PTR(&common_hal_mcu_nvm_obj) },
#else #else
{ MP_ROM_QSTR(MP_QSTR_nvm), MP_ROM_PTR(&mp_const_none_obj) }, { MP_ROM_QSTR(MP_QSTR_nvm), MP_ROM_PTR(&mp_const_none_obj) },
#endif #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_type) },
{ MP_ROM_QSTR(MP_QSTR_pin), MP_ROM_PTR(&mcu_pin_module) }, { MP_ROM_QSTR(MP_QSTR_pin), MP_ROM_PTR(&mcu_pin_module) },
{ MP_ROM_QSTR(MP_QSTR_Processor), MP_ROM_PTR(&mcu_processor_type) }, { MP_ROM_QSTR(MP_QSTR_Processor), MP_ROM_PTR(&mcu_processor_type) },

View File

@ -33,11 +33,16 @@
#include "common-hal/microcontroller/Processor.h" #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_delay_us(uint32_t);
extern void common_hal_mcu_disable_interrupts(void); extern void common_hal_mcu_disable_interrupts(void);
extern void common_hal_mcu_enable_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 mp_obj_dict_t mcu_pin_globals;
extern const mcu_processor_obj_t common_hal_mcu_processor_obj; extern const mcu_processor_obj_t common_hal_mcu_processor_obj;

View File

@ -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;
}

View File

@ -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 <stdint.h>
#include <stdbool.h>
#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

View File

@ -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;
}

View File

@ -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 <stdint.h>
#include <stdbool.h>
#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

View File

@ -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;
}

View File

@ -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 <stdint.h>
#include <stdbool.h>
#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

View File

@ -2,7 +2,7 @@ rm -rf ports/atmel-samd/build*
rm -rf ports/esp8266/build* rm -rf ports/esp8266/build*
rm -rf ports/nrf/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" ROSIE_SETUPS="rosie-ci"
PARALLEL="-j 5" PARALLEL="-j 5"

View File

@ -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)

1
tools/python-semver Submodule

@ -0,0 +1 @@
Subproject commit 2001c62d1a0361c44acc7076d8ce91e1d1c66141