From 011056af15f6107b9ef35fdf19a3f715b55f55d5 Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Tue, 11 Oct 2016 15:48:43 -0700 Subject: [PATCH] atmel-samd: Add support for SPI. Also separate out the ASF config headers that are shared across all boards. --- atmel-samd/Makefile | 2 + .../arduino_zero => asf_conf}/conf_clocks.h | 0 .../arduino_zero => asf_conf}/conf_sleepmgr.h | 0 .../conf_sleepmgr.h => asf_conf/conf_spi.h} | 14 +- .../arduino_zero => asf_conf}/user_board.h | 0 .../feather_m0_bluefruit_le/conf_clocks.h | 197 ----------------- .../feather_m0_bluefruit_le/conf_sleepmgr.h | 52 ----- .../feather_m0_bluefruit_le/user_board.h | 40 ---- .../boards/metro_m0_flash/conf_clocks.h | 197 ----------------- atmel-samd/boards/metro_m0_flash/pins.c | 2 +- atmel-samd/boards/metro_m0_flash/user_board.h | 40 ---- atmel-samd/common-hal/modules/machine.c | 60 ++++++ atmel-samd/common-hal/modules/machine_types.h | 6 + atmel-samd/modmachine.c | 1 + shared-bindings/modules/machine.c | 203 ++++++++++++++++-- shared-bindings/modules/machine.h | 12 ++ 16 files changed, 275 insertions(+), 551 deletions(-) rename atmel-samd/{boards/arduino_zero => asf_conf}/conf_clocks.h (100%) rename atmel-samd/{boards/arduino_zero => asf_conf}/conf_sleepmgr.h (100%) rename atmel-samd/{boards/metro_m0_flash/conf_sleepmgr.h => asf_conf/conf_spi.h} (86%) rename atmel-samd/{boards/arduino_zero => asf_conf}/user_board.h (100%) delete mode 100644 atmel-samd/boards/feather_m0_bluefruit_le/conf_clocks.h delete mode 100644 atmel-samd/boards/feather_m0_bluefruit_le/conf_sleepmgr.h delete mode 100644 atmel-samd/boards/feather_m0_bluefruit_le/user_board.h delete mode 100644 atmel-samd/boards/metro_m0_flash/conf_clocks.h delete mode 100644 atmel-samd/boards/metro_m0_flash/user_board.h diff --git a/atmel-samd/Makefile b/atmel-samd/Makefile index b8bdd2b1bf..b6396d2ed0 100644 --- a/atmel-samd/Makefile +++ b/atmel-samd/Makefile @@ -32,6 +32,7 @@ INC += -I.. INC += -I../lib/mp-readline INC += -I../lib/timeutils INC += -Icommon-hal/modules/ +INC += -Iasf_conf/ INC += -Iasf/common/boards/ INC += -Iasf/common/services/sleepmgr/ INC += -Iasf/common/services/storage/ctrl_access/ @@ -117,6 +118,7 @@ SRC_ASF = $(addprefix asf/sam0/,\ drivers/sercom/i2c/i2c_sam0/i2c_master.c \ drivers/sercom/sercom.c \ drivers/sercom/sercom_interrupt.c \ + drivers/sercom/spi/spi.c \ drivers/sercom/usart/usart.c \ drivers/sercom/usart/usart_interrupt.c \ drivers/system/clock/clock_samd21_r21_da/clock.c \ diff --git a/atmel-samd/boards/arduino_zero/conf_clocks.h b/atmel-samd/asf_conf/conf_clocks.h similarity index 100% rename from atmel-samd/boards/arduino_zero/conf_clocks.h rename to atmel-samd/asf_conf/conf_clocks.h diff --git a/atmel-samd/boards/arduino_zero/conf_sleepmgr.h b/atmel-samd/asf_conf/conf_sleepmgr.h similarity index 100% rename from atmel-samd/boards/arduino_zero/conf_sleepmgr.h rename to atmel-samd/asf_conf/conf_sleepmgr.h diff --git a/atmel-samd/boards/metro_m0_flash/conf_sleepmgr.h b/atmel-samd/asf_conf/conf_spi.h similarity index 86% rename from atmel-samd/boards/metro_m0_flash/conf_sleepmgr.h rename to atmel-samd/asf_conf/conf_spi.h index 281a360784..d093a58c5f 100644 --- a/atmel-samd/boards/metro_m0_flash/conf_sleepmgr.h +++ b/atmel-samd/asf_conf/conf_spi.h @@ -1,9 +1,9 @@ /** * \file * - * \brief Sleep manager configuration + * \brief SAM D21 SPI configuration * - * Copyright (c) 2014-2015 Atmel Corporation. All rights reserved. + * Copyright (C) 2013-2016 Atmel Corporation. All rights reserved. * * \asf_license_start * @@ -44,9 +44,11 @@ * Support and FAQ: visit Atmel Support */ -#ifndef CONF_SLEEPMGR_H_INCLUDED -#define CONF_SLEEPMGR_H_INCLUDED -#define CONFIG_SLEEPMGR_ENABLE +#ifndef CONF_SPI_H_INCLUDED +#define CONF_SPI_H_INCLUDED -#endif /* CONF_SLEEPMGR_H_INCLUDED */ +#define CONF_SPI_MASTER_ENABLE true +#define CONF_SPI_SLAVE_ENABLE false + +#endif /* CONF_SPI_H_INCLUDED */ diff --git a/atmel-samd/boards/arduino_zero/user_board.h b/atmel-samd/asf_conf/user_board.h similarity index 100% rename from atmel-samd/boards/arduino_zero/user_board.h rename to atmel-samd/asf_conf/user_board.h diff --git a/atmel-samd/boards/feather_m0_bluefruit_le/conf_clocks.h b/atmel-samd/boards/feather_m0_bluefruit_le/conf_clocks.h deleted file mode 100644 index 20ee967e2a..0000000000 --- a/atmel-samd/boards/feather_m0_bluefruit_le/conf_clocks.h +++ /dev/null @@ -1,197 +0,0 @@ -/** - * \file - * - * \brief SAM D21 Clock configuration - * - * Copyright (C) 2014-2015 Atmel Corporation. All rights reserved. - * - * \asf_license_start - * - * \page License - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * 3. The name of Atmel may not be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * 4. This software may only be redistributed and used in connection with an - * Atmel microcontroller product. - * - * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE - * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * \asf_license_stop - * - */ -/* - * Support and FAQ: visit Atmel Support - */ -#include - -#ifndef CONF_CLOCKS_H_INCLUDED -# define CONF_CLOCKS_H_INCLUDED - -/* System clock bus configuration */ -# define CONF_CLOCK_CPU_CLOCK_FAILURE_DETECT false -# define CONF_CLOCK_FLASH_WAIT_STATES 2 -# define CONF_CLOCK_CPU_DIVIDER SYSTEM_MAIN_CLOCK_DIV_1 -# define CONF_CLOCK_APBA_DIVIDER SYSTEM_MAIN_CLOCK_DIV_1 -# define CONF_CLOCK_APBB_DIVIDER SYSTEM_MAIN_CLOCK_DIV_1 -# define CONF_CLOCK_APBC_DIVIDER SYSTEM_MAIN_CLOCK_DIV_1 - -/* SYSTEM_CLOCK_SOURCE_OSC8M configuration - Internal 8MHz oscillator */ -# define CONF_CLOCK_OSC8M_PRESCALER SYSTEM_OSC8M_DIV_1 -# define CONF_CLOCK_OSC8M_ON_DEMAND true -# define CONF_CLOCK_OSC8M_RUN_IN_STANDBY false - -/* SYSTEM_CLOCK_SOURCE_XOSC configuration - External clock/oscillator */ -# define CONF_CLOCK_XOSC_ENABLE false -# define CONF_CLOCK_XOSC_EXTERNAL_CRYSTAL SYSTEM_CLOCK_EXTERNAL_CRYSTAL -# define CONF_CLOCK_XOSC_EXTERNAL_FREQUENCY 12000000UL -# define CONF_CLOCK_XOSC_STARTUP_TIME SYSTEM_XOSC_STARTUP_32768 -# define CONF_CLOCK_XOSC_AUTO_GAIN_CONTROL true -# define CONF_CLOCK_XOSC_ON_DEMAND true -# define CONF_CLOCK_XOSC_RUN_IN_STANDBY false - -/* SYSTEM_CLOCK_SOURCE_XOSC32K configuration - External 32KHz crystal/clock oscillator */ -# define CONF_CLOCK_XOSC32K_ENABLE true -# define CONF_CLOCK_XOSC32K_EXTERNAL_CRYSTAL SYSTEM_CLOCK_EXTERNAL_CRYSTAL -# define CONF_CLOCK_XOSC32K_STARTUP_TIME SYSTEM_XOSC32K_STARTUP_65536 -# define CONF_CLOCK_XOSC32K_AUTO_AMPLITUDE_CONTROL false -# define CONF_CLOCK_XOSC32K_ENABLE_1KHZ_OUPUT false -# define CONF_CLOCK_XOSC32K_ENABLE_32KHZ_OUTPUT true -# define CONF_CLOCK_XOSC32K_ON_DEMAND false -# define CONF_CLOCK_XOSC32K_RUN_IN_STANDBY true - -/* SYSTEM_CLOCK_SOURCE_OSC32K configuration - Internal 32KHz oscillator */ -# define CONF_CLOCK_OSC32K_ENABLE false -# define CONF_CLOCK_OSC32K_STARTUP_TIME SYSTEM_OSC32K_STARTUP_130 -# define CONF_CLOCK_OSC32K_ENABLE_1KHZ_OUTPUT true -# define CONF_CLOCK_OSC32K_ENABLE_32KHZ_OUTPUT true -# define CONF_CLOCK_OSC32K_ON_DEMAND true -# define CONF_CLOCK_OSC32K_RUN_IN_STANDBY false - -/* SYSTEM_CLOCK_SOURCE_DFLL configuration - Digital Frequency Locked Loop */ -# define CONF_CLOCK_DFLL_ENABLE true -# define CONF_CLOCK_DFLL_LOOP_MODE SYSTEM_CLOCK_DFLL_LOOP_MODE_CLOSED -# define CONF_CLOCK_DFLL_ON_DEMAND true - -/* DFLL open loop mode configuration */ -# define CONF_CLOCK_DFLL_FINE_VALUE (512) - -/* DFLL closed loop mode configuration */ -# define CONF_CLOCK_DFLL_SOURCE_GCLK_GENERATOR GCLK_GENERATOR_1 -# define CONF_CLOCK_DFLL_MULTIPLY_FACTOR (48000000 / 32768) -# define CONF_CLOCK_DFLL_QUICK_LOCK true -# define CONF_CLOCK_DFLL_TRACK_AFTER_FINE_LOCK true -# define CONF_CLOCK_DFLL_KEEP_LOCK_ON_WAKEUP true -# define CONF_CLOCK_DFLL_ENABLE_CHILL_CYCLE true -# define CONF_CLOCK_DFLL_MAX_COARSE_STEP_SIZE (0x1f / 4) -# define CONF_CLOCK_DFLL_MAX_FINE_STEP_SIZE (0xff / 4) - -/* SYSTEM_CLOCK_SOURCE_DPLL configuration - Digital Phase-Locked Loop */ -# define CONF_CLOCK_DPLL_ENABLE false -# define CONF_CLOCK_DPLL_ON_DEMAND true -# define CONF_CLOCK_DPLL_RUN_IN_STANDBY false -# define CONF_CLOCK_DPLL_LOCK_BYPASS false -# define CONF_CLOCK_DPLL_WAKE_UP_FAST false -# define CONF_CLOCK_DPLL_LOW_POWER_ENABLE false - -# define CONF_CLOCK_DPLL_LOCK_TIME SYSTEM_CLOCK_SOURCE_DPLL_LOCK_TIME_DEFAULT -# define CONF_CLOCK_DPLL_REFERENCE_CLOCK SYSTEM_CLOCK_SOURCE_DPLL_REFERENCE_CLOCK_XOSC32K -# define CONF_CLOCK_DPLL_FILTER SYSTEM_CLOCK_SOURCE_DPLL_FILTER_DEFAULT - -# define CONF_CLOCK_DPLL_REFERENCE_FREQUENCY 32768 -# define CONF_CLOCK_DPLL_REFERENCE_DIVIDER 1 -# define CONF_CLOCK_DPLL_OUTPUT_FREQUENCY 48000000 - -/* DPLL GCLK reference configuration */ -# define CONF_CLOCK_DPLL_REFERENCE_GCLK_GENERATOR GCLK_GENERATOR_1 -/* DPLL GCLK lock timer configuration */ -# define CONF_CLOCK_DPLL_LOCK_GCLK_GENERATOR GCLK_GENERATOR_1 - -/* Set this to true to configure the GCLK when running clocks_init. If set to - * false, none of the GCLK generators will be configured in clocks_init(). */ -# define CONF_CLOCK_CONFIGURE_GCLK true - -/* Configure GCLK generator 0 (Main Clock) */ -# define CONF_CLOCK_GCLK_0_ENABLE true -# define CONF_CLOCK_GCLK_0_RUN_IN_STANDBY true -# define CONF_CLOCK_GCLK_0_CLOCK_SOURCE SYSTEM_CLOCK_SOURCE_DFLL -# define CONF_CLOCK_GCLK_0_PRESCALER 1 -# define CONF_CLOCK_GCLK_0_OUTPUT_ENABLE false - -/* Configure GCLK generator 1 */ -# define CONF_CLOCK_GCLK_1_ENABLE true -# define CONF_CLOCK_GCLK_1_RUN_IN_STANDBY false -# define CONF_CLOCK_GCLK_1_CLOCK_SOURCE SYSTEM_CLOCK_SOURCE_XOSC32K -# define CONF_CLOCK_GCLK_1_PRESCALER 1 -# define CONF_CLOCK_GCLK_1_OUTPUT_ENABLE true - -/* Configure GCLK generator 2 (RTC) */ -# define CONF_CLOCK_GCLK_2_ENABLE false -# define CONF_CLOCK_GCLK_2_RUN_IN_STANDBY false -# define CONF_CLOCK_GCLK_2_CLOCK_SOURCE SYSTEM_CLOCK_SOURCE_OSC32K -# define CONF_CLOCK_GCLK_2_PRESCALER 32 -# define CONF_CLOCK_GCLK_2_OUTPUT_ENABLE false - -/* Configure GCLK generator 3 */ -# define CONF_CLOCK_GCLK_3_ENABLE true -# define CONF_CLOCK_GCLK_3_RUN_IN_STANDBY false -# define CONF_CLOCK_GCLK_3_CLOCK_SOURCE SYSTEM_CLOCK_SOURCE_OSC8M -# define CONF_CLOCK_GCLK_3_PRESCALER 1 -# define CONF_CLOCK_GCLK_3_OUTPUT_ENABLE false - -/* Configure GCLK generator 4 */ -# define CONF_CLOCK_GCLK_4_ENABLE false -# define CONF_CLOCK_GCLK_4_RUN_IN_STANDBY false -# define CONF_CLOCK_GCLK_4_CLOCK_SOURCE SYSTEM_CLOCK_SOURCE_OSC8M -# define CONF_CLOCK_GCLK_4_PRESCALER 1 -# define CONF_CLOCK_GCLK_4_OUTPUT_ENABLE false - -/* Configure GCLK generator 5 */ -# define CONF_CLOCK_GCLK_5_ENABLE false -# define CONF_CLOCK_GCLK_5_RUN_IN_STANDBY false -# define CONF_CLOCK_GCLK_5_CLOCK_SOURCE SYSTEM_CLOCK_SOURCE_OSC8M -# define CONF_CLOCK_GCLK_5_PRESCALER 1 -# define CONF_CLOCK_GCLK_5_OUTPUT_ENABLE false - -/* Configure GCLK generator 6 */ -# define CONF_CLOCK_GCLK_6_ENABLE false -# define CONF_CLOCK_GCLK_6_RUN_IN_STANDBY false -# define CONF_CLOCK_GCLK_6_CLOCK_SOURCE SYSTEM_CLOCK_SOURCE_OSC8M -# define CONF_CLOCK_GCLK_6_PRESCALER 1 -# define CONF_CLOCK_GCLK_6_OUTPUT_ENABLE false - -/* Configure GCLK generator 7 */ -# define CONF_CLOCK_GCLK_7_ENABLE false -# define CONF_CLOCK_GCLK_7_RUN_IN_STANDBY false -# define CONF_CLOCK_GCLK_7_CLOCK_SOURCE SYSTEM_CLOCK_SOURCE_OSC8M -# define CONF_CLOCK_GCLK_7_PRESCALER 1 -# define CONF_CLOCK_GCLK_7_OUTPUT_ENABLE false - -/* Configure GCLK generator 8 */ -# define CONF_CLOCK_GCLK_8_ENABLE false -# define CONF_CLOCK_GCLK_8_RUN_IN_STANDBY false -# define CONF_CLOCK_GCLK_8_CLOCK_SOURCE SYSTEM_CLOCK_SOURCE_OSC8M -# define CONF_CLOCK_GCLK_8_PRESCALER 1 -# define CONF_CLOCK_GCLK_8_OUTPUT_ENABLE false - -#endif /* CONF_CLOCKS_H_INCLUDED */ diff --git a/atmel-samd/boards/feather_m0_bluefruit_le/conf_sleepmgr.h b/atmel-samd/boards/feather_m0_bluefruit_le/conf_sleepmgr.h deleted file mode 100644 index 281a360784..0000000000 --- a/atmel-samd/boards/feather_m0_bluefruit_le/conf_sleepmgr.h +++ /dev/null @@ -1,52 +0,0 @@ -/** - * \file - * - * \brief Sleep manager configuration - * - * Copyright (c) 2014-2015 Atmel Corporation. All rights reserved. - * - * \asf_license_start - * - * \page License - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * 3. The name of Atmel may not be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * 4. This software may only be redistributed and used in connection with an - * Atmel microcontroller product. - * - * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE - * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * \asf_license_stop - * - */ -/* - * Support and FAQ: visit Atmel Support - */ - -#ifndef CONF_SLEEPMGR_H_INCLUDED -#define CONF_SLEEPMGR_H_INCLUDED - -#define CONFIG_SLEEPMGR_ENABLE - -#endif /* CONF_SLEEPMGR_H_INCLUDED */ diff --git a/atmel-samd/boards/feather_m0_bluefruit_le/user_board.h b/atmel-samd/boards/feather_m0_bluefruit_le/user_board.h deleted file mode 100644 index 39980a7d2e..0000000000 --- a/atmel-samd/boards/feather_m0_bluefruit_le/user_board.h +++ /dev/null @@ -1,40 +0,0 @@ -/** - * \file - * - * \brief User board definition template - * - */ - - /* This file is intended to contain definitions and configuration details for - * features and devices that are available on the board, e.g., frequency and - * startup time for an external crystal, external memory devices, LED and USART - * pins. - */ -/* - * Support and FAQ: visit Atmel Support - */ - -#ifndef USER_BOARD_H -#define USER_BOARD_H - -#include - -// External oscillator settings. -// Uncomment and set correct values if external oscillator is used. - -// External oscillator frequency -//#define BOARD_XOSC_HZ 8000000 - -// External oscillator type. -//!< External clock signal -//#define BOARD_XOSC_TYPE XOSC_TYPE_EXTERNAL -//!< 32.768 kHz resonator on TOSC -//#define BOARD_XOSC_TYPE XOSC_TYPE_32KHZ -//!< 0.4 to 16 MHz resonator on XTALS -//#define BOARD_XOSC_TYPE XOSC_TYPE_XTAL - -// External oscillator startup time -//#define BOARD_XOSC_STARTUP_US 500000 - - -#endif // USER_BOARD_H diff --git a/atmel-samd/boards/metro_m0_flash/conf_clocks.h b/atmel-samd/boards/metro_m0_flash/conf_clocks.h deleted file mode 100644 index 20ee967e2a..0000000000 --- a/atmel-samd/boards/metro_m0_flash/conf_clocks.h +++ /dev/null @@ -1,197 +0,0 @@ -/** - * \file - * - * \brief SAM D21 Clock configuration - * - * Copyright (C) 2014-2015 Atmel Corporation. All rights reserved. - * - * \asf_license_start - * - * \page License - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * 3. The name of Atmel may not be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * 4. This software may only be redistributed and used in connection with an - * Atmel microcontroller product. - * - * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE - * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * \asf_license_stop - * - */ -/* - * Support and FAQ: visit Atmel Support - */ -#include - -#ifndef CONF_CLOCKS_H_INCLUDED -# define CONF_CLOCKS_H_INCLUDED - -/* System clock bus configuration */ -# define CONF_CLOCK_CPU_CLOCK_FAILURE_DETECT false -# define CONF_CLOCK_FLASH_WAIT_STATES 2 -# define CONF_CLOCK_CPU_DIVIDER SYSTEM_MAIN_CLOCK_DIV_1 -# define CONF_CLOCK_APBA_DIVIDER SYSTEM_MAIN_CLOCK_DIV_1 -# define CONF_CLOCK_APBB_DIVIDER SYSTEM_MAIN_CLOCK_DIV_1 -# define CONF_CLOCK_APBC_DIVIDER SYSTEM_MAIN_CLOCK_DIV_1 - -/* SYSTEM_CLOCK_SOURCE_OSC8M configuration - Internal 8MHz oscillator */ -# define CONF_CLOCK_OSC8M_PRESCALER SYSTEM_OSC8M_DIV_1 -# define CONF_CLOCK_OSC8M_ON_DEMAND true -# define CONF_CLOCK_OSC8M_RUN_IN_STANDBY false - -/* SYSTEM_CLOCK_SOURCE_XOSC configuration - External clock/oscillator */ -# define CONF_CLOCK_XOSC_ENABLE false -# define CONF_CLOCK_XOSC_EXTERNAL_CRYSTAL SYSTEM_CLOCK_EXTERNAL_CRYSTAL -# define CONF_CLOCK_XOSC_EXTERNAL_FREQUENCY 12000000UL -# define CONF_CLOCK_XOSC_STARTUP_TIME SYSTEM_XOSC_STARTUP_32768 -# define CONF_CLOCK_XOSC_AUTO_GAIN_CONTROL true -# define CONF_CLOCK_XOSC_ON_DEMAND true -# define CONF_CLOCK_XOSC_RUN_IN_STANDBY false - -/* SYSTEM_CLOCK_SOURCE_XOSC32K configuration - External 32KHz crystal/clock oscillator */ -# define CONF_CLOCK_XOSC32K_ENABLE true -# define CONF_CLOCK_XOSC32K_EXTERNAL_CRYSTAL SYSTEM_CLOCK_EXTERNAL_CRYSTAL -# define CONF_CLOCK_XOSC32K_STARTUP_TIME SYSTEM_XOSC32K_STARTUP_65536 -# define CONF_CLOCK_XOSC32K_AUTO_AMPLITUDE_CONTROL false -# define CONF_CLOCK_XOSC32K_ENABLE_1KHZ_OUPUT false -# define CONF_CLOCK_XOSC32K_ENABLE_32KHZ_OUTPUT true -# define CONF_CLOCK_XOSC32K_ON_DEMAND false -# define CONF_CLOCK_XOSC32K_RUN_IN_STANDBY true - -/* SYSTEM_CLOCK_SOURCE_OSC32K configuration - Internal 32KHz oscillator */ -# define CONF_CLOCK_OSC32K_ENABLE false -# define CONF_CLOCK_OSC32K_STARTUP_TIME SYSTEM_OSC32K_STARTUP_130 -# define CONF_CLOCK_OSC32K_ENABLE_1KHZ_OUTPUT true -# define CONF_CLOCK_OSC32K_ENABLE_32KHZ_OUTPUT true -# define CONF_CLOCK_OSC32K_ON_DEMAND true -# define CONF_CLOCK_OSC32K_RUN_IN_STANDBY false - -/* SYSTEM_CLOCK_SOURCE_DFLL configuration - Digital Frequency Locked Loop */ -# define CONF_CLOCK_DFLL_ENABLE true -# define CONF_CLOCK_DFLL_LOOP_MODE SYSTEM_CLOCK_DFLL_LOOP_MODE_CLOSED -# define CONF_CLOCK_DFLL_ON_DEMAND true - -/* DFLL open loop mode configuration */ -# define CONF_CLOCK_DFLL_FINE_VALUE (512) - -/* DFLL closed loop mode configuration */ -# define CONF_CLOCK_DFLL_SOURCE_GCLK_GENERATOR GCLK_GENERATOR_1 -# define CONF_CLOCK_DFLL_MULTIPLY_FACTOR (48000000 / 32768) -# define CONF_CLOCK_DFLL_QUICK_LOCK true -# define CONF_CLOCK_DFLL_TRACK_AFTER_FINE_LOCK true -# define CONF_CLOCK_DFLL_KEEP_LOCK_ON_WAKEUP true -# define CONF_CLOCK_DFLL_ENABLE_CHILL_CYCLE true -# define CONF_CLOCK_DFLL_MAX_COARSE_STEP_SIZE (0x1f / 4) -# define CONF_CLOCK_DFLL_MAX_FINE_STEP_SIZE (0xff / 4) - -/* SYSTEM_CLOCK_SOURCE_DPLL configuration - Digital Phase-Locked Loop */ -# define CONF_CLOCK_DPLL_ENABLE false -# define CONF_CLOCK_DPLL_ON_DEMAND true -# define CONF_CLOCK_DPLL_RUN_IN_STANDBY false -# define CONF_CLOCK_DPLL_LOCK_BYPASS false -# define CONF_CLOCK_DPLL_WAKE_UP_FAST false -# define CONF_CLOCK_DPLL_LOW_POWER_ENABLE false - -# define CONF_CLOCK_DPLL_LOCK_TIME SYSTEM_CLOCK_SOURCE_DPLL_LOCK_TIME_DEFAULT -# define CONF_CLOCK_DPLL_REFERENCE_CLOCK SYSTEM_CLOCK_SOURCE_DPLL_REFERENCE_CLOCK_XOSC32K -# define CONF_CLOCK_DPLL_FILTER SYSTEM_CLOCK_SOURCE_DPLL_FILTER_DEFAULT - -# define CONF_CLOCK_DPLL_REFERENCE_FREQUENCY 32768 -# define CONF_CLOCK_DPLL_REFERENCE_DIVIDER 1 -# define CONF_CLOCK_DPLL_OUTPUT_FREQUENCY 48000000 - -/* DPLL GCLK reference configuration */ -# define CONF_CLOCK_DPLL_REFERENCE_GCLK_GENERATOR GCLK_GENERATOR_1 -/* DPLL GCLK lock timer configuration */ -# define CONF_CLOCK_DPLL_LOCK_GCLK_GENERATOR GCLK_GENERATOR_1 - -/* Set this to true to configure the GCLK when running clocks_init. If set to - * false, none of the GCLK generators will be configured in clocks_init(). */ -# define CONF_CLOCK_CONFIGURE_GCLK true - -/* Configure GCLK generator 0 (Main Clock) */ -# define CONF_CLOCK_GCLK_0_ENABLE true -# define CONF_CLOCK_GCLK_0_RUN_IN_STANDBY true -# define CONF_CLOCK_GCLK_0_CLOCK_SOURCE SYSTEM_CLOCK_SOURCE_DFLL -# define CONF_CLOCK_GCLK_0_PRESCALER 1 -# define CONF_CLOCK_GCLK_0_OUTPUT_ENABLE false - -/* Configure GCLK generator 1 */ -# define CONF_CLOCK_GCLK_1_ENABLE true -# define CONF_CLOCK_GCLK_1_RUN_IN_STANDBY false -# define CONF_CLOCK_GCLK_1_CLOCK_SOURCE SYSTEM_CLOCK_SOURCE_XOSC32K -# define CONF_CLOCK_GCLK_1_PRESCALER 1 -# define CONF_CLOCK_GCLK_1_OUTPUT_ENABLE true - -/* Configure GCLK generator 2 (RTC) */ -# define CONF_CLOCK_GCLK_2_ENABLE false -# define CONF_CLOCK_GCLK_2_RUN_IN_STANDBY false -# define CONF_CLOCK_GCLK_2_CLOCK_SOURCE SYSTEM_CLOCK_SOURCE_OSC32K -# define CONF_CLOCK_GCLK_2_PRESCALER 32 -# define CONF_CLOCK_GCLK_2_OUTPUT_ENABLE false - -/* Configure GCLK generator 3 */ -# define CONF_CLOCK_GCLK_3_ENABLE true -# define CONF_CLOCK_GCLK_3_RUN_IN_STANDBY false -# define CONF_CLOCK_GCLK_3_CLOCK_SOURCE SYSTEM_CLOCK_SOURCE_OSC8M -# define CONF_CLOCK_GCLK_3_PRESCALER 1 -# define CONF_CLOCK_GCLK_3_OUTPUT_ENABLE false - -/* Configure GCLK generator 4 */ -# define CONF_CLOCK_GCLK_4_ENABLE false -# define CONF_CLOCK_GCLK_4_RUN_IN_STANDBY false -# define CONF_CLOCK_GCLK_4_CLOCK_SOURCE SYSTEM_CLOCK_SOURCE_OSC8M -# define CONF_CLOCK_GCLK_4_PRESCALER 1 -# define CONF_CLOCK_GCLK_4_OUTPUT_ENABLE false - -/* Configure GCLK generator 5 */ -# define CONF_CLOCK_GCLK_5_ENABLE false -# define CONF_CLOCK_GCLK_5_RUN_IN_STANDBY false -# define CONF_CLOCK_GCLK_5_CLOCK_SOURCE SYSTEM_CLOCK_SOURCE_OSC8M -# define CONF_CLOCK_GCLK_5_PRESCALER 1 -# define CONF_CLOCK_GCLK_5_OUTPUT_ENABLE false - -/* Configure GCLK generator 6 */ -# define CONF_CLOCK_GCLK_6_ENABLE false -# define CONF_CLOCK_GCLK_6_RUN_IN_STANDBY false -# define CONF_CLOCK_GCLK_6_CLOCK_SOURCE SYSTEM_CLOCK_SOURCE_OSC8M -# define CONF_CLOCK_GCLK_6_PRESCALER 1 -# define CONF_CLOCK_GCLK_6_OUTPUT_ENABLE false - -/* Configure GCLK generator 7 */ -# define CONF_CLOCK_GCLK_7_ENABLE false -# define CONF_CLOCK_GCLK_7_RUN_IN_STANDBY false -# define CONF_CLOCK_GCLK_7_CLOCK_SOURCE SYSTEM_CLOCK_SOURCE_OSC8M -# define CONF_CLOCK_GCLK_7_PRESCALER 1 -# define CONF_CLOCK_GCLK_7_OUTPUT_ENABLE false - -/* Configure GCLK generator 8 */ -# define CONF_CLOCK_GCLK_8_ENABLE false -# define CONF_CLOCK_GCLK_8_RUN_IN_STANDBY false -# define CONF_CLOCK_GCLK_8_CLOCK_SOURCE SYSTEM_CLOCK_SOURCE_OSC8M -# define CONF_CLOCK_GCLK_8_PRESCALER 1 -# define CONF_CLOCK_GCLK_8_OUTPUT_ENABLE false - -#endif /* CONF_CLOCKS_H_INCLUDED */ diff --git a/atmel-samd/boards/metro_m0_flash/pins.c b/atmel-samd/boards/metro_m0_flash/pins.c index db0c6ee4c3..26754b4f49 100644 --- a/atmel-samd/boards/metro_m0_flash/pins.c +++ b/atmel-samd/boards/metro_m0_flash/pins.c @@ -121,7 +121,7 @@ PIN(PB10, false, NO_ADC_INPUT, PIN(PA12, false, NO_ADC_INPUT, TIMER(0, TCC2, 0, 0, PIN_PA12E_TCC2_WO0, MUX_PA12E_TCC2_WO0), TIMER(0, TCC0, 2, 6, PIN_PA12F_TCC0_WO6, MUX_PA12F_TCC0_WO6), - SERCOM(SERCOM4, 0, PINMUX_PA12D_SERCOM4_PAD0), + SERCOM(SERCOM4, 0, PINMUX_PA12D_SERCOM4_PAD0), SERCOM(SERCOM2, 0, PINMUX_PA12C_SERCOM2_PAD0)); PIN(PA13, false, NO_ADC_INPUT, TIMER(0, TCC2, 1, 1, PIN_PA13E_TCC2_WO1, MUX_PA13E_TCC2_WO1), diff --git a/atmel-samd/boards/metro_m0_flash/user_board.h b/atmel-samd/boards/metro_m0_flash/user_board.h deleted file mode 100644 index 39980a7d2e..0000000000 --- a/atmel-samd/boards/metro_m0_flash/user_board.h +++ /dev/null @@ -1,40 +0,0 @@ -/** - * \file - * - * \brief User board definition template - * - */ - - /* This file is intended to contain definitions and configuration details for - * features and devices that are available on the board, e.g., frequency and - * startup time for an external crystal, external memory devices, LED and USART - * pins. - */ -/* - * Support and FAQ: visit Atmel Support - */ - -#ifndef USER_BOARD_H -#define USER_BOARD_H - -#include - -// External oscillator settings. -// Uncomment and set correct values if external oscillator is used. - -// External oscillator frequency -//#define BOARD_XOSC_HZ 8000000 - -// External oscillator type. -//!< External clock signal -//#define BOARD_XOSC_TYPE XOSC_TYPE_EXTERNAL -//!< 32.768 kHz resonator on TOSC -//#define BOARD_XOSC_TYPE XOSC_TYPE_32KHZ -//!< 0.4 to 16 MHz resonator on XTALS -//#define BOARD_XOSC_TYPE XOSC_TYPE_XTAL - -// External oscillator startup time -//#define BOARD_XOSC_STARTUP_US 500000 - - -#endif // USER_BOARD_H diff --git a/atmel-samd/common-hal/modules/machine.c b/atmel-samd/common-hal/modules/machine.c index a43762e0f5..b0558cd5ce 100644 --- a/atmel-samd/common-hal/modules/machine.c +++ b/atmel-samd/common-hal/modules/machine.c @@ -205,3 +205,63 @@ void mp_hal_i2c_read_mem(machine_i2c_obj_t *self, uint8_t addr, uint16_t memaddr mp_hal_i2c_read(self, addr, dest, len); return; } + +void mp_hal_spi_construct(machine_spi_obj_t *self, const pin_obj_t * clock, + const pin_obj_t * mosi, const pin_obj_t * miso, + uint32_t baudrate) { + struct spi_config config_spi_master; + spi_get_config_defaults(&config_spi_master); + + // Depends on where MOSI and CLK are. + uint8_t dopo = 8; + if (clock->primary_sercom.pad == 1) { + if (mosi->primary_sercom.pad == 0) { + dopo = 0; + } else if (mosi->primary_sercom.pad == 3) { + dopo = 2; + } + } else if (clock->primary_sercom.pad == 3) { + if (mosi->primary_sercom.pad == 0) { + dopo = 3; + } else if (mosi->primary_sercom.pad == 2) { + dopo = 1; + } + } + if (dopo == 8) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "SPI MOSI and clock pins incompatible.")); + } + + config_spi_master.mux_setting = (dopo << SERCOM_SPI_CTRLA_DOPO_Pos) | + (miso->primary_sercom.pad << SERCOM_SPI_CTRLA_DIPO_Pos); + + // Map pad to pinmux through a short array. + uint32_t *pinmuxes[4] = {&config_spi_master.pinmux_pad0, + &config_spi_master.pinmux_pad1, + &config_spi_master.pinmux_pad2, + &config_spi_master.pinmux_pad3}; + *pinmuxes[clock->primary_sercom.pad] = clock->primary_sercom.pinmux; + *pinmuxes[mosi->primary_sercom.pad] = mosi->primary_sercom.pinmux; + *pinmuxes[miso->primary_sercom.pad] = miso->primary_sercom.pinmux; + + config_spi_master.mode_specific.master.baudrate = baudrate; + + spi_init(&self->spi_master_instance, mosi->primary_sercom.sercom, &config_spi_master); +} + +void mp_hal_spi_init(machine_spi_obj_t *self) { + spi_enable(&self->spi_master_instance); +} + +void mp_hal_spi_deinit(machine_spi_obj_t *self) { + spi_disable(&self->spi_master_instance); +} + +void mp_hal_spi_transfer(machine_spi_obj_t *self, size_t len, const uint8_t *src, + uint8_t *dest) { + // TODO(tannewt): Don't cast away the const. Change ASF to respect it instead. + enum status_code status = spi_transceive_buffer_wait( + &self->spi_master_instance, (uint8_t *) src, dest, len); + if (status != STATUS_OK) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "SPI bus error")); + } +} diff --git a/atmel-samd/common-hal/modules/machine_types.h b/atmel-samd/common-hal/modules/machine_types.h index 00fe998256..2267115d33 100644 --- a/atmel-samd/common-hal/modules/machine_types.h +++ b/atmel-samd/common-hal/modules/machine_types.h @@ -42,6 +42,7 @@ #include "asf/sam0/drivers/adc/adc_sam_d_r/adc_feature.h" #include "asf/sam0/drivers/sercom/i2c/i2c_master.h" +#include "asf/sam0/drivers/sercom/spi/spi.h" #include "py/obj.h" @@ -77,4 +78,9 @@ typedef struct _machine_i2c_obj_t { struct i2c_master_module i2c_master_instance; } machine_i2c_obj_t; +typedef struct _machine_spi_obj_t { + mp_obj_base_t base; + struct spi_module spi_master_instance; +} machine_spi_obj_t; + #endif // __MICROPY_INCLUDED_ATMEL_SAMD_API_MACHINE_TYPES_H__ diff --git a/atmel-samd/modmachine.c b/atmel-samd/modmachine.c index b09abac309..67bccc5fdc 100644 --- a/atmel-samd/modmachine.c +++ b/atmel-samd/modmachine.c @@ -50,6 +50,7 @@ STATIC const mp_rom_map_elem_t machine_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_Pin), MP_ROM_PTR(&pin_type) }, { MP_ROM_QSTR(MP_QSTR_PWM), MP_ROM_PTR(&pwm_type) }, { MP_ROM_QSTR(MP_QSTR_Flash), MP_ROM_PTR(&flash_type) }, + { MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&machine_spi_type) }, }; STATIC MP_DEFINE_CONST_DICT(machine_module_globals, machine_module_globals_table); diff --git a/shared-bindings/modules/machine.c b/shared-bindings/modules/machine.c index 46ef7d92e7..b16ab8aae8 100644 --- a/shared-bindings/modules/machine.c +++ b/shared-bindings/modules/machine.c @@ -45,8 +45,19 @@ //| //| I2C objects are created attached to a specific bus. They can be initialised //| when created, or initialised later on. - -STATIC void machine_i2c_obj_init_helper(machine_i2c_obj_t *self, mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { +//| +//| Constructors +//| ------------ +//| .. class:: I2C(scl, sda, \*, freq=400000) +//| +//| Construct and return a new I2C object. +//| See the init method below for a description of the arguments. +STATIC mp_obj_t machine_i2c_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *pos_args) { + mp_arg_check_num(n_args, n_kw, 0, MP_OBJ_FUN_ARGS_MAX, true); + machine_i2c_obj_t *self = m_new_obj(machine_i2c_obj_t); + self->base.type = &machine_i2c_type; + mp_map_t kw_args; + mp_map_init_fixed_table(&kw_args, n_kw, pos_args + n_args); enum { ARG_scl, ARG_sda, ARG_freq }; static const mp_arg_t allowed_args[] = { { MP_QSTR_scl, MP_ARG_REQUIRED | MP_ARG_OBJ }, @@ -54,26 +65,11 @@ STATIC void machine_i2c_obj_init_helper(machine_i2c_obj_t *self, mp_uint_t n_arg { MP_QSTR_freq, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 400000} }, }; mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + mp_arg_parse_all(n_args, pos_args, &kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); // TODO(tannewt): Replace pin_find with a unified version. const pin_obj_t* scl = pin_find(args[ARG_scl].u_obj); const pin_obj_t* sda = pin_find(args[ARG_sda].u_obj); mp_hal_i2c_construct(self, scl, sda, args[ARG_freq].u_int); -} - -//| Constructors -//| ------------ -//| .. class:: I2C(scl, sda, \*, freq=400000) -//| -//| Construct and return a new I2C object. -//| See the init method below for a description of the arguments. -STATIC mp_obj_t machine_i2c_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, 0, MP_OBJ_FUN_ARGS_MAX, true); - machine_i2c_obj_t *self = m_new_obj(machine_i2c_obj_t); - self->base.type = &machine_i2c_type; - mp_map_t kw_args; - mp_map_init_fixed_table(&kw_args, n_kw, args + n_args); - machine_i2c_obj_init_helper(self, n_args, args, &kw_args); return (mp_obj_t)self; } @@ -281,6 +277,7 @@ STATIC const mp_rom_map_elem_t machine_i2c_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_writeto), MP_ROM_PTR(&machine_i2c_writeto_obj) }, // memory operations + // TODO(tannewt): Move these into a separate loadable Python module. { MP_ROM_QSTR(MP_QSTR_readfrom_mem), MP_ROM_PTR(&machine_i2c_readfrom_mem_obj) }, { MP_ROM_QSTR(MP_QSTR_readfrom_mem_into), MP_ROM_PTR(&machine_i2c_readfrom_mem_into_obj) }, { MP_ROM_QSTR(MP_QSTR_writeto_mem), MP_ROM_PTR(&machine_i2c_writeto_mem_obj) }, @@ -294,3 +291,173 @@ const mp_obj_type_t machine_i2c_type = { .make_new = machine_i2c_make_new, .locals_dict = (mp_obj_dict_t*)&machine_i2c_locals_dict, }; + +//| class SPI -- a master-driven serial protocol +//| ============================================ +//| +//| SPI is a serial protocol that is driven by a master. This class only +//| manages three of the four SPI lines: SCK, MOSI, MISO. Its up to the client +//| to manage the appropriate slave select line. +//| +//| Constructors +//| ------------ +//| +//| .. class:: SPI(clock, MOSI, MISO, baudrate=1000000) +//| +//| Construct an SPI object on the given bus. ``id`` can be only 0. +//| With no additional parameters, the SPI object is created but not +//| initialised (it has the settings from the last initialisation of +//| the bus, if any). If extra arguments are given, the bus is initialised. +//| See ``init`` for parameters of initialisation. +//| +//| - ``clock`` is the pin to use for the clock. +//| - ``MOSI`` is the Master Out Slave In pin. +//| - ``MISO`` is the Master In Slave Out pin. +//| - ``baudrate`` is the SCK clock rate. +//| +//| Methods +//| ------- +//| + +// TODO(tannewt): Support LSB SPI. +// TODO(tannewt): Support phase, polarity and bit order. +STATIC mp_obj_t machine_spi_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *pos_args) { + mp_arg_check_num(n_args, n_kw, 0, MP_OBJ_FUN_ARGS_MAX, true); + machine_spi_obj_t *self = m_new_obj(machine_spi_obj_t); + self->base.type = &machine_spi_type; + mp_map_t kw_args; + mp_map_init_fixed_table(&kw_args, n_kw, pos_args + n_args); + enum { ARG_clock, ARG_MOSI, ARG_MISO, ARG_baudrate, ARG_polarity, ARG_phase, ARG_bits, ARG_firstbit }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_clock, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_MOSI, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_MISO, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_baudrate, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 100000} }, + { MP_QSTR_polarity, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 400000} }, + { MP_QSTR_phase, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 400000} }, + { MP_QSTR_bits, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 8} }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, &kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + // TODO(tannewt): Replace pin_find with a unified version. + const pin_obj_t* clock = pin_find(args[ARG_clock].u_obj); + const pin_obj_t* mosi = pin_find(args[ARG_MOSI].u_obj); + const pin_obj_t* miso = pin_find(args[ARG_MISO].u_obj); + mp_hal_spi_construct(self, clock, mosi, miso, args[ARG_baudrate].u_int); + return (mp_obj_t)self; +} + +//| .. method:: SPI.init() +//| +//| Initialises the bus. +STATIC mp_obj_t machine_spi_obj_init(mp_obj_t self_in) { + machine_spi_obj_t *self = MP_OBJ_TO_PTR(self_in); + mp_hal_spi_init(self); + return self_in; +} +MP_DEFINE_CONST_FUN_OBJ_1(machine_spi_init_obj, machine_spi_obj_init); + +//| .. method:: SPI.deinit() +//| +//| Turn off the SPI bus. +STATIC mp_obj_t machine_spi_obj_deinit(mp_obj_t self_in) { + machine_spi_obj_t *self = MP_OBJ_TO_PTR(self_in); + mp_hal_spi_deinit(self); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_1(machine_spi_deinit_obj, machine_spi_obj_deinit); + +STATIC mp_obj_t machine_spi_obj___exit__(size_t n_args, const mp_obj_t *args) { + (void)n_args; + mp_hal_spi_deinit(args[0]); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_spi_obj___exit___obj, 4, 4, machine_spi_obj___exit__); + +//| .. method:: SPI.write_readinto(write_buf, read_buf) +//| +//| Write from ``write_buf`` and read into ``read_buf``. Both buffers must have the +//| same length. This is the same as a SPI transfer function on other platforms. +//| Returns the number of bytes written +STATIC mp_obj_t mp_machine_spi_write_readinto(mp_obj_t self_in, mp_obj_t wr_buf, mp_obj_t rd_buf) { + mp_buffer_info_t src; + mp_get_buffer_raise(wr_buf, &src, MP_BUFFER_READ); + mp_buffer_info_t dest; + mp_get_buffer_raise(rd_buf, &dest, MP_BUFFER_WRITE); + if (src.len != dest.len) { + mp_raise_ValueError("buffers must be the same length"); + } + machine_spi_obj_t *self = MP_OBJ_TO_PTR(self_in); + mp_hal_spi_transfer(self, src.len, (uint8_t *) src.buf, (uint8_t *) dest.buf); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_3(mp_machine_spi_write_readinto_obj, mp_machine_spi_write_readinto); + +//| Helper operations +//| ----------------- +//| The below operations are finer grained operations based upon ``SPI.write_readinto``. +//| They may be moved out of the core module later. +//| +//| .. method:: SPI.write(buf) +//| +//| Write the data contained in ``buf``. +//| Returns the number of bytes written. +STATIC mp_obj_t mp_machine_spi_write(mp_obj_t self_in, mp_obj_t wr_buf) { + mp_buffer_info_t src; + mp_get_buffer_raise(wr_buf, &src, MP_BUFFER_READ); + machine_spi_obj_t *self = MP_OBJ_TO_PTR(self_in); + mp_hal_spi_transfer(self, src.len, (uint8_t *) src.buf, NULL); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_2(mp_machine_spi_write_obj, mp_machine_spi_write); + +//| .. method:: SPI.read(nbytes, *, write=0x00) +//| +//| Read the ``nbytes`` while writing the data specified by ``write``. +//| Return the number of bytes read. +STATIC mp_obj_t mp_machine_spi_read(size_t n_args, const mp_obj_t *args) { + vstr_t vstr; + vstr_init_len(&vstr, mp_obj_get_int(args[1])); + memset(vstr.buf, n_args == 3 ? mp_obj_get_int(args[2]) : 0, vstr.len); + mp_hal_spi_transfer(args[0], vstr.len, (uint8_t *) vstr.buf, (uint8_t *) vstr.buf); + return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr); +} +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_machine_spi_read_obj, 2, 3, mp_machine_spi_read); + +//| .. method:: SPI.readinto(buf, *, write=0x00) +//| +//| Read into the buffer specified by ``buf`` while writing the data specified by +//| ``write``. +//| Return the number of bytes read. +STATIC mp_obj_t mp_machine_spi_readinto(size_t n_args, const mp_obj_t *args) { + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(args[1], &bufinfo, MP_BUFFER_WRITE); + memset(bufinfo.buf, n_args == 3 ? mp_obj_get_int(args[2]) : 0, bufinfo.len); + mp_hal_spi_transfer(args[0], bufinfo.len, (uint8_t *) bufinfo.buf, (uint8_t *) bufinfo.buf); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_machine_spi_readinto_obj, 2, 3, mp_machine_spi_readinto); + +STATIC const mp_rom_map_elem_t machine_spi_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&machine_spi_init_obj) }, + { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&machine_spi_deinit_obj) }, + { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&machine_spi_init_obj) }, + { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&machine_spi_obj___exit___obj) }, + + // Standard simultaneous read/write transfer. + { MP_ROM_QSTR(MP_QSTR_write_readinto), MP_ROM_PTR(&mp_machine_spi_write_readinto_obj) }, + + // Helper methods. + // TODO(tannewt): Move these into a helper Python class. + { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_machine_spi_read_obj) }, + { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_machine_spi_readinto_obj) }, + { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_machine_spi_write_obj) }, +}; +STATIC MP_DEFINE_CONST_DICT(machine_spi_locals_dict, machine_spi_locals_dict_table); + +const mp_obj_type_t machine_spi_type = { + { &mp_type_type }, + .name = MP_QSTR_SPI, + .make_new = machine_spi_make_new, + .locals_dict = (mp_obj_dict_t*)&machine_spi_locals_dict, +}; diff --git a/shared-bindings/modules/machine.h b/shared-bindings/modules/machine.h index 66b0ae4656..a3f8a4a0c8 100644 --- a/shared-bindings/modules/machine.h +++ b/shared-bindings/modules/machine.h @@ -49,6 +49,7 @@ // Type object used in Python. Should be shared between ports. extern const mp_obj_type_t machine_i2c_type; +extern const mp_obj_type_t machine_spi_type; // Initializes the hardware peripheral. extern void mp_hal_i2c_construct(machine_i2c_obj_t *self, const pin_obj_t * scl, @@ -76,5 +77,16 @@ extern void mp_hal_i2c_write_mem(machine_i2c_obj_t *self, uint8_t addr, uint16_t memaddr, const uint8_t *src, size_t len); +// Construct an underlying SPI object. +extern void mp_hal_spi_construct(machine_spi_obj_t *self, const pin_obj_t * clock, + const pin_obj_t * mosi, const pin_obj_t * miso, + uint32_t baudrate); + +extern void mp_hal_spi_init(machine_spi_obj_t *self); +extern void mp_hal_spi_deinit(machine_spi_obj_t *self); + +// Concurrently write and read len bytes from the SPI port. Chip select is +// handled externally. +extern void mp_hal_spi_transfer(machine_spi_obj_t *self, size_t len, const uint8_t *src, uint8_t *dest); #endif // __MICROPY_INCLUDED_API_MACHINE_H__