From fc9c0ba5731a7eb1188366841a9a564074e7052f Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Wed, 17 Jun 2020 13:45:21 -0700 Subject: [PATCH] Initial SPI implementation. Almost certainly doesn't compile --- .../espressif_saola_1_wroom/mpconfigboard.mk | 2 - .../boards/unexpectedmaker_feathers2/board.c | 56 ++++ .../unexpectedmaker_feathers2/mpconfigboard.h | 36 +++ .../mpconfigboard.mk | 21 ++ .../boards/unexpectedmaker_feathers2/pins.c | 57 ++++ .../unexpectedmaker_feathers2/sdkconfig | 0 ports/esp32s2/common-hal/busio/I2C.c | 4 +- ports/esp32s2/common-hal/busio/SPI.c | 282 +++++++++++------- ports/esp32s2/common-hal/busio/SPI.h | 12 +- ports/esp32s2/common-hal/busio/UART.c | 8 +- .../esp32s2/common-hal/microcontroller/Pin.c | 5 +- .../esp32s2/common-hal/microcontroller/Pin.h | 5 +- 12 files changed, 366 insertions(+), 122 deletions(-) create mode 100644 ports/esp32s2/boards/unexpectedmaker_feathers2/board.c create mode 100644 ports/esp32s2/boards/unexpectedmaker_feathers2/mpconfigboard.h create mode 100644 ports/esp32s2/boards/unexpectedmaker_feathers2/mpconfigboard.mk create mode 100644 ports/esp32s2/boards/unexpectedmaker_feathers2/pins.c create mode 100644 ports/esp32s2/boards/unexpectedmaker_feathers2/sdkconfig diff --git a/ports/esp32s2/boards/espressif_saola_1_wroom/mpconfigboard.mk b/ports/esp32s2/boards/espressif_saola_1_wroom/mpconfigboard.mk index cd27356153..94e3b60f2d 100644 --- a/ports/esp32s2/boards/espressif_saola_1_wroom/mpconfigboard.mk +++ b/ports/esp32s2/boards/espressif_saola_1_wroom/mpconfigboard.mk @@ -12,8 +12,6 @@ LONGINT_IMPL = MPZ CFLAGS += -DCFG_TUD_TASK_QUEUE_SZ=32 CIRCUITPY_NEOPIXEL_WRITE = 0 -CIRCUITPY_DIGITALIO = 0 -CIRCUITPY_MICROCONTROLLER = 0 CIRCUITPY_ESP_FLASH_MODE=dio CIRCUITPY_ESP_FLASH_FREQ=40m diff --git a/ports/esp32s2/boards/unexpectedmaker_feathers2/board.c b/ports/esp32s2/boards/unexpectedmaker_feathers2/board.c new file mode 100644 index 0000000000..8890ec4c16 --- /dev/null +++ b/ports/esp32s2/boards/unexpectedmaker_feathers2/board.c @@ -0,0 +1,56 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Scott Shawcroft for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "boards/board.h" +#include "mpconfigboard.h" +#include "shared-bindings/microcontroller/Pin.h" + +void board_init(void) { + // USB + never_reset_pin(&pin_GPIO19); + never_reset_pin(&pin_GPIO20); + + // Debug UART + never_reset_pin(&pin_GPIO43); + never_reset_pin(&pin_GPIO44); + + // SPI Flash and RAM + never_reset_pin(&pin_GPIO26); + never_reset_pin(&pin_GPIO27); + never_reset_pin(&pin_GPIO28); + never_reset_pin(&pin_GPIO29); + never_reset_pin(&pin_GPIO30); + never_reset_pin(&pin_GPIO31); + never_reset_pin(&pin_GPIO32); +} + +bool board_requests_safe_mode(void) { + return false; +} + +void reset_board(void) { + +} diff --git a/ports/esp32s2/boards/unexpectedmaker_feathers2/mpconfigboard.h b/ports/esp32s2/boards/unexpectedmaker_feathers2/mpconfigboard.h new file mode 100644 index 0000000000..93fb0c573d --- /dev/null +++ b/ports/esp32s2/boards/unexpectedmaker_feathers2/mpconfigboard.h @@ -0,0 +1,36 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 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. + */ + +//Micropython setup + +#define MICROPY_HW_BOARD_NAME "FeatherS2" +#define MICROPY_HW_MCU_NAME "ESP32S2" + +#define AUTORESET_DELAY_MS 500 + +// Doesn't work with this on. +// #define MICROPY_HW_APA102_MOSI (&pin_GPIO44) +// #define MICROPY_HW_APA102_SCK (&pin_GPIO45) diff --git a/ports/esp32s2/boards/unexpectedmaker_feathers2/mpconfigboard.mk b/ports/esp32s2/boards/unexpectedmaker_feathers2/mpconfigboard.mk new file mode 100644 index 0000000000..ea3484d2fa --- /dev/null +++ b/ports/esp32s2/boards/unexpectedmaker_feathers2/mpconfigboard.mk @@ -0,0 +1,21 @@ +USB_VID = 0x239A +USB_PID = 0x80AC +USB_PRODUCT = "FeatherS2" +USB_MANUFACTURER = "UnexpectedMaker" +USB_DEVICES = "CDC,MSC,HID" + + +INTERNAL_FLASH_FILESYSTEM = 1 +LONGINT_IMPL = MPZ + +# The default queue depth of 16 overflows on release builds, +# so increase it to 32. +CFLAGS += -DCFG_TUD_TASK_QUEUE_SZ=32 + +CIRCUITPY_NEOPIXEL_WRITE = 0 + +CIRCUITPY_ESP_FLASH_MODE=qio +CIRCUITPY_ESP_FLASH_FREQ=40m +CIRCUITPY_ESP_FLASH_SIZE=16MB + +CIRCUITPY_BITBANG_APA102 = 1 diff --git a/ports/esp32s2/boards/unexpectedmaker_feathers2/pins.c b/ports/esp32s2/boards/unexpectedmaker_feathers2/pins.c new file mode 100644 index 0000000000..e8dd2edf6a --- /dev/null +++ b/ports/esp32s2/boards/unexpectedmaker_feathers2/pins.c @@ -0,0 +1,57 @@ +#include "shared-bindings/board/__init__.h" + +STATIC const mp_rom_map_elem_t board_global_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_A0), MP_ROM_PTR(&pin_GPIO17) }, + { MP_ROM_QSTR(MP_QSTR_D14), MP_ROM_PTR(&pin_GPIO17) }, + + { MP_ROM_QSTR(MP_QSTR_A1), MP_ROM_PTR(&pin_GPIO18) }, + { MP_ROM_QSTR(MP_QSTR_D15), MP_ROM_PTR(&pin_GPIO18) }, + + { MP_ROM_QSTR(MP_QSTR_A2), MP_ROM_PTR(&pin_GPIO14) }, + { MP_ROM_QSTR(MP_QSTR_D16), MP_ROM_PTR(&pin_GPIO14) }, + + { MP_ROM_QSTR(MP_QSTR_A3), MP_ROM_PTR(&pin_GPIO12) }, + { MP_ROM_QSTR(MP_QSTR_D17), MP_ROM_PTR(&pin_GPIO12) }, + + { MP_ROM_QSTR(MP_QSTR_A4), MP_ROM_PTR(&pin_GPIO6) }, + { MP_ROM_QSTR(MP_QSTR_D18), MP_ROM_PTR(&pin_GPIO6) }, + + { MP_ROM_QSTR(MP_QSTR_A5), MP_ROM_PTR(&pin_GPIO5) }, + { MP_ROM_QSTR(MP_QSTR_D19), MP_ROM_PTR(&pin_GPIO5) }, + + { MP_ROM_QSTR(MP_QSTR_SCK), MP_ROM_PTR(&pin_GPIO36) }, + { MP_ROM_QSTR(MP_QSTR_D25), MP_ROM_PTR(&pin_GPIO36) }, + + { MP_ROM_QSTR(MP_QSTR_MOSI), MP_ROM_PTR(&pin_GPIO35) }, + { MP_ROM_QSTR(MP_QSTR_D24), MP_ROM_PTR(&pin_GPIO35) }, + + { MP_ROM_QSTR(MP_QSTR_MISO), MP_ROM_PTR(&pin_GPIO37) }, + { MP_ROM_QSTR(MP_QSTR_D23), MP_ROM_PTR(&pin_GPIO37) }, + + { MP_ROM_QSTR(MP_QSTR_D0), MP_ROM_PTR(&pin_GPIO44) }, + { MP_ROM_QSTR(MP_QSTR_RX), MP_ROM_PTR(&pin_GPIO44) }, + + { MP_ROM_QSTR(MP_QSTR_D1), MP_ROM_PTR(&pin_GPIO43) }, + { MP_ROM_QSTR(MP_QSTR_TX), MP_ROM_PTR(&pin_GPIO43) }, + + // Moving to 9 and 8 + { MP_ROM_QSTR(MP_QSTR_SDA), MP_ROM_PTR(&pin_GPIO38) }, + { MP_ROM_QSTR(MP_QSTR_SCL), MP_ROM_PTR(&pin_GPIO33) }, + { MP_ROM_QSTR(MP_QSTR_D5), MP_ROM_PTR(&pin_GPIO1) }, + { MP_ROM_QSTR(MP_QSTR_D6), MP_ROM_PTR(&pin_GPIO3) }, + { MP_ROM_QSTR(MP_QSTR_D9), MP_ROM_PTR(&pin_GPIO7) }, + { MP_ROM_QSTR(MP_QSTR_D10), MP_ROM_PTR(&pin_GPIO8) }, + { MP_ROM_QSTR(MP_QSTR_D11), MP_ROM_PTR(&pin_GPIO9) }, + { MP_ROM_QSTR(MP_QSTR_D12), MP_ROM_PTR(&pin_GPIO10) }, + { MP_ROM_QSTR(MP_QSTR_D13), MP_ROM_PTR(&pin_GPIO11) }, + + { MP_ROM_QSTR(MP_QSTR_APA102_MOSI), MP_ROM_PTR(&pin_GPIO44) }, // MTDO + { MP_ROM_QSTR(MP_QSTR_APA102_SCK), MP_ROM_PTR(&pin_GPIO45) }, + + { MP_ROM_QSTR(MP_QSTR_LED), MP_ROM_PTR(&pin_GPIO13) }, + + { MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&board_i2c_obj) }, + { MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&board_spi_obj) }, + { MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&board_uart_obj) }, +}; +MP_DEFINE_CONST_DICT(board_module_globals, board_global_dict_table); diff --git a/ports/esp32s2/boards/unexpectedmaker_feathers2/sdkconfig b/ports/esp32s2/boards/unexpectedmaker_feathers2/sdkconfig new file mode 100644 index 0000000000..e69de29bb2 diff --git a/ports/esp32s2/common-hal/busio/I2C.c b/ports/esp32s2/common-hal/busio/I2C.c index fd983619ff..51817c95e2 100644 --- a/ports/esp32s2/common-hal/busio/I2C.c +++ b/ports/esp32s2/common-hal/busio/I2C.c @@ -143,8 +143,8 @@ void common_hal_busio_i2c_deinit(busio_i2c_obj_t *self) { i2c_driver_delete(self->i2c_num); i2c_status[self->i2c_num] = STATUS_FREE; - reset_pin(self->sda_pin); - reset_pin(self->scl_pin); + common_hal_reset_pin(self->sda_pin); + common_hal_reset_pin(self->scl_pin); self->sda_pin = NULL; self->scl_pin = NULL; } diff --git a/ports/esp32s2/common-hal/busio/SPI.c b/ports/esp32s2/common-hal/busio/SPI.c index e761eb49be..92a3dd4436 100644 --- a/ports/esp32s2/common-hal/busio/SPI.c +++ b/ports/esp32s2/common-hal/busio/SPI.c @@ -32,84 +32,141 @@ #include "common-hal/microcontroller/Pin.h" #include "supervisor/shared/rgb_led_status.h" -void spi_reset(void) { +static bool spi_never_reset[SOC_SPI_PERIPH_NUM]; +void spi_reset(void) { + for (spi_host_device_t host_id = SPI2_HOST; host_id < SOC_SPI_PERIPH_NUM; host_id++) { + if (spi_never_reset[host_id]) { + continue; + } + spi_bus_free(host_id); + } +} + +// This is copied in from the ESP-IDF because it is static. +// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +static bool bus_uses_iomux_pins(spi_host_device_t host, const spi_bus_config_t* bus_config) +{ + if (bus_config->sclk_io_num>=0 && + bus_config->sclk_io_num != spi_periph_signal[host].spiclk_iomux_pin) return false; + if (bus_config->quadwp_io_num>=0 && + bus_config->quadwp_io_num != spi_periph_signal[host].spiwp_iomux_pin) return false; + if (bus_config->quadhd_io_num>=0 && + bus_config->quadhd_io_num != spi_periph_signal[host].spihd_iomux_pin) return false; + if (bus_config->mosi_io_num >= 0 && + bus_config->mosi_io_num != spi_periph_signal[host].spid_iomux_pin) return false; + if (bus_config->miso_io_num>=0 && + bus_config->miso_io_num != spi_periph_signal[host].spiq_iomux_pin) return false; + + return true; +} + +// End copied code. + +static bool spi_bus_free(spi_host_device_t host_id) { + return spi_bus_get_attr(host_id) == NULL; } void common_hal_busio_spi_construct(busio_spi_obj_t *self, const mcu_pin_obj_t * clock, const mcu_pin_obj_t * mosi, const mcu_pin_obj_t * miso) { - // uint8_t sercom_index; - // uint32_t clock_pinmux = 0; - // bool mosi_none = mosi == NULL; - // bool miso_none = miso == NULL; - // uint32_t mosi_pinmux = 0; - // uint32_t miso_pinmux = 0; - // uint8_t clock_pad = 0; - // uint8_t mosi_pad = 0; - // uint8_t miso_pad = 0; - // uint8_t dopo = 255; + spi_bus_config_t bus_config; + bus_config.mosi_io_num = mosi != NULL ? mosi->number : -1; + bus_config.miso_io_num = miso != NULL ? miso->number : -1; + bus_config.sclk_io_num = clock != NULL ? clock->number : -1; + bus_config.quadwp_io_num = -1; + bus_config.quadhd_io_num = -1; + bus_config.max_transfer_sz = 0; // Uses the default + bus_config.flags = SPICOMMON_BUSFLAG_MASTER | SPICOMMON_BUSFLAG_SCLK | + mosi != NULL ? SPICOMMON_BUSFLAG_MOSI : 0 | + miso != NULL ? SPICOMMON_BUSFLAG_MISO : 0; + bus_config.intr_flags = 0; - // if (sercom == NULL) { - // mp_raise_ValueError(translate("Invalid pins")); - // } + // RAM and Flash is often on SPI1 and is unsupported by the IDF so use it as + // a flag value. + spi_host_device_t host_id = SPI1_HOST; + self->connected_through_gpio = true; + // Try and save SPI2 for pins that are on the IOMUX + if (bus_uses_iomux_pins(SPI2_HOST, &bus_config) && spi_bus_free(SPI2_HOST)) { + host_id = SPI2_HOST; + self->connected_through_gpio = false; + } else if (spi_bus_free(SPI3_HOST)) { + host_id = SPI3_HOST; + } else if (spi_bus_free(SPI2_HOST)) { + host_id = SPI2_HOST; + } + if (host_id == SPI1_HOST) { + mp_raise_ValueError(translate("All SPI peripherals are in use")); + } - // // Set up SPI clocks on SERCOM. - // samd_peripherals_sercom_clock_init(sercom, sercom_index); + esp_err_t result = spi_bus_initialize(host_id, &bus_config, 0 /* dma channel */); + if (result == ESP_ERR_NO_MEM) { + mp_raise_msg(&mp_type_MemoryError, translate("ESP-IDF memory allocation failed")); + } else if (result = ESP_INVALID_ARG) { + mp_raise_ValueError(translate("Invalid pins")); + } + spi_bus_lock_dev_config_t config = { .flags = 0 }; + result = spi_bus_lock_register_dev(spi_bus_get_attr(host_id)->lock, + spi_bus_lock_dev_config_t *config, + &self->lock); + if (result == ESP_ERR_NO_MEM) { + mp_raise_msg(&mp_type_MemoryError, translate("ESP-IDF memory allocation failed")); + } - #if defined(MICROPY_HW_APA102_SCK) && defined(MICROPY_HW_APA102_MOSI) && !CIRCUITPY_BITBANG_APA102 - // // if we're re-using the dotstar sercom, make sure it is disabled or the init will fail out - // hri_sercomspi_clear_CTRLA_ENABLE_bit(sercom); - #endif - // if (spi_m_sync_init(&self->spi_desc, sercom) != ERR_NONE) { - // mp_raise_OSError(MP_EIO); - // } - // Pads must be set after spi_m_sync_init(), which uses default values from - // the prototypical SERCOM. - // hri_sercomspi_write_CTRLA_DOPO_bf(sercom, dopo); - // hri_sercomspi_write_CTRLA_DIPO_bf(sercom, miso_pad); + err = esp_intr_alloc(spicommon_irqsource_for_host(host_id), + bus_config.intr_flags | ESP_INTR_FLAG_INTRDISABLED, + spi_interrupt_handler, self, &self->intr); + if (result == ESP_ERR_NO_MEM) { + mp_raise_msg(&mp_type_MemoryError, translate("ESP-IDF memory allocation failed")); + } - // Always start at 250khz which is what SD cards need. They are sensitive to - // SPI bus noise before they are put into SPI mode. - // uint8_t baud_value = samd_peripherals_spi_baudrate_to_baud_reg_value(250000); - // if (spi_m_sync_set_baudrate(&self->spi_desc, baud_value) != ERR_NONE) { - // // spi_m_sync_set_baudrate does not check for validity, just whether the device is - // // busy or not - // mp_raise_OSError(MP_EIO); - // } + spi_hal_context_t* hal = &self->hal_context; + hal->hw = NULL; // Set by spi_hal_init + hal->dmadesc_tx = NULL; + hal->dmadesc_rx = NULL; + hal->dmadesc_n = 0; - // gpio_set_pin_direction(clock->number, GPIO_DIRECTION_OUT); - // gpio_set_pin_pull_mode(clock->number, GPIO_PULL_OFF); - // gpio_set_pin_function(clock->number, clock_pinmux); - // claim_pin(clock); - // self->clock_pin = clock->number; + // We don't use native CS. + hal->cs_setup = 0; + hal->cs_hold = 0; + hal->cs_pin_id = -1; + hal->timing_conf = &self->timing_conf; - // if (mosi_none) { - // self->MOSI_pin = NO_PIN; - // } else { - // gpio_set_pin_direction(mosi->number, GPIO_DIRECTION_OUT); - // gpio_set_pin_pull_mode(mosi->number, GPIO_PULL_OFF); - // gpio_set_pin_function(mosi->number, mosi_pinmux); - // self->MOSI_pin = mosi->number; - // claim_pin(mosi); - // } + hal->sio = 1; + hal->half_duplex = 0; + hal->tx_lsbfirst = 0; + hal->rx_lsbfirst = 0; + hal->dma_enabled = 0; + hal->no_compensate = 1; + // Ignore CS bits - // if (miso_none) { - // self->MISO_pin = NO_PIN; - // } else { - // gpio_set_pin_direction(miso->number, GPIO_DIRECTION_IN); - // gpio_set_pin_pull_mode(miso->number, GPIO_PULL_OFF); - // gpio_set_pin_function(miso->number, miso_pinmux); - // self->MISO_pin = miso->number; - // claim_pin(miso); - // } + // We don't use cmd, addr or dummy bits. + hal->cmd = 0; + hal->cmd_bits = 0; + hal->addr_bits = 0; + hal->dummy_bits = 0; + hal->addr = 0; - // spi_m_sync_enable(&self->spi_desc); + hal->io_mode = SPI_LL_IO_MODE_NORMAL; + + spi_hal_init(hal, host_id); } void common_hal_busio_spi_never_reset(busio_spi_obj_t *self) { - // never_reset_sercom(self->spi_desc.dev.prvt); + spi_never_reset[self->host_id] = true; never_reset_pin(self->clock_pin); never_reset_pin(self->MOSI_pin); @@ -124,51 +181,50 @@ void common_hal_busio_spi_deinit(busio_spi_obj_t *self) { if (common_hal_busio_spi_deinited(self)) { return; } - // allow_reset_sercom(self->spi_desc.dev.prvt); + spi_never_reset[self->host_id] = false; + spi_bus_free(self->host_id); - // spi_m_sync_disable(&self->spi_desc); - // spi_m_sync_deinit(&self->spi_desc); - reset_pin(self->clock_pin); - reset_pin(self->MOSI_pin); - reset_pin(self->MISO_pin); + common_hal_reset_pin(self->clock_pin); + common_hal_reset_pin(self->MOSI_pin); + common_hal_reset_pin(self->MISO_pin); self->clock_pin = NULL; } bool common_hal_busio_spi_configure(busio_spi_obj_t *self, uint32_t baudrate, uint8_t polarity, uint8_t phase, uint8_t bits) { - // If the settings are already what we want then don't reset them. - // if (hri_sercomspi_get_CTRLA_CPHA_bit(hw) == phase && - // hri_sercomspi_get_CTRLA_CPOL_bit(hw) == polarity && - // hri_sercomspi_read_CTRLB_CHSIZE_bf(hw) == ((uint32_t)bits - 8) && - // hri_sercomspi_read_BAUD_BAUD_bf(hw) == baud_reg_value) { - // return true; - // } - - // Disable, set values (most or all are enable-protected), and re-enable. - // spi_m_sync_disable(&self->spi_desc); - // hri_sercomspi_wait_for_sync(hw, SERCOM_SPI_SYNCBUSY_MASK); - - // hri_sercomspi_write_CTRLA_CPHA_bit(hw, phase); - // hri_sercomspi_write_CTRLA_CPOL_bit(hw, polarity); - // hri_sercomspi_write_CTRLB_CHSIZE_bf(hw, bits - 8); - // hri_sercomspi_write_BAUD_BAUD_bf(hw, baud_reg_value); - // hri_sercomspi_wait_for_sync(hw, SERCOM_SPI_SYNCBUSY_MASK); - - // spi_m_sync_enable(&self->spi_desc); - // hri_sercomspi_wait_for_sync(hw, SERCOM_SPI_SYNCBUSY_MASK); + if (baudrate == self->target_frequency && + polarity == self->polarity && + phase == self->phase && + bits == self->bits) { + return true; + } + self->hal_context->mode = polarity << 1 | phase; + self->polarity = polarity; + self->phase = phase; + self->bits = bits; + self->target_frequency = baudrate; + esp_err_t result = spi_hal_get_clock_conf(self->hal_context, + self->target_frequency, + 128 /* duty_cycle */, + self->connected_through_gpio, + 0 /* input_delay_ns */, + &self->real_frequency, + &self->timing_conf); + spi_hal_setup_device(&self->hal_context); return true; } bool common_hal_busio_spi_try_lock(busio_spi_obj_t *self) { - bool grabbed_lock = false; - // CRITICAL_SECTION_ENTER() - if (!self->has_lock) { - grabbed_lock = true; - self->has_lock = true; - } - // CRITICAL_SECTION_LEAVE(); - return grabbed_lock; + // If our lock has already been taken then return false because someone else + // may already grabbed it in our call stack. + if (self->has_lock) { + return false; + } + // Wait to grab the lock from another task. + esp_err_t ret = spi_bus_lock_acquire_start(self->lock, portMAX_DELAY); + self->has_lock = true; + return true; } bool common_hal_busio_spi_has_lock(busio_spi_obj_t *self) { @@ -176,6 +232,7 @@ bool common_hal_busio_spi_has_lock(busio_spi_obj_t *self) { } void common_hal_busio_spi_unlock(busio_spi_obj_t *self) { + spi_bus_lock_acquire_end(self->lock); self->has_lock = false; } @@ -218,32 +275,35 @@ bool common_hal_busio_spi_transfer(busio_spi_obj_t *self, uint8_t *data_out, uin if (len == 0) { return true; } - // int32_t status; - if (len >= 16) { - // status = sercom_dma_transfer(self->spi_desc.dev.prvt, data_out, data_in, len); + + spi_hal_context_t* hal = &self->hal_context; + hal->tx_bitlen = len * 8; + hal->rx_bitlen = len * 8; + hal->send_buffer = data_out; + hal->rcv_buffer = data_in; + + spi_hal_setup_trans(hal); + spi_hal_prepare_data(hal); + spi_hal_user_start(hal); + if (len >= 16 && false) { + // Set up the interrupt and wait on the lock. } 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); + while (!spi_hal_usr_is_done(hal)) { + RUN_BACKGROUND_TASKS(); + } } - return false; // Status is number of chars read or an error code < 0. + + return false; } uint32_t common_hal_busio_spi_get_frequency(busio_spi_obj_t* self) { - // return samd_peripherals_spi_baud_reg_value_to_baudrate(hri_sercomspi_read_BAUD_reg(self->spi_desc.dev.prvt)); - return 0; + return self->real_frequency; } uint8_t common_hal_busio_spi_get_phase(busio_spi_obj_t* self) { - // void * hw = self->spi_desc.dev.prvt; - // return hri_sercomspi_get_CTRLA_CPHA_bit(hw); - return 0; + return self->phase; } uint8_t common_hal_busio_spi_get_polarity(busio_spi_obj_t* self) { - // void * hw = self->spi_desc.dev.prvt; - // return hri_sercomspi_get_CTRLA_CPOL_bit(hw); - return 0; + return self->polarity; } diff --git a/ports/esp32s2/common-hal/busio/SPI.h b/ports/esp32s2/common-hal/busio/SPI.h index 0ff1a4f7ea..0c2f286078 100644 --- a/ports/esp32s2/common-hal/busio/SPI.h +++ b/ports/esp32s2/common-hal/busio/SPI.h @@ -33,10 +33,20 @@ typedef struct { mp_obj_base_t base; - bool has_lock; const mcu_pin_obj_t* clock_pin; const mcu_pin_obj_t* MOSI_pin; const mcu_pin_obj_t* MISO_pin; + spi_host_device_t host_id; + spi_bus_lock_dev_handle_t lock; + spi_hal_context_t hal_context; + spi_hal_timing_conf_t timing_conf; + uint32_t target_frequency; + uint32_t real_frequency; + uint8_t polarity; + uint8_t phase; + uint8_t bits; + bool has_lock; + bool connected_through_gpio; } busio_spi_obj_t; void spi_reset(void); diff --git a/ports/esp32s2/common-hal/busio/UART.c b/ports/esp32s2/common-hal/busio/UART.c index d52e50cade..f73f5c993d 100644 --- a/ports/esp32s2/common-hal/busio/UART.c +++ b/ports/esp32s2/common-hal/busio/UART.c @@ -222,10 +222,10 @@ void common_hal_busio_uart_deinit(busio_uart_obj_t *self) { } uart_driver_delete(self->uart_num); - reset_pin(self->rx_pin); - reset_pin(self->tx_pin); - reset_pin(self->rts_pin); - reset_pin(self->cts_pin); + common_hal_reset_pin(self->rx_pin); + common_hal_reset_pin(self->tx_pin); + common_hal_reset_pin(self->rts_pin); + common_hal_reset_pin(self->cts_pin); self->rx_pin = NULL; self->tx_pin = NULL; self->cts_pin = NULL; diff --git a/ports/esp32s2/common-hal/microcontroller/Pin.c b/ports/esp32s2/common-hal/microcontroller/Pin.c index fd815518d5..075f80abc6 100644 --- a/ports/esp32s2/common-hal/microcontroller/Pin.c +++ b/ports/esp32s2/common-hal/microcontroller/Pin.c @@ -35,6 +35,9 @@ STATIC uint32_t never_reset_pins[2]; STATIC uint32_t in_use[2]; +bool apa102_mosi_in_use; +bool apa102_sck_in_use; + void never_reset_pin_number(gpio_num_t pin_number) { never_reset_pins[pin_number / 32] |= 1 << pin_number % 32; } @@ -49,7 +52,7 @@ void reset_pin_number(gpio_num_t pin_number) { in_use[pin_number / 32] &= ~(1 << pin_number % 32); } -void reset_pin(const mcu_pin_obj_t* pin) { +void common_hal_reset_pin(const mcu_pin_obj_t* pin) { reset_pin_number(pin->number); } diff --git a/ports/esp32s2/common-hal/microcontroller/Pin.h b/ports/esp32s2/common-hal/microcontroller/Pin.h index 573eec392b..ab06b388f8 100644 --- a/ports/esp32s2/common-hal/microcontroller/Pin.h +++ b/ports/esp32s2/common-hal/microcontroller/Pin.h @@ -31,11 +31,14 @@ #include "peripherals/pins.h" +extern bool apa102_mosi_in_use; +extern bool apa102_sck_in_use; + void reset_all_pins(void); // reset_pin_number takes the pin number instead of the pointer so that objects don't // need to store a full pointer. void reset_pin_number(gpio_num_t pin_number); -void reset_pin(const mcu_pin_obj_t* pin); +void common_hal_reset_pin(const mcu_pin_obj_t* pin); void claim_pin(const mcu_pin_obj_t* pin); bool pin_number_is_free(gpio_num_t pin_number); void never_reset_pin_number(gpio_num_t pin_number);