From 7ada70737fc3806d463a037db4cb2d5c07f08515 Mon Sep 17 00:00:00 2001 From: Lucian Copeland Date: Mon, 26 Oct 2020 10:53:55 -0400 Subject: [PATCH 1/3] Implement basic compiling version of SPI Peripheral --- ports/stm/common-hal/busio/SPI.c | 24 +- ports/stm/common-hal/busio/SPI.h | 17 +- .../common-hal/spiperipheral/SPIPeripheral.c | 270 ++++++++++++++++++ .../common-hal/spiperipheral/SPIPeripheral.h | 50 ++++ ports/stm/common-hal/spiperipheral/__init__.c | 1 + ports/stm/mpconfigport.mk | 2 + py/circuitpy_defns.mk | 5 + py/circuitpy_mpconfig.h | 8 + py/circuitpy_mpconfig.mk | 3 + shared-bindings/spiperipheral/SPIPeripheral.c | 179 ++++++++++++ shared-bindings/spiperipheral/SPIPeripheral.h | 53 ++++ shared-bindings/spiperipheral/__init__.c | 68 +++++ shared-bindings/spiperipheral/__init__.h | 34 +++ 13 files changed, 696 insertions(+), 18 deletions(-) create mode 100644 ports/stm/common-hal/spiperipheral/SPIPeripheral.c create mode 100644 ports/stm/common-hal/spiperipheral/SPIPeripheral.h create mode 100644 ports/stm/common-hal/spiperipheral/__init__.c create mode 100644 shared-bindings/spiperipheral/SPIPeripheral.c create mode 100644 shared-bindings/spiperipheral/SPIPeripheral.h create mode 100644 shared-bindings/spiperipheral/__init__.c create mode 100644 shared-bindings/spiperipheral/__init__.h diff --git a/ports/stm/common-hal/busio/SPI.c b/ports/stm/common-hal/busio/SPI.c index 29fbdee56910..001786b7511c 100644 --- a/ports/stm/common-hal/busio/SPI.c +++ b/ports/stm/common-hal/busio/SPI.c @@ -39,16 +39,6 @@ // Note that any bugs introduced in this file can cause crashes at startup // for chips using external SPI flash. -//arrays use 0 based numbering: SPI1 is stored at index 0 -#define MAX_SPI 6 - -STATIC bool reserved_spi[MAX_SPI]; -STATIC bool never_reset_spi[MAX_SPI]; - -#define ALL_CLOCKS 0xFF -STATIC void spi_clock_enable(uint8_t mask); -STATIC void spi_clock_disable(uint8_t mask); - STATIC uint32_t get_busclock(SPI_TypeDef * instance) { #if (CPY_STM32H7) if (instance == SPI1 || instance == SPI2 || instance == SPI3) { @@ -108,7 +98,7 @@ void spi_reset(void) { spi_clock_disable(ALL_CLOCKS & ~(never_reset_mask)); } -STATIC const mcu_periph_obj_t *find_pin_function(const mcu_periph_obj_t *table, size_t sz, const mcu_pin_obj_t *pin, int periph_index) { +const mcu_periph_obj_t *spi_find_pin_function(const mcu_periph_obj_t *table, size_t sz, const mcu_pin_obj_t *pin, int periph_index) { for(size_t i = 0; iperiph_index && pin == table->pin ) { return table; @@ -118,7 +108,7 @@ STATIC const mcu_periph_obj_t *find_pin_function(const mcu_periph_obj_t *table, } //match pins to SPI objects -STATIC int check_pins(busio_spi_obj_t *self, +int spi_check_pins(busio_spi_obj_t *self, const mcu_pin_obj_t * sck, const mcu_pin_obj_t * mosi, const mcu_pin_obj_t * miso) { bool spi_taken = false; @@ -137,12 +127,12 @@ STATIC int check_pins(busio_spi_obj_t *self, int periph_index = mcu_spi_sck->periph_index; const mcu_periph_obj_t *mcu_spi_miso = NULL; - if (miso && !(mcu_spi_miso = find_pin_function(mcu_spi_miso_list, miso_len, miso, periph_index))) { + if (miso && !(mcu_spi_miso = spi_find_pin_function(mcu_spi_miso_list, miso_len, miso, periph_index))) { continue; } const mcu_periph_obj_t *mcu_spi_mosi = NULL; - if (mosi && !(mcu_spi_mosi = find_pin_function(mcu_spi_mosi_list, mosi_len, mosi, periph_index))) { + if (mosi && !(mcu_spi_mosi = spi_find_pin_function(mcu_spi_mosi_list, mosi_len, mosi, periph_index))) { continue; } @@ -169,7 +159,7 @@ void common_hal_busio_spi_construct(busio_spi_obj_t *self, const mcu_pin_obj_t * sck, const mcu_pin_obj_t * mosi, const mcu_pin_obj_t * miso) { - int periph_index = check_pins(self, sck, mosi, miso); + int periph_index = spi_check_pins(self, sck, mosi, miso); SPI_TypeDef * SPIx = mcu_spi_banks[periph_index - 1]; //Start GPIO for each pin @@ -375,7 +365,7 @@ uint8_t common_hal_busio_spi_get_polarity(busio_spi_obj_t* self) { return self->polarity; } -STATIC void spi_clock_enable(uint8_t mask) { +void spi_clock_enable(uint8_t mask) { #ifdef SPI1 if (mask & (1 << 0)) { __HAL_RCC_SPI1_CLK_ENABLE(); @@ -408,7 +398,7 @@ STATIC void spi_clock_enable(uint8_t mask) { #endif } -STATIC void spi_clock_disable(uint8_t mask) { +void spi_clock_disable(uint8_t mask) { #ifdef SPI1 if (mask & (1 << 0)) { __HAL_RCC_SPI1_CLK_DISABLE(); diff --git a/ports/stm/common-hal/busio/SPI.h b/ports/stm/common-hal/busio/SPI.h index 6483183678ee..e4d063e66523 100644 --- a/ports/stm/common-hal/busio/SPI.h +++ b/ports/stm/common-hal/busio/SPI.h @@ -37,11 +37,12 @@ typedef struct { mp_obj_base_t base; SPI_HandleTypeDef handle; + IRQn_Type irq; bool has_lock; const mcu_periph_obj_t *sck; const mcu_periph_obj_t *mosi; const mcu_periph_obj_t *miso; - const mcu_periph_obj_t *nss; + const mcu_pin_obj_t *cs_pin; uint32_t baudrate; uint16_t prescaler; uint8_t polarity; @@ -49,6 +50,20 @@ typedef struct { uint8_t bits; } busio_spi_obj_t; +//arrays use 0 based numbering: SPI1 is stored at index 0 +#define MAX_SPI 6 +#define ALL_CLOCKS 0xFF + +bool reserved_spi[MAX_SPI]; +bool never_reset_spi[MAX_SPI]; + +const mcu_periph_obj_t *spi_find_pin_function(const mcu_periph_obj_t *table, size_t sz, + const mcu_pin_obj_t *pin, int periph_index); +int spi_check_pins(busio_spi_obj_t *self, + const mcu_pin_obj_t * sck, const mcu_pin_obj_t * mosi, + const mcu_pin_obj_t * miso); void spi_reset(void); +void spi_clock_enable(uint8_t mask); +void spi_clock_disable(uint8_t mask); #endif // MICROPY_INCLUDED_STM32_COMMON_HAL_BUSIO_SPI_H diff --git a/ports/stm/common-hal/spiperipheral/SPIPeripheral.c b/ports/stm/common-hal/spiperipheral/SPIPeripheral.c new file mode 100644 index 000000000000..df5f65466ae3 --- /dev/null +++ b/ports/stm/common-hal/spiperipheral/SPIPeripheral.c @@ -0,0 +1,270 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Lucian Copeland + * + * 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/spiperipheral/SPIPeripheral.h" +#include "common-hal/busio/SPI.h" + +#include "py/mperrno.h" +#include "py/mphal.h" +#include "py/runtime.h" +#include "lib/utils/interrupt_char.h" + +#include "shared-bindings/microcontroller/__init__.h" +#include "supervisor/shared/translate.h" +#include "shared-bindings/microcontroller/Pin.h" + +// This module is largely quite similar to busio/SPI, and borrows the same reservation and +// pin location systems. + +STATIC bool txrx_complete; +STATIC bool txrx_error; + +spiperipheral_spi_peripheral_obj_t * handles[6]; + +STATIC void spi_assign_irq(spiperipheral_spi_peripheral_obj_t *self, SPI_TypeDef * SPIx); + +void common_hal_spiperipheral_spi_peripheral_construct(spiperipheral_spi_peripheral_obj_t *self, + const mcu_pin_obj_t * sck, const mcu_pin_obj_t * mosi, + const mcu_pin_obj_t * miso, const mcu_pin_obj_t * cs) { + + // CS can be any pin and does not need to be checked against the others. + int periph_index = spi_check_pins((busio_spi_obj_t*)self, sck, mosi, miso); + self->cs_pin = cs; + + SPI_TypeDef * SPIx = mcu_spi_banks[periph_index - 1]; + + //Start GPIO for each pin + GPIO_InitTypeDef GPIO_InitStruct = {0}; + + GPIO_InitStruct.Pin = pin_mask(sck->number); + GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; + GPIO_InitStruct.Alternate = self->sck->altfn_index; + HAL_GPIO_Init(pin_port(sck->port), &GPIO_InitStruct); + + GPIO_InitStruct.Pin = pin_mask(cs->number); + GPIO_InitStruct.Mode = GPIO_MODE_INPUT; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; + HAL_GPIO_Init(pin_port(sck->port), &GPIO_InitStruct); + + if (self->mosi != NULL) { + GPIO_InitStruct.Pin = pin_mask(mosi->number); + GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; + GPIO_InitStruct.Alternate = self->mosi->altfn_index; + HAL_GPIO_Init(pin_port(mosi->port), &GPIO_InitStruct); + } + + if (self->miso != NULL) { + GPIO_InitStruct.Pin = pin_mask(miso->number); + GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; + GPIO_InitStruct.Alternate = self->miso->altfn_index; + HAL_GPIO_Init(pin_port(miso->port), &GPIO_InitStruct); + } + + spi_clock_enable(1 << (self->sck->periph_index - 1)); + reserved_spi[self->sck->periph_index - 1] = true; + spi_assign_irq(self, SPIx); + + self->handle.Instance = SPIx; + self->handle.Init.Mode = SPI_MODE_SLAVE; + // Direction change only required for RX-only, see RefMan RM0090:884 + self->handle.Init.Direction = (self->mosi == NULL) ? SPI_DIRECTION_2LINES_RXONLY : SPI_DIRECTION_2LINES; + self->handle.Init.DataSize = SPI_DATASIZE_8BIT; + self->handle.Init.CLKPolarity = SPI_POLARITY_LOW; + self->handle.Init.CLKPhase = SPI_PHASE_1EDGE; + self->handle.Init.NSS = SPI_NSS_SOFT; + self->handle.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_256; + self->handle.Init.FirstBit = SPI_FIRSTBIT_MSB; + self->handle.Init.TIMode = SPI_TIMODE_DISABLE; + self->handle.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE; + self->handle.Init.CRCPolynomial = 10; + if (HAL_SPI_Init(&self->handle) != HAL_OK) + { + mp_raise_ValueError(translate("SPI Init Error")); + } + self->polarity = 0; + self->phase = 0; + self->bits = 8; + + common_hal_mcu_pin_claim(sck); + common_hal_mcu_pin_claim(cs); + if (self->mosi != NULL) { + common_hal_mcu_pin_claim(mosi); + } + if (self->miso != NULL) { + common_hal_mcu_pin_claim(miso); + } + + HAL_NVIC_SetPriority(self->irq, 0, 1); + HAL_NVIC_EnableIRQ(self->irq); +} + + +bool common_hal_spiperipheral_spi_peripheral_deinited(spiperipheral_spi_peripheral_obj_t *self) { + return self->sck->pin == NULL; +} + +void common_hal_spiperipheral_spi_peripheral_deinit(spiperipheral_spi_peripheral_obj_t *self) { + if (common_hal_spiperipheral_spi_peripheral_deinited(self)) { + return; + } + spi_clock_disable(1<<(self->sck->periph_index - 1)); + reserved_spi[self->sck->periph_index - 1] = false; + never_reset_spi[self->sck->periph_index - 1] = false; + + reset_pin_number(self->sck->pin->port,self->sck->pin->number); + if (self->mosi != NULL) { + reset_pin_number(self->mosi->pin->port,self->mosi->pin->number); + } + if (self->miso != NULL) { + reset_pin_number(self->miso->pin->port,self->miso->pin->number); + } + self->sck = NULL; + self->mosi = NULL; + self->miso = NULL; +} + +bool common_hal_spiperipheral_spi_peripheral_spi_ready(spiperipheral_spi_peripheral_obj_t *self) { + return HAL_SPI_GetState(&self->handle) == HAL_SPI_STATE_READY; +} + +bool common_hal_spiperipheral_spi_peripheral_transaction_complete(spiperipheral_spi_peripheral_obj_t *self) { + return txrx_complete; +} + +bool common_hal_spiperipheral_spi_peripheral_transaction_error(spiperipheral_spi_peripheral_obj_t *self) { + return txrx_error; +} + +bool common_hal_spiperipheral_spi_peripheral_wait_for_transaction(spiperipheral_spi_peripheral_obj_t *self, + const uint8_t *data_out, uint8_t *data_in, size_t len) { + if (!common_hal_spiperipheral_spi_peripheral_spi_ready(self)) { + mp_raise_RuntimeError(translate("SPI transaction not complete")); + } + if (common_hal_spiperipheral_spi_peripheral_transaction_error(self)) { + mp_raise_RuntimeError(translate("Error in last transaction")); + } + + // Wait until the CS pin has dropped before attempting a transaction. + while(HAL_GPIO_ReadPin(pin_port(self->cs_pin->port), pin_mask(self->cs_pin->number))) { + RUN_BACKGROUND_TASKS; + // Allow user to break out of a timeout with a KeyboardInterrupt. + if ( mp_hal_is_interrupted() ) { + return 0; + } + } + + txrx_complete = false; + txrx_error = false; + + // Is there a compelling reason to use HAL_SPI_TransmitReceive_DMA here instead? + return HAL_SPI_TransmitReceive_IT(&self->handle, (uint8_t*)data_out, (uint8_t *)data_in, (uint16_t)len) == HAL_OK; +} + +void HAL_SPI_TxRxCpltCallback(SPI_HandleTypeDef *hspi) +{ + txrx_complete = true; +} + +void HAL_SPI_ErrorCallback(SPI_HandleTypeDef *hspi) +{ + txrx_error = true; +} + +void SPI1_IRQHandler(void) { + if (handles[0]) { + HAL_SPI_IRQHandler(&handles[0]->handle); + } +} + +void SPI2_IRQHandler(void) { + if (handles[1]) { + HAL_SPI_IRQHandler(&handles[1]->handle); + } +} + +void SPI3_IRQHandler(void) { + if (handles[2]) { + HAL_SPI_IRQHandler(&handles[2]->handle); + } +} + +void SPI4_IRQHandler(void) { + if (handles[3]) { + HAL_SPI_IRQHandler(&handles[3]->handle); + } +} + +void SPI5_IRQHandler(void) { + if (handles[4]) { + HAL_SPI_IRQHandler(&handles[4]->handle); + } +} + +void SPI6_IRQHandler(void) { + if (handles[5]) { + HAL_SPI_IRQHandler(&handles[5]->handle); + } +} + +STATIC void spi_assign_irq(spiperipheral_spi_peripheral_obj_t *self, SPI_TypeDef * SPIx) { + #ifdef SPI1 + if (SPIx == SPI1) { + self->irq = SPI1_IRQn; + } + #endif + #ifdef SPI2 + if (SPIx == SPI2) { + self->irq = SPI2_IRQn; + } + #endif + #ifdef SPI3 + if (SPIx == SPI3) { + self->irq = SPI3_IRQn; + } + #endif + #ifdef SPI4 + if (SPIx == SPI4) { + self->irq = SPI4_IRQn; + } + #endif + #ifdef SPI5 + if (SPIx == SPI5) { + self->irq = SPI5_IRQn; + } + #endif + #ifdef SPI6 + if (SPIx == SPI6) { + self->irq = SPI6_IRQn; + } + #endif +} diff --git a/ports/stm/common-hal/spiperipheral/SPIPeripheral.h b/ports/stm/common-hal/spiperipheral/SPIPeripheral.h new file mode 100644 index 000000000000..3ec7826a342b --- /dev/null +++ b/ports/stm/common-hal/spiperipheral/SPIPeripheral.h @@ -0,0 +1,50 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Lucian Copeland + * + * 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_STM32_COMMON_HAL_SPIPERIPHERAL_SPI_PERIPHERAL_H +#define MICROPY_INCLUDED_STM32_COMMON_HAL_SPIPERIPHERAL_SPI_PERIPHERAL_H + +#include "common-hal/microcontroller/Pin.h" +#include "peripherals/periph.h" +#include "py/obj.h" + +typedef struct { + mp_obj_base_t base; + SPI_HandleTypeDef handle; + IRQn_Type irq; + bool has_lock; + const mcu_periph_obj_t *sck; + const mcu_periph_obj_t *mosi; + const mcu_periph_obj_t *miso; + const mcu_pin_obj_t *cs_pin; + uint32_t baudrate; + uint16_t prescaler; + uint8_t polarity; + uint8_t phase; + uint8_t bits; +} spiperipheral_spi_peripheral_obj_t; + +#endif // MICROPY_INCLUDED_STM32_COMMON_HAL_SPIPERIPHERAL_SPI_PERIPHERAL_H diff --git a/ports/stm/common-hal/spiperipheral/__init__.c b/ports/stm/common-hal/spiperipheral/__init__.c new file mode 100644 index 000000000000..848dde35a963 --- /dev/null +++ b/ports/stm/common-hal/spiperipheral/__init__.c @@ -0,0 +1 @@ +// No spiperipheral module functions. \ No newline at end of file diff --git a/ports/stm/mpconfigport.mk b/ports/stm/mpconfigport.mk index bcecaa517023..45926aeee230 100644 --- a/ports/stm/mpconfigport.mk +++ b/ports/stm/mpconfigport.mk @@ -13,6 +13,8 @@ endif ifeq ($(MCU_SERIES),F4) # Not yet implemented common-hal modules: + CIRCUITPY_SPIPERIPHERAL ?= 1 + CIRCUITPY_AUDIOBUSIO ?= 0 CIRCUITPY_AUDIOIO ?= 0 CIRCUITPY_COUNTIO ?= 0 diff --git a/py/circuitpy_defns.mk b/py/circuitpy_defns.mk index ccdf973e9fb5..1bc5a7b1660d 100644 --- a/py/circuitpy_defns.mk +++ b/py/circuitpy_defns.mk @@ -238,6 +238,9 @@ endif ifeq ($(CIRCUITPY_SOCKETPOOL),1) SRC_PATTERNS += socketpool/% endif +ifeq ($(CIRCUITPY_SPIPERIPHERAL),1) +SRC_PATTERNS += spiperipheral/% +endif ifeq ($(CIRCUITPY_SSL),1) SRC_PATTERNS += ssl/% endif @@ -356,6 +359,8 @@ SRC_COMMON_HAL_ALL = \ socketpool/__init__.c \ socketpool/SocketPool.c \ socketpool/Socket.c \ + spiperipheral/__init__.c \ + spiperipheral/SPIPeripheral.c \ ssl/__init__.c \ ssl/SSLContext.c \ supervisor/Runtime.c \ diff --git a/py/circuitpy_mpconfig.h b/py/circuitpy_mpconfig.h index 1e01bd9c5e0b..69e379fe4242 100644 --- a/py/circuitpy_mpconfig.h +++ b/py/circuitpy_mpconfig.h @@ -619,6 +619,13 @@ extern const struct _mp_obj_module_t socketpool_module; #define SOCKETPOOL_MODULE #endif +#if CIRCUITPY_SPIPERIPHERAL +extern const struct _mp_obj_module_t spiperipheral_module; +#define SPIPERIPHERAL_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR_spiperipheral), (mp_obj_t)&spiperipheral_module }, +#else +#define SPIPERIPHERAL_MODULE +#endif + #if CIRCUITPY_SSL extern const struct _mp_obj_module_t ssl_module; #define SSL_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR_ssl), (mp_obj_t)&ssl_module }, @@ -815,6 +822,7 @@ extern const struct _mp_obj_module_t wifi_module; SDIOIO_MODULE \ SHARPDISPLAY_MODULE \ SOCKETPOOL_MODULE \ + SPIPERIPHERAL_MODULE \ SSL_MODULE \ STAGE_MODULE \ STORAGE_MODULE \ diff --git a/py/circuitpy_mpconfig.mk b/py/circuitpy_mpconfig.mk index a6aabec33d18..de41e5494673 100644 --- a/py/circuitpy_mpconfig.mk +++ b/py/circuitpy_mpconfig.mk @@ -212,6 +212,9 @@ CFLAGS += -DCIRCUITPY_SHARPDISPLAY=$(CIRCUITPY_SHARPDISPLAY) CIRCUITPY_SOCKETPOOL ?= $(CIRCUITPY_WIFI) CFLAGS += -DCIRCUITPY_SOCKETPOOL=$(CIRCUITPY_SOCKETPOOL) +CIRCUITPY_SPIPERIPHERAL ?= 0 +CFLAGS += -DCIRCUITPY_SPIPERIPHERAL=$(CIRCUITPY_SPIPERIPHERAL) + CIRCUITPY_SSL ?= $(CIRCUITPY_WIFI) CFLAGS += -DCIRCUITPY_SSL=$(CIRCUITPY_SSL) diff --git a/shared-bindings/spiperipheral/SPIPeripheral.c b/shared-bindings/spiperipheral/SPIPeripheral.c new file mode 100644 index 000000000000..5ddecbeb4bb8 --- /dev/null +++ b/shared-bindings/spiperipheral/SPIPeripheral.c @@ -0,0 +1,179 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Lucian Copeland + * + * 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. + */ + +// This file contains all of the Python API definitions for the +// spiperipheral.SPIPeripheral class. + +#include + +#include "shared-bindings/microcontroller/Pin.h" +#include "shared-bindings/spiperipheral/SPIPeripheral.h" +#include "shared-bindings/util.h" + +#include "lib/utils/buffer_helper.h" +#include "lib/utils/context_manager_helpers.h" +#include "py/mperrno.h" +#include "py/objproperty.h" +#include "py/runtime.h" +#include "supervisor/shared/translate.h" + + +//| class SPIPeripheral: + +STATIC mp_obj_t spiperipheral_spi_peripheral_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + spiperipheral_spi_peripheral_obj_t *self = m_new_obj(spiperipheral_spi_peripheral_obj_t); + self->base.type = &spiperipheral_spi_peripheral_type; + enum { ARG_SCK, ARG_MOSI, ARG_MISO, ARG_CS }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_SCK, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_MOSI, MP_ARG_OBJ, {.u_obj = mp_const_none} }, + { MP_QSTR_MISO, MP_ARG_OBJ, {.u_obj = mp_const_none} }, + { MP_QSTR_CS, MP_ARG_REQUIRED | MP_ARG_OBJ }, + }; + 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); + const mcu_pin_obj_t* sck = validate_obj_is_free_pin(args[ARG_SCK].u_obj); + const mcu_pin_obj_t* mosi = validate_obj_is_free_pin_or_none(args[ARG_MOSI].u_obj); + const mcu_pin_obj_t* miso = validate_obj_is_free_pin_or_none(args[ARG_MISO].u_obj); + const mcu_pin_obj_t* cs = validate_obj_is_free_pin(args[ARG_CS].u_obj); + + if (!miso && !mosi) { + mp_raise_ValueError(translate("Must provide MISO or MOSI pin")); + } + + common_hal_spiperipheral_spi_peripheral_construct(self, sck, mosi, miso, cs); + return MP_OBJ_FROM_PTR(self); +} + +//| def deinit(self) -> None: +//| """Turn off the SPI Peripheral bus.""" +//| ... +//| +STATIC mp_obj_t spiperipheral_spi_peripheral_obj_deinit(mp_obj_t self_in) { + spiperipheral_spi_peripheral_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_spiperipheral_spi_peripheral_deinit(self); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_1(spiperipheral_spi_peripheral_deinit_obj, spiperipheral_spi_peripheral_obj_deinit); + +//| def __enter__(self) -> SPI: +//| """No-op used by Context Managers. +//| Provided by context manager helper.""" +//| ... +//| + +//| def __exit__(self) -> None: +//| """Automatically deinitializes the hardware when exiting a context. See +//| :ref:`lifetime-and-contextmanagers` for more info.""" +//| ... +//| +STATIC mp_obj_t spiperipheral_spi_peripheral_obj___exit__(size_t n_args, const mp_obj_t *args) { + (void)n_args; + common_hal_spiperipheral_spi_peripheral_deinit(args[0]); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(spiperipheral_spi_peripheral_obj___exit___obj, 4, 4, spiperipheral_spi_peripheral_obj___exit__); + +STATIC void check_for_deinit(spiperipheral_spi_peripheral_obj_t *self) { + if (common_hal_spiperipheral_spi_peripheral_deinited(self)) { + raise_deinited_error(); + } +} + +STATIC mp_obj_t spiperipheral_spi_peripheral_obj_spi_ready(mp_obj_t self_in) { + spiperipheral_spi_peripheral_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + return mp_obj_new_bool(common_hal_spiperipheral_spi_peripheral_spi_ready(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(spiperipheral_spi_peripheral_spi_ready_obj, spiperipheral_spi_peripheral_obj_spi_ready); + +STATIC mp_obj_t spiperipheral_spi_peripheral_obj_transaction_complete(mp_obj_t self_in) { + spiperipheral_spi_peripheral_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + return mp_obj_new_bool(common_hal_spiperipheral_spi_peripheral_transaction_complete(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(spiperipheral_spi_peripheral_transaction_complete_obj, spiperipheral_spi_peripheral_obj_transaction_complete); + +STATIC mp_obj_t spiperipheral_spi_peripheral_obj_transaction_error(mp_obj_t self_in) { + spiperipheral_spi_peripheral_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + return mp_obj_new_bool(common_hal_spiperipheral_spi_peripheral_transaction_error(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(spiperipheral_spi_peripheral_transaction_error_obj, spiperipheral_spi_peripheral_obj_transaction_error); + +STATIC mp_obj_t spiperipheral_spi_peripheral_wait_for_transaction(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_buffer_out, ARG_buffer_in, ARG_length}; + 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_length, MP_ARG_REQUIRED | MP_ARG_INT }, + }; + + spiperipheral_spi_peripheral_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); + check_for_deinit(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); + mp_buffer_info_t buf_in_info; + mp_get_buffer_raise(args[ARG_buffer_in].u_obj, &buf_in_info, MP_BUFFER_WRITE); + + if (args[ARG_length].u_int == 0) { + return mp_const_none; + } + + bool ok = common_hal_spiperipheral_spi_peripheral_wait_for_transaction(self, + ((const uint8_t*)buf_out_info.buf), ((uint8_t*)buf_in_info.buf), args[ARG_length].u_int); + + if (!ok) { + mp_raise_OSError(MP_EIO); + } + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_KW(spiperipheral_spi_peripheral_wait_for_transaction_obj, 3, spiperipheral_spi_peripheral_wait_for_transaction); + + + +STATIC const mp_rom_map_elem_t spiperipheral_spi_peripheral_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&spiperipheral_spi_peripheral_deinit_obj) }, + { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) }, + { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&spiperipheral_spi_peripheral_obj___exit___obj) }, + + { MP_ROM_QSTR(MP_QSTR_ready), MP_ROM_PTR(&spiperipheral_spi_peripheral_spi_ready_obj) }, + { MP_ROM_QSTR(MP_QSTR_complete), MP_ROM_PTR(&spiperipheral_spi_peripheral_transaction_complete_obj) }, + { MP_ROM_QSTR(MP_QSTR_error), MP_ROM_PTR(&spiperipheral_spi_peripheral_transaction_error_obj) }, + + { MP_ROM_QSTR(MP_QSTR_wait_for_transaction), MP_ROM_PTR(&spiperipheral_spi_peripheral_wait_for_transaction_obj) }, +}; +STATIC MP_DEFINE_CONST_DICT(spiperipheral_spi_peripheral_locals_dict, spiperipheral_spi_peripheral_locals_dict_table); + +const mp_obj_type_t spiperipheral_spi_peripheral_type = { + { &mp_type_type }, + .name = MP_QSTR_SPIPERIPHERAL, + .make_new = spiperipheral_spi_peripheral_make_new, + .locals_dict = (mp_obj_dict_t*)&spiperipheral_spi_peripheral_locals_dict, +}; diff --git a/shared-bindings/spiperipheral/SPIPeripheral.h b/shared-bindings/spiperipheral/SPIPeripheral.h new file mode 100644 index 000000000000..83f1dd760bd7 --- /dev/null +++ b/shared-bindings/spiperipheral/SPIPeripheral.h @@ -0,0 +1,53 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Lucian Copeland + * + * 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_SPIPERIPHERAL_SPI_PERIPHERAL_H +#define MICROPY_INCLUDED_SHARED_BINDINGS_SPIPERIPHERAL_SPI_PERIPHERAL_H + +#include "py/obj.h" + +#include "common-hal/microcontroller/Pin.h" +#include "common-hal/spiperipheral/SPIPeripheral.h" + +// Type object used in Python. Should be shared between ports. +extern const mp_obj_type_t spiperipheral_spi_peripheral_type; + +// Construct an underlying SPI object. +void common_hal_spiperipheral_spi_peripheral_construct(spiperipheral_spi_peripheral_obj_t *self, + const mcu_pin_obj_t * sck, const mcu_pin_obj_t * mosi, + const mcu_pin_obj_t * miso, const mcu_pin_obj_t * cs); + +bool common_hal_spiperipheral_spi_peripheral_deinited(spiperipheral_spi_peripheral_obj_t *self); +void common_hal_spiperipheral_spi_peripheral_deinit(spiperipheral_spi_peripheral_obj_t *self); + +bool common_hal_spiperipheral_spi_peripheral_spi_ready(spiperipheral_spi_peripheral_obj_t *self); +bool common_hal_spiperipheral_spi_peripheral_transaction_complete(spiperipheral_spi_peripheral_obj_t *self); +bool common_hal_spiperipheral_spi_peripheral_transaction_error(spiperipheral_spi_peripheral_obj_t *self); + +bool common_hal_spiperipheral_spi_peripheral_wait_for_transaction(spiperipheral_spi_peripheral_obj_t *self, + const uint8_t *data_out, uint8_t *data_in, size_t len); + +#endif // MICROPY_INCLUDED_SHARED_BINDINGS_SPIPERIPHERAL_SPI_PERIPHERAL_H diff --git a/shared-bindings/spiperipheral/__init__.c b/shared-bindings/spiperipheral/__init__.c new file mode 100644 index 000000000000..743122407a12 --- /dev/null +++ b/shared-bindings/spiperipheral/__init__.c @@ -0,0 +1,68 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Lucian Copeland + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include + +#include "py/obj.h" +#include "py/runtime.h" + +#include "shared-bindings/microcontroller/Pin.h" +#include "shared-bindings/spiperipheral/__init__.h" +#include "shared-bindings/spiperipheral/SPIPeripheral.h" + +//| """Support for SPI as a peripheral +//| +//| The `spiperipheral` module allows using SPI in peripheral/slave mode, +//| rather than controller/master mode. +//| + +//| All classes change hardware state and should be deinitialized when they +//| are no longer needed if the program continues after use. To do so, either +//| call :py:meth:`!deinit` or use a context manager. See +//| :ref:`lifetime-and-contextmanagers` for more info. +//| +//| For example:: +//| +//| import spiperipheral +//| import time +//| from board import * +//| +//| periph = spiperipheral.SPIPeripheral(SCK, MOSI, MISO, D5) +//| +//| This example will initialize the the device. +//| + +STATIC const mp_rom_map_elem_t spiperipheral_module_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_spiperipheral) }, + { MP_ROM_QSTR(MP_QSTR_SPIPeripheral), MP_ROM_PTR(&spiperipheral_spi_peripheral_type) }, +}; + +STATIC MP_DEFINE_CONST_DICT(spiperipheral_module_globals, spiperipheral_module_globals_table); + +const mp_obj_module_t spiperipheral_module = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&spiperipheral_module_globals, +}; \ No newline at end of file diff --git a/shared-bindings/spiperipheral/__init__.h b/shared-bindings/spiperipheral/__init__.h new file mode 100644 index 000000000000..1daee0a7eb42 --- /dev/null +++ b/shared-bindings/spiperipheral/__init__.h @@ -0,0 +1,34 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Lucian Copeland + * + * 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_SPIPERIPHERAL___INIT___H +#define MICROPY_INCLUDED_SHARED_BINDINGS_SPIPERIPHERAL___INIT___H + +#include "py/obj.h" + +// Nothing now. + +#endif // MICROPY_INCLUDED_SHARED_BINDINGS_SPIPERIPHERAL___INIT___H From 116f027ab6669dbd4e9d052141be46d83b9c9e94 Mon Sep 17 00:00:00 2001 From: Lucian Copeland Date: Thu, 29 Oct 2020 11:35:58 -0400 Subject: [PATCH 2/3] Fix handle array references --- ports/stm/common-hal/spiperipheral/SPIPeripheral.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ports/stm/common-hal/spiperipheral/SPIPeripheral.c b/ports/stm/common-hal/spiperipheral/SPIPeripheral.c index df5f65466ae3..635bf760e041 100644 --- a/ports/stm/common-hal/spiperipheral/SPIPeripheral.c +++ b/ports/stm/common-hal/spiperipheral/SPIPeripheral.c @@ -42,7 +42,7 @@ STATIC bool txrx_complete; STATIC bool txrx_error; -spiperipheral_spi_peripheral_obj_t * handles[6]; +spiperipheral_spi_peripheral_obj_t * handles[6] = {NULL, NULL, NULL, NULL, NULL, NULL}; STATIC void spi_assign_irq(spiperipheral_spi_peripheral_obj_t *self, SPI_TypeDef * SPIx); @@ -93,6 +93,7 @@ void common_hal_spiperipheral_spi_peripheral_construct(spiperipheral_spi_periphe spi_clock_enable(1 << (self->sck->periph_index - 1)); reserved_spi[self->sck->periph_index - 1] = true; spi_assign_irq(self, SPIx); + handles[self->sck->periph_index - 1] = self; self->handle.Instance = SPIx; self->handle.Init.Mode = SPI_MODE_SLAVE; @@ -140,6 +141,7 @@ void common_hal_spiperipheral_spi_peripheral_deinit(spiperipheral_spi_peripheral spi_clock_disable(1<<(self->sck->periph_index - 1)); reserved_spi[self->sck->periph_index - 1] = false; never_reset_spi[self->sck->periph_index - 1] = false; + handles[self->sck->periph_index - 1] = NULL; reset_pin_number(self->sck->pin->port,self->sck->pin->number); if (self->mosi != NULL) { From c8c2b1b8f1704e260a3a188b9af02c5762b39f4b Mon Sep 17 00:00:00 2001 From: Lucian Copeland Date: Wed, 2 Dec 2020 14:20:34 -0500 Subject: [PATCH 3/3] Implement DMA API. Doesn't work. --- ports/stm/Makefile | 1 + .../common-hal/spiperipheral/SPIPeripheral.c | 180 ++++++++++-- .../common-hal/spiperipheral/SPIPeripheral.h | 4 + ports/stm/peripherals/dma.c | 261 ++++++++++++++++++ ports/stm/peripherals/dma.h | 91 ++++++ ports/stm/supervisor/port.c | 6 + 6 files changed, 521 insertions(+), 22 deletions(-) create mode 100644 ports/stm/peripherals/dma.c create mode 100644 ports/stm/peripherals/dma.h diff --git a/ports/stm/Makefile b/ports/stm/Makefile index b9426e07ec94..ee72e0403c9c 100755 --- a/ports/stm/Makefile +++ b/ports/stm/Makefile @@ -217,6 +217,7 @@ SRC_C += \ boards/$(BOARD)/board.c \ boards/$(BOARD)/pins.c \ peripherals/timers.c \ + peripherals/dma.c \ peripherals/stm32$(MCU_SERIES_LOWER)/clocks.c \ peripherals/stm32$(MCU_SERIES_LOWER)/$(MCU_VARIANT_LOWER)/pins.c \ peripherals/stm32$(MCU_SERIES_LOWER)/$(MCU_VARIANT_LOWER)/gpio.c \ diff --git a/ports/stm/common-hal/spiperipheral/SPIPeripheral.c b/ports/stm/common-hal/spiperipheral/SPIPeripheral.c index 635bf760e041..f643a2909d89 100644 --- a/ports/stm/common-hal/spiperipheral/SPIPeripheral.c +++ b/ports/stm/common-hal/spiperipheral/SPIPeripheral.c @@ -36,16 +36,41 @@ #include "supervisor/shared/translate.h" #include "shared-bindings/microcontroller/Pin.h" +#include "peripherals/dma.h" + // This module is largely quite similar to busio/SPI, and borrows the same reservation and // pin location systems. STATIC bool txrx_complete; STATIC bool txrx_error; +STATIC DMA_HandleTypeDef *g_dma_handle_rx; +STATIC DMA_HandleTypeDef *g_dma_handle_tx; + spiperipheral_spi_peripheral_obj_t * handles[6] = {NULL, NULL, NULL, NULL, NULL, NULL}; STATIC void spi_assign_irq(spiperipheral_spi_peripheral_obj_t *self, SPI_TypeDef * SPIx); +void spiperipheral_reset(void) { + if (g_dma_handle_tx) { + HAL_DMA_DeInit(g_dma_handle_tx); + } + if (g_dma_handle_rx) { + HAL_DMA_DeInit(g_dma_handle_rx); + } + HAL_NVIC_DisableIRQ(DMA1_Stream4_IRQn); + HAL_NVIC_DisableIRQ(DMA1_Stream3_IRQn); + HAL_NVIC_DisableIRQ(SPI2_IRQn); + + __HAL_RCC_DMA1_CLK_DISABLE(); + __HAL_RCC_DMA2_CLK_DISABLE(); + for (int i = 0; i < 6; i++) { + g_dma_handle_rx = NULL; + g_dma_handle_tx = NULL; + handles[i] = NULL; + } +} + void common_hal_spiperipheral_spi_peripheral_construct(spiperipheral_spi_peripheral_obj_t *self, const mcu_pin_obj_t * sck, const mcu_pin_obj_t * mosi, const mcu_pin_obj_t * miso, const mcu_pin_obj_t * cs) { @@ -85,7 +110,7 @@ void common_hal_spiperipheral_spi_peripheral_construct(spiperipheral_spi_periphe GPIO_InitStruct.Pin = pin_mask(miso->number); GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; - GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_MEDIUM; GPIO_InitStruct.Alternate = self->miso->altfn_index; HAL_GPIO_Init(pin_port(miso->port), &GPIO_InitStruct); } @@ -125,8 +150,86 @@ void common_hal_spiperipheral_spi_peripheral_construct(spiperipheral_spi_periphe common_hal_mcu_pin_claim(miso); } - HAL_NVIC_SetPriority(self->irq, 0, 1); - HAL_NVIC_EnableIRQ(self->irq); + // --------------------------- + // DMA Peripheral module setup (not working) + // --------------------------- + + // uint8_t dma_idx = 0; + // uint8_t dma_stream_idx = 0; + // uint32_t dma_channel = 0; + + // // TX + // stm32_peripherals_dma_get_params(DMA_SPI_TX, periph_index, &dma_idx, &dma_stream_idx, &dma_channel); + // stm32_peripherals_dma_init(&self->dma_handle_tx, dma_idx, dma_stream_idx, dma_channel, + // DMA_MEMORY_TO_PERIPH, DMA_PRIORITY_LOW, 1); + // __HAL_LINKDMA(&self->handle, hdmatx, self->dma_handle_tx); + + // // RX + // stm32_peripherals_dma_get_params(DMA_SPI_RX, periph_index, &dma_idx, &dma_stream_idx, &dma_channel); + // stm32_peripherals_dma_init(&self->dma_handle_rx, dma_idx, dma_stream_idx, dma_channel, + // DMA_PERIPH_TO_MEMORY, DMA_PRIORITY_HIGH, 0); + // __HAL_LINKDMA(&self->handle, hdmarx, self->dma_handle_rx); + + // HAL_NVIC_SetPriority(SPI2_IRQn, 0, 2); + // HAL_NVIC_EnableIRQ(SPI2_IRQn); + + + // --------------------------- + // Manual DMA setup + // --------------------------- + + __HAL_RCC_DMA1_CLK_ENABLE(); + + // TX + self->dma_handle_tx.Instance = DMA1_Stream4; + self->dma_handle_tx.Init.Channel = DMA_CHANNEL_0; + self->dma_handle_tx.Init.Direction = DMA_MEMORY_TO_PERIPH; + self->dma_handle_tx.Init.PeriphInc = DMA_PINC_DISABLE; + self->dma_handle_tx.Init.MemInc = DMA_MINC_ENABLE; + self->dma_handle_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE; + self->dma_handle_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE; + self->dma_handle_tx.Init.Mode = DMA_NORMAL; + self->dma_handle_tx.Init.Priority = DMA_PRIORITY_LOW; + self->dma_handle_tx.Init.FIFOMode = DMA_FIFOMODE_DISABLE; + self->dma_handle_tx.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL; + self->dma_handle_tx.Init.MemBurst = DMA_MBURST_INC4; + self->dma_handle_tx.Init.PeriphBurst = DMA_PBURST_INC4; + HAL_DMA_Init(&self->dma_handle_tx); + __HAL_LINKDMA(&self->handle, hdmatx, self->dma_handle_tx); + + //register global handle for interrupt + g_dma_handle_tx = &self->dma_handle_tx; + + // RX + self->dma_handle_rx.Instance = DMA1_Stream3; + self->dma_handle_rx.Init.Channel = DMA_CHANNEL_0; + self->dma_handle_rx.Init.Direction = DMA_PERIPH_TO_MEMORY; + self->dma_handle_rx.Init.PeriphInc = DMA_PINC_DISABLE; + self->dma_handle_rx.Init.MemInc = DMA_MINC_ENABLE; + self->dma_handle_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE; + self->dma_handle_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE; + self->dma_handle_rx.Init.Mode = DMA_NORMAL; + self->dma_handle_rx.Init.Priority = DMA_PRIORITY_HIGH; + self->dma_handle_rx.Init.FIFOMode = DMA_FIFOMODE_DISABLE; + self->dma_handle_rx.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL; + self->dma_handle_rx.Init.MemBurst = DMA_MBURST_INC4; + self->dma_handle_rx.Init.PeriphBurst = DMA_PBURST_INC4; + HAL_DMA_Init(&self->dma_handle_rx); + __HAL_LINKDMA(&self->handle, hdmarx, self->dma_handle_rx); + + //register global handle for interrupt + g_dma_handle_rx = &self->dma_handle_rx; + + HAL_NVIC_SetPriority(DMA1_Stream4_IRQn, 0, 1); + HAL_NVIC_EnableIRQ(DMA1_Stream4_IRQn); + HAL_NVIC_SetPriority(DMA1_Stream3_IRQn, 0, 0); + HAL_NVIC_EnableIRQ(DMA1_Stream3_IRQn); + HAL_NVIC_SetPriority(SPI2_IRQn, 0, 2); + HAL_NVIC_EnableIRQ(SPI2_IRQn); + + // --------------------------- + // End of DMA + // --------------------------- } @@ -167,29 +270,43 @@ bool common_hal_spiperipheral_spi_peripheral_transaction_error(spiperipheral_spi return txrx_error; } +STATIC uint8_t incr_counter = 0; +STATIC uint8_t redata_out[72]; +STATIC uint8_t redata_in[72]; + bool common_hal_spiperipheral_spi_peripheral_wait_for_transaction(spiperipheral_spi_peripheral_obj_t *self, const uint8_t *data_out, uint8_t *data_in, size_t len) { - if (!common_hal_spiperipheral_spi_peripheral_spi_ready(self)) { - mp_raise_RuntimeError(translate("SPI transaction not complete")); - } - if (common_hal_spiperipheral_spi_peripheral_transaction_error(self)) { - mp_raise_RuntimeError(translate("Error in last transaction")); - } + // if (!common_hal_spiperipheral_spi_peripheral_spi_ready(self)) { + // txrx_complete = false; + // mp_raise_RuntimeError(translate("SPI transaction not complete")); + // } + // if (common_hal_spiperipheral_spi_peripheral_transaction_error(self)) { + // txrx_error = false; + // mp_raise_RuntimeError(translate("Error in last transaction")); + // } + + // txrx_complete = false; + // txrx_error = false; + __disable_irq(); + HAL_SPI_DMAStop(&self->handle); + + len = 72; + incr_counter++; // = redata_in[1] + 1; + redata_out[0] = 0x01; + redata_out[1] = incr_counter; + redata_out[2] = 0x03; // Wait until the CS pin has dropped before attempting a transaction. - while(HAL_GPIO_ReadPin(pin_port(self->cs_pin->port), pin_mask(self->cs_pin->number))) { - RUN_BACKGROUND_TASKS; - // Allow user to break out of a timeout with a KeyboardInterrupt. - if ( mp_hal_is_interrupted() ) { - return 0; - } - } - - txrx_complete = false; - txrx_error = false; - - // Is there a compelling reason to use HAL_SPI_TransmitReceive_DMA here instead? - return HAL_SPI_TransmitReceive_IT(&self->handle, (uint8_t*)data_out, (uint8_t *)data_in, (uint16_t)len) == HAL_OK; + // while(HAL_GPIO_ReadPin(pin_port(self->cs_pin->port), pin_mask(self->cs_pin->number))) { + // RUN_BACKGROUND_TASKS; + // // Allow user to break out of a timeout with a KeyboardInterrupt. + // if ( mp_hal_is_interrupted() ) { + // return 0; + // } + // } + + return HAL_SPI_TransmitReceive_DMA(&self->handle, (uint8_t*)redata_out, (uint8_t *)redata_in, (uint16_t)len) == HAL_OK; + __enable_irq(); } void HAL_SPI_TxRxCpltCallback(SPI_HandleTypeDef *hspi) @@ -202,6 +319,25 @@ void HAL_SPI_ErrorCallback(SPI_HandleTypeDef *hspi) txrx_error = true; } +void DMA1_Stream3_IRQHandler(void) +{ + if (g_dma_handle_rx) { + HAL_DMA_IRQHandler(g_dma_handle_rx); + } +} + +void DMA1_Stream4_IRQHandler(void) +{ + if (g_dma_handle_tx) { + HAL_DMA_IRQHandler(g_dma_handle_tx); + } +} + +// void SPI2_IRQHandler(void) +// { +// HAL_SPI_IRQHandler(&SpiHandle); +// } + void SPI1_IRQHandler(void) { if (handles[0]) { HAL_SPI_IRQHandler(&handles[0]->handle); diff --git a/ports/stm/common-hal/spiperipheral/SPIPeripheral.h b/ports/stm/common-hal/spiperipheral/SPIPeripheral.h index 3ec7826a342b..bce19f2a8cec 100644 --- a/ports/stm/common-hal/spiperipheral/SPIPeripheral.h +++ b/ports/stm/common-hal/spiperipheral/SPIPeripheral.h @@ -40,6 +40,8 @@ typedef struct { const mcu_periph_obj_t *mosi; const mcu_periph_obj_t *miso; const mcu_pin_obj_t *cs_pin; + DMA_HandleTypeDef dma_handle_tx; + DMA_HandleTypeDef dma_handle_rx; uint32_t baudrate; uint16_t prescaler; uint8_t polarity; @@ -47,4 +49,6 @@ typedef struct { uint8_t bits; } spiperipheral_spi_peripheral_obj_t; +void spiperipheral_reset(void); + #endif // MICROPY_INCLUDED_STM32_COMMON_HAL_SPIPERIPHERAL_SPI_PERIPHERAL_H diff --git a/ports/stm/peripherals/dma.c b/ports/stm/peripherals/dma.c new file mode 100644 index 000000000000..919717bb75a7 --- /dev/null +++ b/ports/stm/peripherals/dma.c @@ -0,0 +1,261 @@ +/* + * This file is part of the Micro Python project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Lucian Copeland 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 "peripherals/dma.h" + +static DMA_HandleTypeDef * dma1_handles[8]; +static DMA_HandleTypeDef * dma2_handles[8]; + +void dma_reset(void) { + for (int i = 0; i < 8; i++) { + dma1_handles[i] = NULL; + dma2_handles[i] = NULL; + } +} + +bool stm32_peripherals_dma_init(DMA_HandleTypeDef* handle, uint8_t dma_index, uint8_t stream_idx, + uint32_t channel, uint32_t direction, uint32_t priority, uint32_t subprio) { + + DMA_Stream_TypeDef* stream; + if (dma_index == 1) { + __HAL_RCC_DMA1_CLK_ENABLE(); + stream = (DMA_Stream_TypeDef*)dma1_stream_map[stream_idx]; + dma1_handles[stream_idx] = handle; + } else if (dma_index == 2) { + __HAL_RCC_DMA2_CLK_ENABLE(); + stream = (DMA_Stream_TypeDef*)dma2_stream_map[stream_idx]; + dma2_handles[stream_idx] = handle; + } else { + return false; + } + + handle->Instance = stream; + handle->Init.Channel = channel; + handle->Init.Direction = direction; + handle->Init.PeriphInc = DMA_PINC_DISABLE; + handle->Init.MemInc = DMA_MINC_ENABLE; + handle->Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE; + handle->Init.MemDataAlignment = DMA_MDATAALIGN_BYTE; + handle->Init.Mode = DMA_NORMAL; + handle->Init.Priority = priority; + handle->Init.FIFOMode = DMA_FIFOMODE_DISABLE; + handle->Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL; + handle->Init.MemBurst = DMA_MBURST_INC4; + handle->Init.PeriphBurst = DMA_PBURST_INC4; + if (HAL_DMA_Init(handle) != HAL_OK) { + return false; + } + + if (dma_index == 1) { + HAL_NVIC_SetPriority(dma1_irq_map[stream_idx], 0, subprio); + HAL_NVIC_EnableIRQ(dma1_irq_map[stream_idx]); + } else if (dma_index == 2) { + HAL_NVIC_SetPriority(dma2_irq_map[stream_idx], 0, subprio); + HAL_NVIC_EnableIRQ(dma2_irq_map[stream_idx]); + } + + return true; +} + +bool stm32_peripherals_dma_get_params(dma_channel_type dma_type, uint8_t periph_idx, + uint8_t* dma_idx, uint8_t* stream_idx, uint32_t* channel) { + // Iterate through DMA channel options until one matches the desired peripheral (SPI1_TX, etc) + // TODO: implement reservation system + for (size_t i = 0; i < (sizeof(dma_map)/sizeof(*dma_map)); i++) { + if (dma_map[i].type == dma_type && periph_idx == dma_map[i].periph_index) { + *dma_idx = dma_map[i].dma_index; + *stream_idx = dma_map[i].stream_index; + *channel = dma_map[i].channel; + return true; + } + } + // No matching options found. + return false; +} + +// Only call handles if they exist, else ignore +#define DMA_IRQ_CALLHANDLE(arr, idx) if (arr[idx]) HAL_DMA_IRQHandler(arr[idx]); + +// void DMA1_Stream0_IRQHandler(void) { +// DMA_IRQ_CALLHANDLE(dma1_handles, 0); +// } +// void DMA1_Stream1_IRQHandler(void) { +// DMA_IRQ_CALLHANDLE(dma1_handles, 1); +// } +// void DMA1_Stream2_IRQHandler(void) { +// DMA_IRQ_CALLHANDLE(dma1_handles, 2); +// } +// void DMA1_Stream3_IRQHandler(void) { +// DMA_IRQ_CALLHANDLE(dma1_handles, 3); +// } +// void DMA1_Stream4_IRQHandler(void) { +// DMA_IRQ_CALLHANDLE(dma1_handles, 4); +// } +// void DMA1_Stream5_IRQHandler(void) { +// DMA_IRQ_CALLHANDLE(dma1_handles, 5); +// } +// void DMA1_Stream6_IRQHandler(void) { +// DMA_IRQ_CALLHANDLE(dma1_handles, 6); +// } +// void DMA1_Stream7_IRQHandler(void) { +// DMA_IRQ_CALLHANDLE(dma1_handles, 7); +// } + +// void DMA2_Stream0_IRQHandler(void) { +// DMA_IRQ_CALLHANDLE(dma2_handles, 0); +// } +// void DMA2_Stream1_IRQHandler(void) { +// DMA_IRQ_CALLHANDLE(dma2_handles, 1); +// } +// void DMA2_Stream2_IRQHandler(void) { +// DMA_IRQ_CALLHANDLE(dma2_handles, 2); +// } +// void DMA2_Stream3_IRQHandler(void) { +// DMA_IRQ_CALLHANDLE(dma2_handles, 3); +// } +// void DMA2_Stream4_IRQHandler(void) { +// DMA_IRQ_CALLHANDLE(dma2_handles, 4); +// } +// void DMA2_Stream5_IRQHandler(void) { +// DMA_IRQ_CALLHANDLE(dma2_handles, 5); +// } +// void DMA2_Stream6_IRQHandler(void) { +// DMA_IRQ_CALLHANDLE(dma2_handles, 6); +// } +// void DMA2_Stream7_IRQHandler(void) { +// DMA_IRQ_CALLHANDLE(dma2_handles, 7); +// } + +const IRQn_Type dma1_irq_map[8] = { + DMA1_Stream0_IRQn, + DMA1_Stream1_IRQn, + DMA1_Stream2_IRQn, + DMA1_Stream3_IRQn, + DMA1_Stream4_IRQn, + DMA1_Stream5_IRQn, + DMA1_Stream6_IRQn, + DMA1_Stream7_IRQn, +}; + +const IRQn_Type dma2_irq_map[8] = { + DMA2_Stream0_IRQn, + DMA2_Stream1_IRQn, + DMA2_Stream2_IRQn, + DMA2_Stream3_IRQn, + DMA2_Stream4_IRQn, + DMA2_Stream5_IRQn, + DMA2_Stream6_IRQn, + DMA2_Stream7_IRQn, +}; + +const DMA_Stream_TypeDef* dma1_stream_map[8] = { + DMA1_Stream0, + DMA1_Stream1, + DMA1_Stream2, + DMA1_Stream3, + DMA1_Stream4, + DMA1_Stream5, + DMA1_Stream6, + DMA1_Stream7, +}; + +const DMA_Stream_TypeDef* dma2_stream_map[8] = { + DMA2_Stream0, + DMA2_Stream1, + DMA2_Stream2, + DMA2_Stream3, + DMA2_Stream4, + DMA2_Stream5, + DMA2_Stream6, + DMA2_Stream7, +}; + +const dma_map_obj dma_map[34] = { + DMA_MAP(DMA_SPI_RX, 3, 1, 0, DMA_CHANNEL_0), + //------------------------------------------------- + DMA_MAP(DMA_SPI_RX, 3, 1, 2, DMA_CHANNEL_0), + DMA_MAP(DMA_SPI_RX, 2, 1, 3, DMA_CHANNEL_0), + DMA_MAP(DMA_SPI_TX, 2, 1, 4, DMA_CHANNEL_0), + DMA_MAP(DMA_SPI_TX, 3, 1, 5, DMA_CHANNEL_0), + //------------------------------------------------- + DMA_MAP(DMA_SPI_TX, 3, 1, 7, DMA_CHANNEL_0), + + DMA_MAP(DMA_I2C_RX, 1, 1, 0, DMA_CHANNEL_1), + //------------------------------------------------- + DMA_MAP(DMA_TIM_UP, 7, 1, 2, DMA_CHANNEL_1), + //------------------------------------------------- + DMA_MAP(DMA_TIM_UP, 7, 1, 4, DMA_CHANNEL_1), + DMA_MAP(DMA_I2C_RX, 1, 1, 5, DMA_CHANNEL_1), + DMA_MAP(DMA_I2C_TX, 1, 1, 6, DMA_CHANNEL_1), + DMA_MAP(DMA_I2C_TX, 1, 1, 7, DMA_CHANNEL_1), + + DMA_MAP(DMA_TIM_CH1, 4, 1, 0, DMA_CHANNEL_2), + //----------------------------------------------------- + DMA_MAP(DMA_I2S_EXT_RX, 3, 1, 2, DMA_CHANNEL_2), + DMA_MAP(DMA_TIM_CH2, 4, 1, 3, DMA_CHANNEL_2), + DMA_MAP(DMA_I2S_EXT_TX, 2, 1, 4, DMA_CHANNEL_2), + DMA_MAP(DMA_I2S_EXT_TX, 3, 1, 5, DMA_CHANNEL_2), + DMA_MAP(DMA_TIM_UP, 4, 1, 6, DMA_CHANNEL_2), + DMA_MAP(DMA_TIM_CH3, 4, 1, 7, DMA_CHANNEL_2), + + DMA_MAP(DMA_I2S_EXT_RX, 3, 1, 0, DMA_CHANNEL_3), + DMA_MAP(DMA_TIM_UP, 2, 1, 1, DMA_CHANNEL_3), + DMA_MAP(DMA_TIM_CH3, 2, 1, 1, DMA_CHANNEL_3), + DMA_MAP(DMA_I2C_RX, 3, 1, 2, DMA_CHANNEL_3), + DMA_MAP(DMA_I2S_EXT_RX, 2, 1, 3, DMA_CHANNEL_3), + DMA_MAP(DMA_I2C_TX, 3, 1, 4, DMA_CHANNEL_3), + DMA_MAP(DMA_TIM_CH1, 2, 1, 5, DMA_CHANNEL_3), + DMA_MAP(DMA_TIM_CH2, 2, 1, 6, DMA_CHANNEL_3), + DMA_MAP(DMA_TIM_CH4, 2, 1, 6, DMA_CHANNEL_3), + DMA_MAP(DMA_TIM_UP, 2, 1, 7, DMA_CHANNEL_3), + DMA_MAP(DMA_TIM_CH4, 2, 1, 7, DMA_CHANNEL_3), + + //CH4 + //CH5 + //CH6 + //CH7 + + //DMA2 ----- + + //CH0 + //CH1 + //CH2 + + //CH3 + DMA_MAP(DMA_SPI_RX, 1, 2, 0, DMA_CHANNEL_3), + //-----------------2------------------------------- + DMA_MAP(DMA_SPI_RX, 1, 2, 2, DMA_CHANNEL_3), + DMA_MAP(DMA_SPI_TX, 1, 2, 3, DMA_CHANNEL_3), + //------------------------------------------------- + DMA_MAP(DMA_SPI_TX, 1, 2, 5, DMA_CHANNEL_3), + //------------------------------------------------- + //------------------------------------------------- + + //CH4 + //CH5 + //CH6 + //CH7 +}; diff --git a/ports/stm/peripherals/dma.h b/ports/stm/peripherals/dma.h new file mode 100644 index 000000000000..b69d719d2edd --- /dev/null +++ b/ports/stm/peripherals/dma.h @@ -0,0 +1,91 @@ +/* + * This file is part of the Micro Python project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Lucian Copeland 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_STM32_PERIPHERALS_DMA_H__ +#define __MICROPY_INCLUDED_STM32_PERIPHERALS_DMA_H__ + +#include STM32_HAL_H + +#include +#include + +typedef enum { + DMA_SPI_RX, + DMA_SPI_TX, + DMA_I2C_RX, + DMA_I2C_TX, + DMA_I2S_EXT_RX, + DMA_I2S_EXT_TX, + DMA_TIM_UP, + DMA_TIM_TRIG, + DMA_TIM_CH1, + DMA_TIM_CH2, + DMA_TIM_CH3, + DMA_TIM_CH4, + DMA_UART_RX, + DMA_UART_TX, + DMA_USART_RX, + DMA_USART_TX, + DMA_SAI_A, + DMA_SAI_B, + DMA_DCMI, + DMA_ADC, + DMA_DAC, + DMA_CRYP_IN, + DMA_HASH_IN, + DMA_CRYP_OUT, + DMA_SDIO, +} dma_channel_type; + +typedef struct { + const dma_channel_type type; + const uint8_t periph_index; + const uint8_t dma_index; + const uint8_t stream_index; + const uint32_t channel; +} dma_map_obj; + +#define DMA_MAP(t, i, d, s, c) \ +{ \ + .type = t, \ + .periph_index = i, \ + .dma_index = d, \ + .stream_index = s, \ + .channel = c, \ +} + +void dma_reset(void); +bool stm32_peripherals_dma_init(DMA_HandleTypeDef* handle, uint8_t dma_index, uint8_t stream_idx, + uint32_t channel, uint32_t direction, uint32_t priority, uint32_t subprio); +bool stm32_peripherals_dma_get_params(dma_channel_type dma_type, uint8_t periph_idx, + uint8_t* dma_idx, uint8_t* stream_idx, uint32_t* channel); +extern const IRQn_Type dma1_irq_map[8]; +extern const IRQn_Type dma2_irq_map[8]; +extern const DMA_Stream_TypeDef* dma1_stream_map[8]; +extern const DMA_Stream_TypeDef* dma2_stream_map[8]; +extern const dma_map_obj dma_map[34]; + +#endif // __MICROPY_INCLUDED_STM32_PERIPHERALS_DMA_H__ diff --git a/ports/stm/supervisor/port.c b/ports/stm/supervisor/port.c index a8aab00ff25e..395a318c949f 100644 --- a/ports/stm/supervisor/port.c +++ b/ports/stm/supervisor/port.c @@ -50,6 +50,9 @@ #if CIRCUITPY_SDIOIO #include "common-hal/sdioio/SDCard.h" #endif +#if CIRCUITPY_SPIPERIPHERAL +#include "common-hal/spiperipheral/SPIPeripheral.h" +#endif #include "clocks.h" #include "gpio.h" @@ -247,6 +250,9 @@ void reset_port(void) { #if CIRCUITPY_PWMIO pwmout_reset(); #endif +#if CIRCUITPY_SPIPERIPHERAL + spiperipheral_reset(); +#endif } void reset_to_bootloader(void) {