From 6b407d5600620dfd6670304b77008d92fd19388b Mon Sep 17 00:00:00 2001 From: iabdalkader Date: Tue, 2 May 2023 12:34:12 +0200 Subject: [PATCH 1/6] mimxrt/machine_pin: Extend pin configuration functions. Add portable pin config macros to mphalport.h. And add a function to configure pins with more pin options such as alt function, pull, speed, drive, interrupt mode, etc. Note: this new `machine_pin_config()` function can replace `machine_pin_set_mode()`, but the latter is left as-is to avoid breaking anything. Signed-off-by: iabdalkader --- ports/mimxrt/machine_pin.c | 54 ++++++++++++++++++++++++++++++++++++++ ports/mimxrt/mphalport.h | 19 ++++++++++++++ ports/mimxrt/pin.h | 9 +++++++ 3 files changed, 82 insertions(+) diff --git a/ports/mimxrt/machine_pin.c b/ports/mimxrt/machine_pin.c index c66718e976cb8..5dfb2b72e29af 100644 --- a/ports/mimxrt/machine_pin.c +++ b/ports/mimxrt/machine_pin.c @@ -187,6 +187,60 @@ void machine_pin_set_mode(const machine_pin_obj_t *self, uint8_t mode) { GPIO_PinInit(self->gpio, self->pin, &pin_config); } +void machine_pin_config(const machine_pin_obj_t *self, uint8_t mode, + uint8_t pull, uint8_t drive, uint8_t speed, uint8_t alt) { + (void)speed; + gpio_pin_config_t pin_config = {0}; + + if (IS_GPIO_IT_MODE(mode)) { + if (mode == PIN_MODE_IT_FALLING) { + pin_config.interruptMode = kGPIO_IntFallingEdge; + } else if (mode == PIN_MODE_IT_RISING) { + pin_config.interruptMode = kGPIO_IntRisingEdge; + } else if (mode == PIN_MODE_IT_BOTH) { + pin_config.interruptMode = kGPIO_IntRisingOrFallingEdge; + } + // Set pad config mode to input. + mode = PIN_MODE_IN; + } + + if (mode == PIN_MODE_IN) { + pin_config.direction = kGPIO_DigitalInput; + } else { + pin_config.direction = kGPIO_DigitalOutput; + } + + if (mode != PIN_MODE_ALT) { + // GPIO is always ALT5 + alt = PIN_AF_MODE_ALT5; + } + + const machine_pin_af_obj_t *af = pin_find_af(self, alt); + if (af == NULL) { + return; + } + + // Configure the pad. + uint32_t pad_config = pin_generate_config(pull, mode, drive, self->configRegister); + IOMUXC_SetPinMux(self->muxRegister, alt, af->input_register, af->input_daisy, self->configRegister, 0U); + IOMUXC_SetPinConfig(self->muxRegister, alt, af->input_register, af->input_daisy, self->configRegister, pad_config); + + // Initialize the pin. + GPIO_PinInit(self->gpio, self->pin, &pin_config); + + // Configure interrupt (if enabled). + if (pin_config.interruptMode != kGPIO_NoIntmode) { + uint32_t gpio_nr = GPIO_get_instance(self->gpio); + uint32_t irq_num = self->pin < 16 ? GPIO_combined_low_irqs[gpio_nr] : GPIO_combined_high_irqs[gpio_nr]; + + GPIO_PortEnableInterrupts(self->gpio, 1U << self->pin); + GPIO_PortClearInterruptFlags(self->gpio, ~0); + + NVIC_SetPriority(irq_num, IRQ_PRI_EXTINT); + EnableIRQ(irq_num); + } +} + STATIC mp_obj_t machine_pin_obj_call(mp_obj_t self_in, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *args) { mp_arg_check_num(n_args, n_kw, 0, 1, false); machine_pin_obj_t *self = self_in; diff --git a/ports/mimxrt/mphalport.h b/ports/mimxrt/mphalport.h index ba7e1cfa94165..1813a9834b165 100644 --- a/ports/mimxrt/mphalport.h +++ b/ports/mimxrt/mphalport.h @@ -38,6 +38,25 @@ #define MICROPY_HW_USB_CDC_TX_TIMEOUT (500) #define MP_HAL_PIN_FMT "%q" +#define MP_HAL_PIN_MODE_INPUT PIN_MODE_IN +#define MP_HAL_PIN_MODE_OUTPUT PIN_MODE_OUT +#define MP_HAL_PIN_MODE_ALT PIN_MODE_ALT +#define MP_HAL_PIN_MODE_OPEN_DRAIN PIN_MODE_OPEN_DRAIN + +#define MP_HAL_PIN_PULL_NONE PIN_PULL_DISABLED +#define MP_HAL_PIN_PULL_UP PIN_PULL_UP_100K +#define MP_HAL_PIN_PULL_DOWN PIN_PULL_DOWN_100K + +#define MP_HAL_PIN_SPEED_LOW (0) +#define MP_HAL_PIN_SPEED_MEDIUM (1) +#define MP_HAL_PIN_SPEED_HIGH (2) +#define MP_HAL_PIN_SPEED_VERY_HIGH (3) + +#define MP_HAL_PIN_TRIGGER_NONE kGPIO_NoIntmode +#define MP_HAL_PIN_TRIGGER_FALL kGPIO_IntFallingEdge +#define MP_HAL_PIN_TRIGGER_RISE kGPIO_IntRisingEdge +#define MP_HAL_PIN_TRIGGER_RISE_FALL kGPIO_IntRisingOrFallingEdge + extern ringbuf_t stdin_ringbuf; // Define an alias for systick_ms, because the shared softtimer.c uses diff --git a/ports/mimxrt/pin.h b/ports/mimxrt/pin.h index 63db55f8a7c55..aa86f05e82d46 100644 --- a/ports/mimxrt/pin.h +++ b/ports/mimxrt/pin.h @@ -39,6 +39,10 @@ ((MODE) == PIN_MODE_OPEN_DRAIN) || \ ((MODE) == PIN_MODE_ALT)) +#define IS_GPIO_IT_MODE(MODE) (((MODE) == PIN_MODE_IT_RISING) || \ + ((MODE) == PIN_MODE_IT_FALLING) || \ + ((MODE) == PIN_MODE_IT_BOTH)) + #define IS_GPIO_DRIVE(DRIVE) (((DRIVE) == PIN_DRIVE_OFF) || \ ((DRIVE) == PIN_DRIVE_0) || \ ((DRIVE) == PIN_DRIVE_1) || \ @@ -56,6 +60,9 @@ enum { PIN_MODE_OPEN_DRAIN, PIN_MODE_ALT, PIN_MODE_SKIP, + PIN_MODE_IT_RISING, + PIN_MODE_IT_FALLING, + PIN_MODE_IT_BOTH, }; enum { @@ -161,6 +168,8 @@ const machine_pin_af_obj_t *pin_find_af(const machine_pin_obj_t *pin, uint8_t fn const machine_pin_af_obj_t *pin_find_af_by_index(const machine_pin_obj_t *pin, mp_uint_t af_idx); const machine_pin_af_obj_t *pin_find_af_by_name(const machine_pin_obj_t *pin, const char *name); void machine_pin_set_mode(const machine_pin_obj_t *pin, uint8_t mode); +void machine_pin_config(const machine_pin_obj_t *self, uint8_t mode, + uint8_t pull, uint8_t drive, uint8_t speed, uint8_t alt); uint32_t pin_generate_config(const uint32_t pull, const uint32_t mode, const uint32_t drive, uint32_t config_register); #endif // MICROPY_INCLUDED_MIMXRT_PIN_H From 46d83d97484790c163d4276e2472fc925aaaf8ff Mon Sep 17 00:00:00 2001 From: iabdalkader Date: Tue, 2 May 2023 12:44:46 +0200 Subject: [PATCH 2/6] mimxrt/sdio: Add SDIO driver. This is a basic SDIO driver for the mimxrt port, that was added mainly to support the CYW43 WiFi driver, and as such it only supports the commands required by the CYW43 driver (but more commands can be added easily). The driver performs non-blocking DMA transfers, and can detect and recover from errors. Note: because the mimxrt port is missing static alternate functions, named pins and other pin related functions, currently the alternate functions for USDHC 1 and 2 are hard-coded in the driver. Signed-off-by: iabdalkader --- ports/mimxrt/Makefile | 1 + ports/mimxrt/sdio.c | 334 ++++++++++++++++++++++++++++++++++++++++++ ports/mimxrt/sdio.h | 40 +++++ 3 files changed, 375 insertions(+) create mode 100644 ports/mimxrt/sdio.c create mode 100644 ports/mimxrt/sdio.h diff --git a/ports/mimxrt/Makefile b/ports/mimxrt/Makefile index 8cb46245aec97..f74e957c313f6 100644 --- a/ports/mimxrt/Makefile +++ b/ports/mimxrt/Makefile @@ -216,6 +216,7 @@ SRC_C += \ pendsv.c \ pin.c \ sdcard.c \ + sdio.c \ systick.c \ ticks.c \ tusb_port.c \ diff --git a/ports/mimxrt/sdio.c b/ports/mimxrt/sdio.c new file mode 100644 index 0000000000000..771a01e3d94ac --- /dev/null +++ b/ports/mimxrt/sdio.c @@ -0,0 +1,334 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2023 Ibrahim Abdelkader + * + * 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/mperrno.h" +#include "py/mphal.h" +#include "pin.h" +#include "pendsv.h" + +#include "fsl_usdhc.h" +#include "fsl_iomuxc.h" + +#if MICROPY_PY_NETWORK_CYW43 + +#if MICROPY_HW_SDIO_SDMMC == 1 +#define SDMMC USDHC1 +#define SDMMC_IRQn USDHC1_IRQn +#define SDMMC_CLOCK_DIV kCLOCK_Usdhc1Div +#define SDMMC_CLOCK_MUX kCLOCK_Usdhc1Mux +#ifndef MICROPY_HW_SDIO_CLK_ALT +#define MICROPY_HW_SDIO_CMD_ALT (0) +#define MICROPY_HW_SDIO_CLK_ALT (0) +#define MICROPY_HW_SDIO_D0_ALT (0) +#define MICROPY_HW_SDIO_D1_ALT (0) +#define MICROPY_HW_SDIO_D2_ALT (0) +#define MICROPY_HW_SDIO_D3_ALT (0) +#endif +#else +#define SDMMC USDHC2 +#define SDMMC_IRQn USDHC2_IRQn +#define SDMMC_CLOCK_DIV kCLOCK_Usdhc2Div +#define SDMMC_CLOCK_MUX kCLOCK_Usdhc2Mux +#ifndef MICROPY_HW_SDIO_CLK_ALT +#define MICROPY_HW_SDIO_CMD_ALT (6) +#define MICROPY_HW_SDIO_CLK_ALT (6) +#define MICROPY_HW_SDIO_D0_ALT (6) +#define MICROPY_HW_SDIO_D1_ALT (6) +#define MICROPY_HW_SDIO_D2_ALT (6) +#define MICROPY_HW_SDIO_D3_ALT (6) +#endif +#endif + +#define SDMMC_CLOCK_400KHZ (400000U) +#define SDMMC_CLOCK_25MHZ (25000000U) +#define SDMMC_CLOCK_50MHZ (50000000U) + +#if SDIO_DEBUG +#define debug_printf(...) mp_printf(&mp_plat_print, __VA_ARGS__) +#else +#define debug_printf(...) +#endif + +#define DMA_DESCRIPTOR_BUFFER_SIZE (32U) +AT_NONCACHEABLE_SECTION_ALIGN( + static uint32_t sdio_adma_descriptor_table[DMA_DESCRIPTOR_BUFFER_SIZE], USDHC_ADMA2_ADDRESS_ALIGN); + +typedef struct _mimxrt_sdmmc_t { + USDHC_Type *inst; + usdhc_handle_t handle; + volatile uint32_t xfer_flags; + volatile uint32_t xfer_error; +} mimxrt_sdmmc_t; + +static mimxrt_sdmmc_t sdmmc = { + .inst = SDMMC, +}; + +typedef enum { + SDIO_TRANSFER_DATA_COMPLETE = (1 << 0), + SDIO_TRANSFER_CMD_COMPLETE = (1 << 1), + SDIO_TRANSFER_ERROR = (1 << 2), +} sdio_xfer_flags_t; + +static uint32_t sdio_base_clk(void) { + return CLOCK_GetSysPfdFreq(kCLOCK_Pfd0) / (CLOCK_GetDiv(kCLOCK_Usdhc1Div) + 1U); +} + +static uint32_t sdio_response_type(uint32_t cmd) { + switch (cmd) { + case 3: + return kCARD_ResponseTypeR6; + case 5: + return kCARD_ResponseTypeR4; + case 7: + return kCARD_ResponseTypeR1; + case 52: + return kCARD_ResponseTypeR5; + default: + return kCARD_ResponseTypeNone; + } +} + +static void sdio_transfer_callback(USDHC_Type *base, + usdhc_handle_t *handle, status_t status, void *userData) { + if (status == kStatus_USDHC_TransferDataComplete) { + sdmmc.xfer_flags |= SDIO_TRANSFER_DATA_COMPLETE; + } else if (status == kStatus_USDHC_SendCommandSuccess) { + sdmmc.xfer_flags |= SDIO_TRANSFER_CMD_COMPLETE; + } else if (status != kStatus_USDHC_BusyTransferring) { + sdmmc.xfer_error = status; + sdmmc.xfer_flags |= SDIO_TRANSFER_ERROR; + } +} + +static void sdio_interrupt_callback(USDHC_Type *base, void *userData) { + extern void (*cyw43_poll)(void); + + USDHC_DisableInterruptSignal(base, kUSDHC_CardInterruptFlag); + USDHC_ClearInterruptStatusFlags(base, kUSDHC_CardInterruptFlag); + + if (cyw43_poll) { + pendsv_schedule_dispatch(PENDSV_DISPATCH_CYW43, cyw43_poll); + } +} + +void sdio_init(uint32_t irq_pri) { + machine_pin_config(MICROPY_HW_SDIO_CMD, PIN_MODE_ALT, PIN_PULL_UP_100K, PIN_DRIVE_6, 0, MICROPY_HW_SDIO_CMD_ALT); + machine_pin_config(MICROPY_HW_SDIO_CLK, PIN_MODE_ALT, PIN_PULL_DISABLED, PIN_DRIVE_6, 0, MICROPY_HW_SDIO_CLK_ALT); + machine_pin_config(MICROPY_HW_SDIO_D0, PIN_MODE_ALT, PIN_PULL_UP_100K, PIN_DRIVE_6, 0, MICROPY_HW_SDIO_D0_ALT); + machine_pin_config(MICROPY_HW_SDIO_D1, PIN_MODE_ALT, PIN_PULL_UP_100K, PIN_DRIVE_6, 0, MICROPY_HW_SDIO_D1_ALT); + machine_pin_config(MICROPY_HW_SDIO_D2, PIN_MODE_ALT, PIN_PULL_UP_100K, PIN_DRIVE_6, 0, MICROPY_HW_SDIO_D2_ALT); + machine_pin_config(MICROPY_HW_SDIO_D3, PIN_MODE_ALT, PIN_PULL_UP_100K, PIN_DRIVE_6, 0, MICROPY_HW_SDIO_D3_ALT); + + // Configure PFD0 of PLL2 (system PLL) fractional divider to 24 resulting in: + // with PFD0_clk = PLL2_clk * 18 / N + // PFD0_clk = 528MHz * 18 / 24 = 396MHz + CLOCK_InitSysPfd(kCLOCK_Pfd0, 24U); + CLOCK_SetDiv(SDMMC_CLOCK_DIV, 1U); // USDHC_input_clk = PFD0_clk / 2 + CLOCK_SetMux(SDMMC_CLOCK_MUX, 1U); // Select PFD0 as clock input for USDHC + + // Initialize USDHC + const usdhc_config_t config = { + .endianMode = kUSDHC_EndianModeLittle, + .dataTimeout = 0xFU, + .readBurstLen = 0, + .writeBurstLen = 0, + .readWatermarkLevel = 128U, + .writeWatermarkLevel = 128U, + }; + + USDHC_Init(sdmmc.inst, &config); + USDHC_Reset(SDMMC, kUSDHC_ResetAll, 1000U); + USDHC_DisableInterruptSignal(SDMMC, kUSDHC_AllInterruptFlags); + USDHC_SetSdClock(sdmmc.inst, sdio_base_clk(), SDMMC_CLOCK_25MHZ); + USDHC_SetDataBusWidth(sdmmc.inst, kUSDHC_DataBusWidth1Bit); + + mp_hal_delay_ms(10); + + NVIC_SetPriority(SDMMC_IRQn, irq_pri); + EnableIRQ(SDMMC_IRQn); + + usdhc_transfer_callback_t callbacks = { + .SdioInterrupt = sdio_interrupt_callback, + .TransferComplete = sdio_transfer_callback, + }; + USDHC_TransferCreateHandle(sdmmc.inst, &sdmmc.handle, &callbacks, NULL); +} + +void sdio_deinit(void) { +} + +void sdio_reenable(void) { +} + +void sdio_enable_irq(bool enable) { + if (enable) { + USDHC_ClearInterruptStatusFlags(sdmmc.inst, kUSDHC_CardInterruptFlag); + USDHC_EnableInterruptStatus(sdmmc.inst, kUSDHC_CardInterruptFlag); + USDHC_EnableInterruptSignal(sdmmc.inst, kUSDHC_CardInterruptFlag); + } else { + USDHC_DisableInterruptStatus(sdmmc.inst, kUSDHC_CardInterruptFlag); + USDHC_ClearInterruptStatusFlags(sdmmc.inst, kUSDHC_CardInterruptFlag); + USDHC_DisableInterruptSignal(sdmmc.inst, kUSDHC_CardInterruptFlag); + } +} + +void sdio_enable_high_speed_4bit(void) { + USDHC_SetSdClock(sdmmc.inst, sdio_base_clk(), SDMMC_CLOCK_50MHZ); + USDHC_SetDataBusWidth(sdmmc.inst, kUSDHC_DataBusWidth4Bit); +} + +static status_t sdio_transfer_dma(USDHC_Type *base, + usdhc_handle_t *handle, usdhc_transfer_t *transfer, uint32_t timeout_ms) { + status_t status; + usdhc_adma_config_t dma_config = { + .dmaMode = kUSDHC_DmaModeAdma2, + #if !FSL_FEATURE_USDHC_HAS_NO_RW_BURST_LEN + .burstLen = kUSDHC_EnBurstLenForINCR, + #endif + .admaTable = sdio_adma_descriptor_table, + .admaTableWords = DMA_DESCRIPTOR_BUFFER_SIZE, + }; + + sdmmc.xfer_flags = 0; + sdmmc.xfer_error = 0; + + uint32_t xfer_flags = SDIO_TRANSFER_CMD_COMPLETE; + if (transfer->data != NULL) { + xfer_flags |= SDIO_TRANSFER_DATA_COMPLETE; + } + + status = USDHC_TransferNonBlocking(base, handle, &dma_config, transfer); + if (status != kStatus_Success) { + debug_printf("sdio_transfer_dma failed to start transfer error: %lu\n", status); + return status; + } + + uint32_t start = mp_hal_ticks_ms(); + while ((sdmmc.xfer_flags != xfer_flags) && + !(sdmmc.xfer_flags & SDIO_TRANSFER_ERROR) && + (mp_hal_ticks_ms() - start) < timeout_ms) { + MICROPY_EVENT_POLL_HOOK; + } + + if (sdmmc.xfer_flags == 0) { + debug_printf("sdio_transfer_dma transfer timeout.\n"); + return kStatus_Timeout; + } else if (sdmmc.xfer_flags != xfer_flags) { + debug_printf("sdio_transfer_dma transfer failed: %lu\n", sdmmc.xfer_error); + USDHC_Reset(base, kUSDHC_ResetCommand, 100); + if (xfer_flags & SDIO_TRANSFER_DATA_COMPLETE) { + USDHC_Reset(base, kUSDHC_ResetData, 100); + } + return sdmmc.xfer_error; + } + + return kStatus_Success; +} + +int sdio_transfer(uint32_t cmd, uint32_t arg, uint32_t *resp) { + status_t status; + usdhc_command_t command = { + .index = cmd, + .argument = arg, + .type = kCARD_CommandTypeNormal, + .responseType = sdio_response_type(cmd), + .responseErrorFlags = 0 + }; + + usdhc_transfer_t transfer = { + .data = NULL, + .command = &command, + }; + + status = sdio_transfer_dma(sdmmc.inst, &sdmmc.handle, &transfer, 5000); + + if (status != kStatus_Success) { + debug_printf("sdio_transfer failed!\n"); + return -MP_EIO; + } + + if (resp != NULL) { + *resp = command.response[0]; + } + + return 0; +} + +int sdio_transfer_cmd53(bool write, uint32_t block_size, uint32_t arg, size_t len, uint8_t *buf) { + usdhc_data_t data = { + .enableAutoCommand12 = false, + .enableAutoCommand23 = false, + .enableIgnoreError = false, + .dataType = kUSDHC_TransferDataNormal, + }; + + usdhc_command_t command = { + .index = 53, + .argument = arg, + .type = kCARD_CommandTypeNormal, + .responseType = kCARD_ResponseTypeR5, + .responseErrorFlags = 0 + }; + + usdhc_transfer_t transfer = { + .data = &data, + .command = &command, + }; + + if (write) { + data.rxData = NULL; + data.txData = (uint32_t *)buf; + } else { + data.txData = NULL; + data.rxData = (uint32_t *)buf; + } + + if (arg & (1 << 27)) { + // SDIO_BLOCK_MODE + data.blockSize = block_size; + data.blockCount = len / block_size; + } else { + // SDIO_BYTE_MODE + data.blockSize = block_size; + data.blockCount = 1; + } + + debug_printf("cmd53 rw: %d addr 0x%p blocksize %u blockcount %lu total %lu len %d\n", + write, buf, data.blockSize, data.blockCount, data.blockSize * data.blockCount, len); + + status_t status = sdio_transfer_dma(sdmmc.inst, &sdmmc.handle, &transfer, 5000); + + if (status != kStatus_Success) { + debug_printf("sdio_transfer_cmd53 failed!\n"); + return -1; + } + + return 0; +} + +#endif diff --git a/ports/mimxrt/sdio.h b/ports/mimxrt/sdio.h new file mode 100644 index 0000000000000..f8d6f498b6485 --- /dev/null +++ b/ports/mimxrt/sdio.h @@ -0,0 +1,40 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2023 Ibrahim Abdelkader + * + * 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_MIMXRT_SDIO_H +#define MICROPY_INCLUDED_MIMXRT_SDIO_H + +#include +#include + +void sdio_init(uint32_t irq_pri); +void sdio_deinit(void); +void sdio_reenable(void); +void sdio_enable_irq(bool enable); +void sdio_enable_high_speed_4bit(void); +int sdio_transfer(uint32_t cmd, uint32_t arg, uint32_t *resp); +int sdio_transfer_cmd53(bool write, uint32_t block_size, uint32_t arg, size_t len, uint8_t *buf); + +#endif // MICROPY_INCLUDED_MIMXRT_SDIO_H From 772a36098f1b30ce1a5988c84471c7caec98b119 Mon Sep 17 00:00:00 2001 From: iabdalkader Date: Tue, 2 May 2023 12:44:05 +0200 Subject: [PATCH 3/6] mimxrt: Integrate support for WiFi via the CYW43 driver. This commit adds the necessary configuration and hooks to get the CYW43 driver working with the mimxrt port. Signed-off-by: iabdalkader --- ports/mimxrt/board_init.c | 1 + ports/mimxrt/cyw43_configport.h | 155 ++++++++++++++++++++++++++++++++ ports/mimxrt/machine_pin.c | 13 +++ ports/mimxrt/main.c | 14 +++ ports/mimxrt/mpconfigport.h | 8 ++ ports/mimxrt/mpnetworkport.c | 15 ++++ ports/mimxrt/pendsv.h | 3 + 7 files changed, 209 insertions(+) create mode 100644 ports/mimxrt/cyw43_configport.h diff --git a/ports/mimxrt/board_init.c b/ports/mimxrt/board_init.c index 78001862f05d2..9222b302b2337 100644 --- a/ports/mimxrt/board_init.c +++ b/ports/mimxrt/board_init.c @@ -63,6 +63,7 @@ void board_init(void) { // 1ms tick timer SysTick_Config(SystemCoreClock / 1000); + NVIC_SetPriority(SysTick_IRQn, NVIC_EncodePriority(NVIC_PRIORITYGROUP_4, 0, 0)); // USB0 usb_phy0_init(0b0111, 0b0110, 0b0110); // Configure nominal values for D_CAL and TXCAL45DP/DN diff --git a/ports/mimxrt/cyw43_configport.h b/ports/mimxrt/cyw43_configport.h new file mode 100644 index 0000000000000..5f96856474051 --- /dev/null +++ b/ports/mimxrt/cyw43_configport.h @@ -0,0 +1,155 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2022 Damien P. George + * Copyright (c) 2022 Jim Mussared + * + * 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_CYW43_CONFIGPORT_H +#define MICROPY_INCLUDED_STM32_CYW43_CONFIGPORT_H + +// The board-level config will be included here, so it can set some CYW43 values. +#include "py/mpconfig.h" +#include "py/mperrno.h" +#include "py/mphal.h" +#include "extmod/modnetwork.h" +#include "pendsv.h" +#include "sdio.h" + +#define CYW43_USE_SPI (0) +#define CYW43_LWIP (1) +#define CYW43_USE_STATS (0) + +#ifndef CYW43_CHIPSET_FIRMWARE_INCLUDE_FILE +#define CYW43_CHIPSET_FIRMWARE_INCLUDE_FILE "lib/cyw43-driver/firmware/w4343WA1_7_45_98_50_combined.h" +#endif + +#ifndef CYW43_WIFI_NVRAM_INCLUDE_FILE +#define CYW43_WIFI_NVRAM_INCLUDE_FILE "lib/cyw43-driver/firmware/wifi_nvram_1dx.h" +#endif + +#define CYW43_IOCTL_TIMEOUT_US (1000000) +#define CYW43_SLEEP_MAX (50) +#define CYW43_NETUTILS (1) +#define CYW43_CLEAR_SDIO_INT (1) + +#define CYW43_EPERM MP_EPERM // Operation not permitted +#define CYW43_EIO MP_EIO // I/O error +#define CYW43_EINVAL MP_EINVAL // Invalid argument +#define CYW43_ETIMEDOUT MP_ETIMEDOUT // Connection timed out + +#define CYW43_THREAD_ENTER MICROPY_PY_LWIP_ENTER +#define CYW43_THREAD_EXIT MICROPY_PY_LWIP_EXIT +#define CYW43_THREAD_LOCK_CHECK + +#define CYW43_HOST_NAME mod_network_hostname + +#define CYW43_SDPCM_SEND_COMMON_WAIT __WFI(); +#define CYW43_DO_IOCTL_WAIT __WFI(); + +#define CYW43_ARRAY_SIZE(a) MP_ARRAY_SIZE(a) + +#define CYW43_HAL_PIN_MODE_INPUT MP_HAL_PIN_MODE_INPUT +#define CYW43_HAL_PIN_MODE_OUTPUT MP_HAL_PIN_MODE_OUTPUT +#define CYW43_HAL_PIN_PULL_NONE MP_HAL_PIN_PULL_NONE +#define CYW43_HAL_PIN_PULL_UP MP_HAL_PIN_PULL_UP +#define CYW43_HAL_PIN_PULL_DOWN MP_HAL_PIN_PULL_DOWN + +#define CYW43_HAL_MAC_WLAN0 MP_HAL_MAC_WLAN0 + +#define cyw43_hal_ticks_us mp_hal_ticks_us +#define cyw43_hal_ticks_ms mp_hal_ticks_ms + +#define cyw43_hal_pin_obj_t mp_hal_pin_obj_t +#define cyw43_hal_pin_read mp_hal_pin_read +#define cyw43_hal_pin_low mp_hal_pin_low +#define cyw43_hal_pin_high mp_hal_pin_high + +#define cyw43_hal_get_mac mp_hal_get_mac +#define cyw43_hal_get_mac_ascii mp_hal_get_mac_ascii +#define cyw43_hal_generate_laa_mac mp_hal_generate_laa_mac + +#define cyw43_delay_us mp_hal_delay_us +#define cyw43_delay_ms mp_hal_delay_ms + +#define CYW43_PIN_WL_REG_ON MICROPY_HW_WL_REG_ON +#define CYW43_PIN_WL_HOST_WAKE MICROPY_HW_WL_HOST_WAKE +#define CYW43_PIN_WL_SDIO_1 MICROPY_HW_SDIO_D1 + +#define CYW43_PIN_BT_REG_ON MICROPY_HW_BT_REG_ON +#ifdef MICROPY_HW_BT_HOST_WAKE +#define CYW43_PIN_BT_HOST_WAKE MICROPY_HW_BT_HOST_WAKE +#endif +#ifdef MICROPY_HW_BT_DEV_WAKE +#define CYW43_PIN_BT_DEV_WAKE MICROPY_HW_BT_DEV_WAKE +#endif +#ifdef MICROPY_HW_BT_CTS +#define CYW43_PIN_BT_CTS MICROPY_HW_BT_CTS +#endif + +#if MICROPY_HW_ENABLE_RF_SWITCH +#define CYW43_PIN_WL_RFSW_VDD pin_WL_RFSW_VDD +#endif + +#define cyw43_schedule_internal_poll_dispatch(func) pendsv_schedule_dispatch(PENDSV_DISPATCH_CYW43, func) + +static inline void cyw43_hal_pin_config(cyw43_hal_pin_obj_t pin, uint8_t mode, uint8_t pull, uint8_t alt) { + machine_pin_set_mode(pin, mode); +} + +static inline void cyw43_hal_pin_config_irq_falling(cyw43_hal_pin_obj_t pin, int enable) { + if (enable) { + machine_pin_config(pin, PIN_MODE_IT_FALLING, PIN_PULL_UP_100K, 0, 0, PIN_AF_MODE_ALT5); + } +} + +static inline void cyw43_sdio_init(void) { + sdio_init(NVIC_EncodePriority(NVIC_PRIORITYGROUP_4, 14, 0)); +} + +static inline void cyw43_sdio_reinit(void) { + sdio_reenable(); +} + +static inline void cyw43_sdio_deinit(void) { + sdio_deinit(); +} + +static inline void cyw43_sdio_set_irq(bool enable) { + sdio_enable_irq(enable); +} + +static inline void cyw43_sdio_enable_high_speed_4bit(void) { + sdio_enable_high_speed_4bit(); +} + +static inline int cyw43_sdio_transfer(uint32_t cmd, uint32_t arg, uint32_t *resp) { + return sdio_transfer(cmd, arg, resp); +} + +static inline int cyw43_sdio_transfer_cmd53(bool write, uint32_t block_size, uint32_t arg, size_t len, uint8_t *buf) { + return sdio_transfer_cmd53(write, block_size, arg, len, buf); +} + +#define CYW43_EVENT_POLL_HOOK MICROPY_EVENT_POLL_HOOK + +#endif // MICROPY_INCLUDED_STM32_CYW43_CONFIGPORT_H diff --git a/ports/mimxrt/machine_pin.c b/ports/mimxrt/machine_pin.c index 5dfb2b72e29af..3ebccb1755ad8 100644 --- a/ports/mimxrt/machine_pin.c +++ b/ports/mimxrt/machine_pin.c @@ -34,6 +34,9 @@ #include "shared/runtime/mpirq.h" #include "extmod/virtpin.h" #include "pin.h" +#if MICROPY_PY_NETWORK_CYW43 +#include "pendsv.h" +#endif // Local functions STATIC mp_obj_t machine_pin_obj_init_helper(const machine_pin_obj_t *self, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); @@ -98,6 +101,16 @@ void call_handler(GPIO_Type *gpio, int gpio_nr, int pin) { if (isr & mask) { gpio->ISR = mask; // clear the ISR flag int index = GET_PIN_IRQ_INDEX(gpio_nr, pin); + #if MICROPY_PY_NETWORK_CYW43 + extern void (*cyw43_poll)(void); + const machine_pin_obj_t *pin = MICROPY_HW_WL_HOST_WAKE; + if (pin->gpio == gpio && pin->pin == (index % 32)) { + if (cyw43_poll) { + pendsv_schedule_dispatch(PENDSV_DISPATCH_CYW43, cyw43_poll); + } + return; + } + #endif machine_pin_irq_obj_t *irq = MP_STATE_PORT(machine_pin_irq_objects[index]); if (irq != NULL) { irq->flags = irq->trigger; diff --git a/ports/mimxrt/main.c b/ports/mimxrt/main.c index 2d0760964c225..8deaa5427570f 100644 --- a/ports/mimxrt/main.c +++ b/ports/mimxrt/main.c @@ -43,6 +43,9 @@ #if MICROPY_PY_LWIP #include "lwip/init.h" #include "lwip/apps/mdns.h" +#if MICROPY_PY_NETWORK_CYW43 +#include "lib/cyw43-driver/src/cyw43.h" +#endif #endif #include "systick.h" #include "extmod/modnetwork.h" @@ -69,6 +72,17 @@ int main(void) { systick_enable_dispatch(SYSTICK_DISPATCH_LWIP, mod_network_lwip_poll_wrapper); #endif + #if MICROPY_PY_NETWORK_CYW43 + { + cyw43_init(&cyw43_state); + uint8_t buf[8]; + memcpy(&buf[0], "PYBD", 4); + mp_hal_get_mac_ascii(MP_HAL_MAC_WLAN0, 8, 4, (char *)&buf[4]); + cyw43_wifi_ap_set_ssid(&cyw43_state, 8, buf); + cyw43_wifi_ap_set_password(&cyw43_state, 8, (const uint8_t *)"pybd0123"); + } + #endif + for (;;) { #if defined(MICROPY_HW_LED1) led_init(); diff --git a/ports/mimxrt/mpconfigport.h b/ports/mimxrt/mpconfigport.h index cd69151ed88c0..eb5c3450b3c26 100644 --- a/ports/mimxrt/mpconfigport.h +++ b/ports/mimxrt/mpconfigport.h @@ -170,12 +170,20 @@ extern const struct _mp_obj_type_t network_lan_type; #define MICROPY_HW_NIC_ETH #endif +#if MICROPY_PY_NETWORK_CYW43 +extern const struct _mp_obj_type_t mp_network_cyw43_type; +#define MICROPY_HW_NIC_CYW43 { MP_ROM_QSTR(MP_QSTR_WLAN), MP_ROM_PTR(&mp_network_cyw43_type) }, +#else +#define MICROPY_HW_NIC_CYW43 +#endif + #ifndef MICROPY_BOARD_NETWORK_INTERFACES #define MICROPY_BOARD_NETWORK_INTERFACES #endif #define MICROPY_PORT_NETWORK_INTERFACES \ MICROPY_HW_NIC_ETH \ + MICROPY_HW_NIC_CYW43 \ MICROPY_BOARD_NETWORK_INTERFACES \ #ifndef MICROPY_BOARD_ROOT_POINTERS diff --git a/ports/mimxrt/mpnetworkport.c b/ports/mimxrt/mpnetworkport.c index 2e6a49b90ee70..2ca3426197538 100644 --- a/ports/mimxrt/mpnetworkport.c +++ b/ports/mimxrt/mpnetworkport.c @@ -43,6 +43,11 @@ #include "lwip/dhcp.h" #include "lwip/apps/mdns.h" +#if MICROPY_PY_NETWORK_CYW43 +#include "extmod/network_cyw43.h" +#include "lib/cyw43-driver/src/cyw43.h" +#endif + // Poll lwIP every 128ms #define LWIP_TICK(tick) (((tick) & ~(SYSTICK_DISPATCH_NUM_SLOTS - 1) & 0x7f) == 0) @@ -59,6 +64,16 @@ void mod_network_lwip_poll_wrapper(uint32_t ticks_ms) { if (LWIP_TICK(ticks_ms)) { pendsv_schedule_dispatch(PENDSV_DISPATCH_LWIP, pyb_lwip_poll); } + + #if MICROPY_PY_NETWORK_CYW43 + if (cyw43_poll) { + if (cyw43_sleep != 0) { + if (--cyw43_sleep == 0) { + pendsv_schedule_dispatch(PENDSV_DISPATCH_CYW43, cyw43_poll); + } + } + } + #endif } #endif // MICROPY_PY_LWIP diff --git a/ports/mimxrt/pendsv.h b/ports/mimxrt/pendsv.h index e68f487fb4a13..f3369b07fefdc 100644 --- a/ports/mimxrt/pendsv.h +++ b/ports/mimxrt/pendsv.h @@ -31,6 +31,9 @@ enum { #if MICROPY_PY_NETWORK && MICROPY_PY_LWIP PENDSV_DISPATCH_LWIP, #endif + #if MICROPY_PY_NETWORK_CYW43 + PENDSV_DISPATCH_CYW43, + #endif MICROPY_BOARD_PENDSV_ENTRIES PENDSV_DISPATCH_MAX }; From fc495240a6c63a9839c8112f8c2bcbb6a0f168d0 Mon Sep 17 00:00:00 2001 From: iabdalkader Date: Tue, 9 May 2023 17:06:57 +0200 Subject: [PATCH 4/6] mimxrt: Integrate Bluetooth support with NimBLE bindings. This commit adds the necessary functions to get NimBLE working with the mimxrt port. Signed-off-by: iabdalkader --- ports/mimxrt/Makefile | 9 ++ ports/mimxrt/main.c | 12 +++ ports/mimxrt/mpbthciport.c | 196 ++++++++++++++++++++++++++++++++++++ ports/mimxrt/mpbthciport.h | 42 ++++++++ ports/mimxrt/mpconfigport.h | 9 ++ ports/mimxrt/mpnimbleport.c | 78 ++++++++++++++ ports/mimxrt/mpnimbleport.h | 30 ++++++ 7 files changed, 376 insertions(+) create mode 100644 ports/mimxrt/mpbthciport.c create mode 100644 ports/mimxrt/mpbthciport.h create mode 100644 ports/mimxrt/mpnimbleport.c create mode 100644 ports/mimxrt/mpnimbleport.h diff --git a/ports/mimxrt/Makefile b/ports/mimxrt/Makefile index f74e957c313f6..ead206e5e2106 100644 --- a/ports/mimxrt/Makefile +++ b/ports/mimxrt/Makefile @@ -264,6 +264,14 @@ else SRC_HAL_C += hal/$(FLEXSPI_FLASH_TYPE)_config.c endif +ifeq ($(MICROPY_PY_BLUETOOTH),1) +SRC_C += mpbthciport.c +endif # MICROPY_PY_BLUETOOTH + +ifeq ($(MICROPY_BLUETOOTH_NIMBLE),1) +SRC_C += mpnimbleport.c +endif + # Math library source files ifeq ($(MICROPY_FLOAT_IMPL),double) LIBM_SRC_C += $(addprefix lib/libm_dbl/,\ @@ -449,6 +457,7 @@ OBJ += $(PY_O) OBJ += $(LIBM_O) OBJ += $(addprefix $(BUILD)/, $(SRC_C:.c=.o)) OBJ += $(addprefix $(BUILD)/, $(SHARED_SRC_C:.c=.o)) +OBJ += $(addprefix $(BUILD)/, $(DRIVERS_SRC_C:.c=.o)) OBJ += $(addprefix $(BUILD)/, $(SRC_S:.s=.o)) OBJ += $(addprefix $(BUILD)/, $(SRC_SS:.S=.o)) OBJ += $(addprefix $(BUILD)/, $(SRC_TINYUSB_C:.c=.o)) diff --git a/ports/mimxrt/main.c b/ports/mimxrt/main.c index 8deaa5427570f..993e598185702 100644 --- a/ports/mimxrt/main.c +++ b/ports/mimxrt/main.c @@ -47,6 +47,12 @@ #include "lib/cyw43-driver/src/cyw43.h" #endif #endif + +#if MICROPY_PY_BLUETOOTH +#include "mpbthciport.h" +#include "extmod/modbluetooth.h" +#endif + #include "systick.h" #include "extmod/modnetwork.h" @@ -71,6 +77,9 @@ int main(void) { systick_enable_dispatch(SYSTICK_DISPATCH_LWIP, mod_network_lwip_poll_wrapper); #endif + #if MICROPY_PY_BLUETOOTH + mp_bluetooth_hci_init(); + #endif #if MICROPY_PY_NETWORK_CYW43 { @@ -135,6 +144,9 @@ int main(void) { #if MICROPY_PY_MACHINE_I2S machine_i2s_deinit_all(); #endif + #if MICROPY_PY_BLUETOOTH + mp_bluetooth_deinit(); + #endif #if MICROPY_PY_NETWORK mod_network_deinit(); #endif diff --git a/ports/mimxrt/mpbthciport.c b/ports/mimxrt/mpbthciport.c new file mode 100644 index 0000000000000..c83c765871923 --- /dev/null +++ b/ports/mimxrt/mpbthciport.c @@ -0,0 +1,196 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018-2021 Damien P. George + * Copyright (c) 2023 Ibrahim Abdelkader + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/runtime.h" +#include "py/stream.h" +#include "py/mphal.h" +#include "extmod/modbluetooth.h" +#include "extmod/mpbthci.h" +#include "shared/runtime/softtimer.h" +#include "modmachine.h" +#include "mpbthciport.h" + +#include "fsl_lpuart.h" +#include CLOCK_CONFIG_H + +#if MICROPY_PY_BLUETOOTH + +#define DEBUG_printf(...) // mp_printf(&mp_plat_print, "mpbthciport.c: " __VA_ARGS__) +#define ERROR_printf(...) mp_printf(&mp_plat_print, "mpbthciport.c: " __VA_ARGS__) + +uint8_t mp_bluetooth_hci_cmd_buf[4 + 256]; + +STATIC mp_sched_node_t mp_bluetooth_hci_sched_node; +STATIC soft_timer_entry_t mp_bluetooth_hci_soft_timer; + +STATIC void mp_bluetooth_hci_soft_timer_callback(soft_timer_entry_t *self) { + mp_bluetooth_hci_poll_now(); +} + +void mp_bluetooth_hci_init(void) { + soft_timer_static_init( + &mp_bluetooth_hci_soft_timer, + SOFT_TIMER_MODE_ONE_SHOT, + 0, + mp_bluetooth_hci_soft_timer_callback + ); +} + +STATIC void mp_bluetooth_hci_start_polling(void) { + mp_bluetooth_hci_poll_now(); +} + +void mp_bluetooth_hci_poll_in_ms(uint32_t ms) { + soft_timer_reinsert(&mp_bluetooth_hci_soft_timer, ms); +} + +// For synchronous mode, we run all BLE stack code inside a scheduled task. +STATIC void run_events_scheduled_task(mp_sched_node_t *node) { + // This will process all buffered HCI UART data, and run any callouts or events. + mp_bluetooth_hci_poll(); +} + +// Called periodically (systick) or directly (e.g. UART RX IRQ) in order to +// request that processing happens ASAP in the scheduler. +void mp_bluetooth_hci_poll_now(void) { + mp_sched_schedule_node(&mp_bluetooth_hci_sched_node, run_events_scheduled_task); +} + +mp_obj_t mp_bthci_uart; + +int mp_bluetooth_hci_uart_init(uint32_t port, uint32_t baudrate) { + DEBUG_printf("mp_bluetooth_hci_uart_init\n"); + + mp_obj_t args[] = { + MP_OBJ_NEW_SMALL_INT(port), + MP_OBJ_NEW_QSTR(MP_QSTR_baudrate), MP_OBJ_NEW_SMALL_INT(baudrate), + MP_OBJ_NEW_QSTR(MP_QSTR_timeout), MP_OBJ_NEW_SMALL_INT(200), + MP_OBJ_NEW_QSTR(MP_QSTR_timeout_char), MP_OBJ_NEW_SMALL_INT(200), + MP_OBJ_NEW_QSTR(MP_QSTR_txbuf), MP_OBJ_NEW_SMALL_INT(768), + MP_OBJ_NEW_QSTR(MP_QSTR_rxbuf), MP_OBJ_NEW_SMALL_INT(768), + }; + + mp_bthci_uart = MP_OBJ_TYPE_GET_SLOT(&machine_uart_type, make_new)((mp_obj_t)&machine_uart_type, 1, 5, args); + MP_STATE_PORT(mp_bthci_uart) = mp_bthci_uart; + + // Start the HCI polling to process any initial events/packets. + mp_bluetooth_hci_start_polling(); + return 0; +} + +int mp_bluetooth_hci_uart_deinit(void) { + DEBUG_printf("mp_bluetooth_hci_uart_deinit\n"); + mp_bthci_uart = MP_OBJ_NULL; + return 0; +} + +int mp_bluetooth_hci_uart_set_baudrate(uint32_t baudrate) { + DEBUG_printf("mp_bluetooth_hci_uart_set_baudrate(%lu)\n", baudrate); + if (mp_bthci_uart != MP_OBJ_NULL) { + // This struct is not public, so we use the base defined in board config files. + // machine_uart_obj_t uart = (machine_uart_obj_t *) MP_PTR_FROM_OBJ(mp_bthci_uart); + LPUART_SetBaudRate(MICROPY_HW_BLE_UART_BASE, baudrate, BOARD_BOOTCLOCKRUN_UART_CLK_ROOT); + } + return 0; +} + +int mp_bluetooth_hci_uart_any(void) { + int errcode = 0; + const mp_stream_p_t *proto = (mp_stream_p_t *)MP_OBJ_TYPE_GET_SLOT(&machine_uart_type, protocol); + + mp_uint_t ret = proto->ioctl(mp_bthci_uart, MP_STREAM_POLL, MP_STREAM_POLL_RD, &errcode); + if (errcode != 0) { + ERROR_printf("Uart ioctl failed to poll UART %d\n", errcode); + return -1; + } + return ret & MP_STREAM_POLL_RD; +} + +int mp_bluetooth_hci_uart_write(const uint8_t *buf, size_t len) { + DEBUG_printf("mp_bluetooth_hci_uart_write\n"); + + int errcode = 0; + const mp_stream_p_t *proto = (mp_stream_p_t *)MP_OBJ_TYPE_GET_SLOT(&machine_uart_type, protocol); + + mp_bluetooth_hci_controller_wakeup(); + + if (proto->write(mp_bthci_uart, (void *)buf, len, &errcode) < 0) { + ERROR_printf("mp_bluetooth_hci_uart_write: failed to write to UART %d\n", errcode); + } + return 0; +} + +// This function expects the controller to be in the wake state via a previous call +// to mp_bluetooth_hci_controller_woken. +int mp_bluetooth_hci_uart_readchar(void) { + DEBUG_printf("mp_bluetooth_hci_uart_readchar\n"); + if (mp_bluetooth_hci_uart_any()) { + int errcode = 0; + uint8_t buf = 0; + const mp_stream_p_t *proto = (mp_stream_p_t *)MP_OBJ_TYPE_GET_SLOT(&machine_uart_type, protocol); + if (proto->read(mp_bthci_uart, (void *)&buf, 1, &errcode) < 0) { + ERROR_printf("mp_bluetooth_hci_uart_readchar: failed to read UART %d\n", errcode); + return -1; + } + return buf; + } else { + DEBUG_printf("mp_bluetooth_hci_uart_readchar: not ready\n"); + return -1; + } +} + +// Default (weak) implementation of the HCI controller interface. +// A driver (e.g. cywbt43.c) can override these for controller-specific +// functionality (i.e. power management). +MP_WEAK int mp_bluetooth_hci_controller_init(void) { + DEBUG_printf("mp_bluetooth_hci_controller_init (default)\n"); + return 0; +} + +MP_WEAK int mp_bluetooth_hci_controller_deinit(void) { + DEBUG_printf("mp_bluetooth_hci_controller_deinit (default)\n"); + return 0; +} + +MP_WEAK int mp_bluetooth_hci_controller_sleep_maybe(void) { + DEBUG_printf("mp_bluetooth_hci_controller_sleep_maybe (default)\n"); + return 0; +} + +MP_WEAK bool mp_bluetooth_hci_controller_woken(void) { + DEBUG_printf("mp_bluetooth_hci_controller_woken (default)\n"); + return true; +} + +MP_WEAK int mp_bluetooth_hci_controller_wakeup(void) { + DEBUG_printf("mp_bluetooth_hci_controller_wakeup (default)\n"); + return 0; +} + +MP_REGISTER_ROOT_POINTER(mp_obj_t mp_bthci_uart); + +#endif // MICROPY_PY_BLUETOOTH diff --git a/ports/mimxrt/mpbthciport.h b/ports/mimxrt/mpbthciport.h new file mode 100644 index 0000000000000..124c85dae5025 --- /dev/null +++ b/ports/mimxrt/mpbthciport.h @@ -0,0 +1,42 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018-2021 Damien P. George + * + * 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_MIMXRT_MPBTHCIPORT_H +#define MICROPY_INCLUDED_MIMXRT_MPBTHCIPORT_H + +// Initialise the HCI subsystem (should be called once, early on). +void mp_bluetooth_hci_init(void); + +// Poll the HCI now, or after a certain timeout. +void mp_bluetooth_hci_poll_now(void); +void mp_bluetooth_hci_poll_in_ms(uint32_t ms); + +// Must be provided by the stack bindings (e.g. mpnimbleport.c or mpbtstackport.c). +// Request new data from the uart and pass to the stack, and run pending events/callouts. +// This is a low-level function and should not be called directly, use +// mp_bluetooth_hci_poll_now/mp_bluetooth_hci_poll_in_ms instead. +void mp_bluetooth_hci_poll(void); + +#endif // MICROPY_INCLUDED_MIMXRT_MPBTHCIPORT_H diff --git a/ports/mimxrt/mpconfigport.h b/ports/mimxrt/mpconfigport.h index eb5c3450b3c26..9dccebc1feb91 100644 --- a/ports/mimxrt/mpconfigport.h +++ b/ports/mimxrt/mpconfigport.h @@ -59,6 +59,7 @@ uint32_t trng_random_u32(void); #define MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF (1) #define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_MPZ) #define MICROPY_SCHEDULER_DEPTH (8) +#define MICROPY_SCHEDULER_STATIC_NODES (1) #define MICROPY_VFS (1) // Control over Python builtins @@ -118,6 +119,14 @@ uint32_t trng_random_u32(void); #define MICROPY_PY_LWIP_REENTER MICROPY_PY_PENDSV_REENTER #define MICROPY_PY_LWIP_EXIT MICROPY_PY_PENDSV_EXIT +#ifndef MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE +#define MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE (1) +#endif + +#ifndef MICROPY_PY_BLUETOOTH_ENABLE_L2CAP_CHANNELS +#define MICROPY_PY_BLUETOOTH_ENABLE_L2CAP_CHANNELS (MICROPY_BLUETOOTH_NIMBLE) +#endif + #ifndef MICROPY_PY_NETWORK_HOSTNAME_DEFAULT #define MICROPY_PY_NETWORK_HOSTNAME_DEFAULT "mpy-mimxrt" #endif diff --git a/ports/mimxrt/mpnimbleport.c b/ports/mimxrt/mpnimbleport.c new file mode 100644 index 0000000000000..e2d39e271ce6c --- /dev/null +++ b/ports/mimxrt/mpnimbleport.c @@ -0,0 +1,78 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 Jim Mussared + * Copyright (c) 2020 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/runtime.h" +#include "py/mperrno.h" +#include "py/mphal.h" + +#if MICROPY_PY_BLUETOOTH && MICROPY_BLUETOOTH_NIMBLE + +#define DEBUG_printf(...) // printf("mpnimbleport.c: " __VA_ARGS__) + +#include "host/ble_hs.h" +#include "nimble/nimble_npl.h" + +#include "extmod/mpbthci.h" +#include "extmod/modbluetooth.h" +#include "extmod/nimble/modbluetooth_nimble.h" +#include "extmod/nimble/hal/hal_uart.h" +#include "mpbthciport.h" + +// Get any pending data from the UART and send it to NimBLE's HCI buffers. +// Any further processing by NimBLE will be run via its event queue. +void mp_bluetooth_hci_poll(void) { + if (mp_bluetooth_nimble_ble_state >= MP_BLUETOOTH_NIMBLE_BLE_STATE_WAITING_FOR_SYNC) { + // DEBUG_printf("mp_bluetooth_hci_poll_uart %d\n", mp_bluetooth_nimble_ble_state); + + // Run any timers. + mp_bluetooth_nimble_os_callout_process(); + + // Process incoming UART data, and run events as they are generated. + mp_bluetooth_nimble_hci_uart_process(true); + + // Run any remaining events (e.g. if there was no UART data). + mp_bluetooth_nimble_os_eventq_run_all(); + } + + if (mp_bluetooth_nimble_ble_state != MP_BLUETOOTH_NIMBLE_BLE_STATE_OFF) { + // Call this function again in 128ms to check for new events. + // TODO: improve this by only calling back when needed. + mp_bluetooth_hci_poll_in_ms(128); + } +} + +// --- Port-specific helpers for the generic NimBLE bindings. ----------------- + +void mp_bluetooth_nimble_hci_uart_wfi(void) { + __WFI(); + + // This is called while NimBLE is waiting in ble_npl_sem_pend, i.e. waiting for an HCI ACK. + // Do not need to run events here (it must not invoke Python code), only processing incoming HCI data. + mp_bluetooth_nimble_hci_uart_process(false); +} + +#endif // MICROPY_PY_BLUETOOTH && MICROPY_BLUETOOTH_NIMBLE diff --git a/ports/mimxrt/mpnimbleport.h b/ports/mimxrt/mpnimbleport.h new file mode 100644 index 0000000000000..78f4fc9b00c40 --- /dev/null +++ b/ports/mimxrt/mpnimbleport.h @@ -0,0 +1,30 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Jim Mussared + * + * 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_MIMXRT_NIMBLE_PORT_H +#define MICROPY_INCLUDED_MIMXRT_NIMBLE_PORT_H + +#endif // MICROPY_INCLUDED_MIMXRT_NIMBLE_PORT_H From a453b4f31d3b5928eeb48f50ce1d6314612538c1 Mon Sep 17 00:00:00 2001 From: iabdalkader Date: Wed, 10 May 2023 15:59:15 +0200 Subject: [PATCH 5/6] drivers/cyw43: Make the CYW43 Bluetooth HCI driver more portable. This commit allows other ports to reuse the CYW43 HCI driver, by replacing all Bluetooth UART and control named pins with defines in config files and using `mpbthci` abstract functions (i.e. `mp_bluetooth_hci_*`) instead of the STM32 specific UART functions. Note: the function `cywbt_wait_cts_low` does not need to switch the CTS pin from alternate function to GPIO to read it. At least on stm32, mimxrt it's possible to just read the pin input. For example, see the STM32F7 RM0410 section 6.3.11, and the `SION` for IMXRT. So this function can also be available for other ports if the pin mode switching is removed. Signed-off-by: iabdalkader --- drivers/cyw43/cywbt.c | 99 ++++++++++++++++++++-------------- ports/stm32/cyw43_configport.h | 7 +++ 2 files changed, 66 insertions(+), 40 deletions(-) diff --git a/drivers/cyw43/cywbt.c b/drivers/cyw43/cywbt.c index 006fd28e901d7..bc6674ea2ef7c 100644 --- a/drivers/cyw43/cywbt.c +++ b/drivers/cyw43/cywbt.c @@ -29,8 +29,6 @@ #include "py/runtime.h" #include "py/mphal.h" -#include "pin_static_af.h" -#include "uart.h" #include "extmod/mpbthci.h" #if MICROPY_PY_NETWORK_CYW43 @@ -38,33 +36,41 @@ #include "lib/cyw43-driver/src/cyw43_config.h" #include "lib/cyw43-driver/firmware/cyw43_btfw_4343A1.h" -// Provided by the port. -extern pyb_uart_obj_t mp_bluetooth_hci_uart_obj; - // Provided by the port, and also possibly shared with the stack. extern uint8_t mp_bluetooth_hci_cmd_buf[4 + 256]; /******************************************************************************/ // CYW BT HCI low-level driver +#ifdef CYW43_PIN_BT_CTS +// This code is not portable and currently only builds on stm32 port. + +#include "pin_static_af.h" +#include "uart.h" + +// Provided by the port. +extern pyb_uart_obj_t mp_bluetooth_hci_uart_obj; + STATIC void cywbt_wait_cts_low(void) { - mp_hal_pin_config(pyb_pin_BT_CTS, MP_HAL_PIN_MODE_INPUT, MP_HAL_PIN_PULL_UP, 0); + mp_hal_pin_config(CYW43_PIN_BT_CTS, MP_HAL_PIN_MODE_INPUT, MP_HAL_PIN_PULL_UP, 0); for (int i = 0; i < 200; ++i) { - if (mp_hal_pin_read(pyb_pin_BT_CTS) == 0) { + if (mp_hal_pin_read(CYW43_PIN_BT_CTS) == 0) { break; } mp_hal_delay_ms(1); } - mp_hal_pin_config_alt(pyb_pin_BT_CTS, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_UP, AF_FN_UART, mp_bluetooth_hci_uart_obj.uart_id); + mp_hal_pin_config_alt(CYW43_PIN_BT_CTS, MP_HAL_PIN_MODE_ALT, + MP_HAL_PIN_PULL_UP, AF_FN_UART, mp_bluetooth_hci_uart_obj.uart_id); } +#endif STATIC int cywbt_hci_cmd_raw(size_t len, uint8_t *buf) { - uart_tx_strn(&mp_bluetooth_hci_uart_obj, (void*)buf, len); - for (int i = 0; i < 6; ++i) { - while (!uart_rx_any(&mp_bluetooth_hci_uart_obj)) { + mp_bluetooth_hci_uart_write((void *)buf, len); + for (int c, i = 0; i < 6; ++i) { + while ((c = mp_bluetooth_hci_uart_readchar()) == -1) { MICROPY_EVENT_POLL_HOOK } - buf[i] = uart_rx_char(&mp_bluetooth_hci_uart_obj); + buf[i] = c; } // expect a command complete event (event 0x0e) @@ -80,11 +86,11 @@ STATIC int cywbt_hci_cmd_raw(size_t len, uint8_t *buf) { */ int sz = buf[2] - 3; - for (int i = 0; i < sz; ++i) { - while (!uart_rx_any(&mp_bluetooth_hci_uart_obj)) { + for (int c, i = 0; i < sz; ++i) { + while ((c = mp_bluetooth_hci_uart_readchar()) == -1) { MICROPY_EVENT_POLL_HOOK } - buf[i] = uart_rx_char(&mp_bluetooth_hci_uart_obj); + buf[i] = c; } return 0; @@ -150,12 +156,15 @@ STATIC int cywbt_download_firmware(const uint8_t *firmware) { // RF switch must select high path during BT patch boot #if MICROPY_HW_ENABLE_RF_SWITCH - mp_hal_pin_config(pyb_pin_WL_GPIO_1, MP_HAL_PIN_MODE_INPUT, MP_HAL_PIN_PULL_UP, 0); + mp_hal_pin_config(CYW43_PIN_WL_GPIO_1, MP_HAL_PIN_MODE_INPUT, MP_HAL_PIN_PULL_UP, 0); #endif mp_hal_delay_ms(10); // give some time for CTS to go high + #ifdef CYW43_PIN_BT_CTS cywbt_wait_cts_low(); + #endif #if MICROPY_HW_ENABLE_RF_SWITCH - mp_hal_pin_config(pyb_pin_WL_GPIO_1, MP_HAL_PIN_MODE_INPUT, MP_HAL_PIN_PULL_DOWN, 0); // Select chip antenna (could also select external) + // Select chip antenna (could also select external) + mp_hal_pin_config(CYW43_PIN_WL_GPIO_1, MP_HAL_PIN_MODE_INPUT, MP_HAL_PIN_PULL_DOWN, 0); #endif mp_bluetooth_hci_uart_set_baudrate(115200); @@ -168,25 +177,33 @@ STATIC int cywbt_download_firmware(const uint8_t *firmware) { int mp_bluetooth_hci_controller_init(void) { // This is called immediately after the UART is initialised during stack initialisation. - mp_hal_pin_output(pyb_pin_BT_REG_ON); - mp_hal_pin_low(pyb_pin_BT_REG_ON); - mp_hal_pin_input(pyb_pin_BT_HOST_WAKE); - mp_hal_pin_output(pyb_pin_BT_DEV_WAKE); - mp_hal_pin_low(pyb_pin_BT_DEV_WAKE); + mp_hal_pin_output(CYW43_PIN_BT_REG_ON); + mp_hal_pin_low(CYW43_PIN_BT_REG_ON); + #ifdef CYW43_PIN_BT_HOST_WAKE + mp_hal_pin_input(CYW43_PIN_BT_HOST_WAKE); + #endif + #ifdef CYW43_PIN_BT_DEV_WAKE + mp_hal_pin_output(CYW43_PIN_BT_DEV_WAKE); + mp_hal_pin_low(CYW43_PIN_BT_DEV_WAKE); + #endif #if MICROPY_HW_ENABLE_RF_SWITCH // TODO don't select antenna if wifi is enabled - mp_hal_pin_config(pyb_pin_WL_GPIO_4, MP_HAL_PIN_MODE_OUTPUT, MP_HAL_PIN_PULL_NONE, 0); // RF-switch power - mp_hal_pin_high(pyb_pin_WL_GPIO_4); // Turn the RF-switch on + mp_hal_pin_config(CYW43_PIN_WL_GPIO_4, MP_HAL_PIN_MODE_OUTPUT, MP_HAL_PIN_PULL_NONE, 0); // RF-switch power + mp_hal_pin_high(CYW43_PIN_WL_GPIO_4); // Turn the RF-switch on #endif uint8_t buf[256]; - mp_hal_pin_low(pyb_pin_BT_REG_ON); + mp_hal_pin_low(CYW43_PIN_BT_REG_ON); mp_bluetooth_hci_uart_set_baudrate(115200); mp_hal_delay_ms(100); - mp_hal_pin_high(pyb_pin_BT_REG_ON); + mp_hal_pin_high(CYW43_PIN_BT_REG_ON); + #ifdef CYW43_PIN_BT_CTS cywbt_wait_cts_low(); + #else + mp_hal_delay_ms(100); + #endif // Reset cywbt_hci_cmd(0x03, 0x0003, 0, NULL); @@ -197,7 +214,7 @@ int mp_bluetooth_hci_controller_init(void) { mp_bluetooth_hci_uart_set_baudrate(MICROPY_HW_BLE_UART_BAUDRATE_DOWNLOAD_FIRMWARE); #endif - cywbt_download_firmware((const uint8_t*)&cyw43_btfw_4343A1[0]); + cywbt_download_firmware((const uint8_t *)&cyw43_btfw_4343A1[0]); // Reset cywbt_hci_cmd(0x03, 0x0003, 0, NULL); @@ -219,31 +236,33 @@ int mp_bluetooth_hci_controller_init(void) { // cywbt_hci_cmd(0x03, 0x0013, 248, buf); // Configure sleep mode - cywbt_hci_cmd(0x3f, 0x27, 12, (const uint8_t*)"\x01\x02\x02\x00\x00\x00\x01\x00\x00\x00\x00\x00"); + cywbt_hci_cmd(0x3f, 0x27, 12, (const uint8_t *)"\x01\x02\x02\x00\x00\x00\x01\x00\x00\x00\x00\x00"); // HCI_Write_LE_Host_Support - cywbt_hci_cmd(3, 109, 2, (const uint8_t*)"\x01\x00"); + cywbt_hci_cmd(3, 109, 2, (const uint8_t *)"\x01\x00"); - mp_hal_pin_high(pyb_pin_BT_DEV_WAKE); // let sleep + #ifdef CYW43_PIN_BT_DEV_WAKE + mp_hal_pin_high(CYW43_PIN_BT_DEV_WAKE); // let sleep + #endif return 0; } int mp_bluetooth_hci_controller_deinit(void) { - mp_hal_pin_low(pyb_pin_BT_REG_ON); + mp_hal_pin_low(CYW43_PIN_BT_REG_ON); return 0; } -#ifdef pyb_pin_BT_DEV_WAKE +#ifdef CYW43_PIN_BT_DEV_WAKE STATIC uint32_t bt_sleep_ticks; #endif int mp_bluetooth_hci_controller_sleep_maybe(void) { - #ifdef pyb_pin_BT_DEV_WAKE - if (mp_hal_pin_read(pyb_pin_BT_DEV_WAKE) == 0) { + #ifdef CYW43_PIN_BT_DEV_WAKE + if (mp_hal_pin_read(CYW43_PIN_BT_DEV_WAKE) == 0) { if (mp_hal_ticks_ms() - bt_sleep_ticks > 500) { - mp_hal_pin_high(pyb_pin_BT_DEV_WAKE); // let sleep + mp_hal_pin_high(CYW43_PIN_BT_DEV_WAKE); // let sleep } } #endif @@ -251,8 +270,8 @@ int mp_bluetooth_hci_controller_sleep_maybe(void) { } bool mp_bluetooth_hci_controller_woken(void) { - #ifdef pyb_pin_BT_HOST_WAKE - bool host_wake = mp_hal_pin_read(pyb_pin_BT_HOST_WAKE); + #ifdef CYW43_PIN_BT_HOST_WAKE + bool host_wake = mp_hal_pin_read(CYW43_PIN_BT_HOST_WAKE); /* // this is just for info/tracing purposes static bool last_host_wake = false; @@ -268,11 +287,11 @@ bool mp_bluetooth_hci_controller_woken(void) { } int mp_bluetooth_hci_controller_wakeup(void) { - #ifdef pyb_pin_BT_DEV_WAKE + #ifdef CYW43_PIN_BT_DEV_WAKE bt_sleep_ticks = mp_hal_ticks_ms(); - if (mp_hal_pin_read(pyb_pin_BT_DEV_WAKE) == 1) { - mp_hal_pin_low(pyb_pin_BT_DEV_WAKE); // wake up + if (mp_hal_pin_read(CYW43_PIN_BT_DEV_WAKE) == 1) { + mp_hal_pin_low(CYW43_PIN_BT_DEV_WAKE); // wake up // Use delay_us rather than delay_ms to prevent running the scheduler (which // might result in more BLE operations). mp_hal_delay_us(5000); // can't go lower than this diff --git a/ports/stm32/cyw43_configport.h b/ports/stm32/cyw43_configport.h index 4b6dde3c43f7a..f2a880603ab04 100644 --- a/ports/stm32/cyw43_configport.h +++ b/ports/stm32/cyw43_configport.h @@ -93,6 +93,13 @@ #define CYW43_PIN_WL_REG_ON pyb_pin_WL_REG_ON #define CYW43_PIN_WL_HOST_WAKE pyb_pin_WL_HOST_WAKE #define CYW43_PIN_WL_SDIO_1 pyb_pin_WL_SDIO_1 +#define CYW43_PIN_WL_GPIO_1 pyb_pin_WL_GPIO_1 +#define CYW43_PIN_WL_GPIO_4 pyb_pin_WL_GPIO_4 + +#define CYW43_PIN_BT_REG_ON pyb_pin_BT_REG_ON +#define CYW43_PIN_BT_HOST_WAKE pyb_pin_BT_HOST_WAKE +#define CYW43_PIN_BT_DEV_WAKE pyb_pin_BT_DEV_WAKE +#define CYW43_PIN_BT_CTS pyb_pin_BT_CTS #if MICROPY_HW_ENABLE_RF_SWITCH #define CYW43_PIN_WL_RFSW_VDD pyb_pin_WL_RFSW_VDD From 3f5976e14a1e0f94f9af414bd99789ebf30a865d Mon Sep 17 00:00:00 2001 From: iabdalkader Date: Thu, 11 May 2023 18:56:56 +0200 Subject: [PATCH 6/6] mimxrt/irq: Move all IRQ related definitions to dedicated header. Following other ports, IRQ priorities and related functions are moved to their own header, to simplify mpconfigport.h. Signed-off-by: iabdalkader --- ports/mimxrt/board_init.c | 3 +- ports/mimxrt/irq.h | 80 +++++++++++++++++++++++++++++++++++++ ports/mimxrt/mpconfigport.h | 17 -------- ports/mimxrt/mphalport.h | 1 + ports/mimxrt/pendsv.c | 4 +- 5 files changed, 84 insertions(+), 21 deletions(-) create mode 100644 ports/mimxrt/irq.h diff --git a/ports/mimxrt/board_init.c b/ports/mimxrt/board_init.c index 9222b302b2337..88de27ea77371 100644 --- a/ports/mimxrt/board_init.c +++ b/ports/mimxrt/board_init.c @@ -39,6 +39,7 @@ #include CLOCK_CONFIG_H #include "modmachine.h" +#include "irq.h" const uint8_t dcd_data[] = { 0x00 }; @@ -63,7 +64,7 @@ void board_init(void) { // 1ms tick timer SysTick_Config(SystemCoreClock / 1000); - NVIC_SetPriority(SysTick_IRQn, NVIC_EncodePriority(NVIC_PRIORITYGROUP_4, 0, 0)); + NVIC_SetPriority(SysTick_IRQn, IRQ_PRI_SYSTICK); // USB0 usb_phy0_init(0b0111, 0b0110, 0b0110); // Configure nominal values for D_CAL and TXCAL45DP/DN diff --git a/ports/mimxrt/irq.h b/ports/mimxrt/irq.h new file mode 100644 index 0000000000000..b83eb49ffabfa --- /dev/null +++ b/ports/mimxrt/irq.h @@ -0,0 +1,80 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2023 Damien P. George + * + * 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_MIMXRT_IRQ_H +#define MICROPY_INCLUDED_MIMXRT_IRQ_H + +#define NVIC_PRIORITYGROUP_4 ((uint32_t)0x00000003) + +static inline uint32_t query_irq(void) { + return __get_PRIMASK(); +} + +static inline uint32_t raise_irq_pri(uint32_t pri) { + uint32_t basepri = __get_BASEPRI(); + // If non-zero, the processor does not process any exception with a + // priority value greater than or equal to BASEPRI. + // When writing to BASEPRI_MAX the write goes to BASEPRI only if either: + // - Rn is non-zero and the current BASEPRI value is 0 + // - Rn is non-zero and less than the current BASEPRI value + pri <<= (8 - __NVIC_PRIO_BITS); + __ASM volatile ("msr basepri_max, %0" : : "r" (pri) : "memory"); + return basepri; +} + +// "basepri" should be the value returned from raise_irq_pri +static inline void restore_irq_pri(uint32_t basepri) { + __set_BASEPRI(basepri); +} + +// IRQ priority definitions. +// +// Lower number implies higher interrupt priority. +// +// The default priority grouping used in this port is NVIC_PRIORITYGROUP_4. +// This corresponds to 4 bits for the priority field and 0 bits for the +// sub-priority field (which means that for all intents and purposes the +// sub-priorities below are ignored). +// +// While a given interrupt is being processed, only higher priority (lower number) +// interrupts will preempt a given interrupt. If sub-priorities are active +// then the sub-priority determines the order that pending interrupts of +// a given priority are executed. This is only meaningful if 2 or more +// interrupts of the same priority are pending at the same time. +// +// The following interrupts are arranged from highest priority to lowest +// priority to make it a bit easier to figure out. + +#define IRQ_PRI_SYSTICK NVIC_EncodePriority(NVIC_PRIORITYGROUP_4, 0, 0) + +#define IRQ_PRI_OTG_HS NVIC_EncodePriority(NVIC_PRIORITYGROUP_4, 6, 0) + +#define IRQ_PRI_EXTINT NVIC_EncodePriority(NVIC_PRIORITYGROUP_4, 14, 0) + +// PENDSV should be at the lowst priority so that other interrupts complete +// before exception is raised. +#define IRQ_PRI_PENDSV NVIC_EncodePriority(NVIC_PRIORITYGROUP_4, 15, 0) + +#endif // MICROPY_INCLUDED_MIMXRT_IRQ_H diff --git a/ports/mimxrt/mpconfigport.h b/ports/mimxrt/mpconfigport.h index 9dccebc1feb91..fb4acede5901e 100644 --- a/ports/mimxrt/mpconfigport.h +++ b/ports/mimxrt/mpconfigport.h @@ -152,23 +152,6 @@ __attribute__((always_inline)) static inline uint32_t disable_irq(void) { return state; } -static inline uint32_t raise_irq_pri(uint32_t pri) { - uint32_t basepri = __get_BASEPRI(); - // If non-zero, the processor does not process any exception with a - // priority value greater than or equal to BASEPRI. - // When writing to BASEPRI_MAX the write goes to BASEPRI only if either: - // - Rn is non-zero and the current BASEPRI value is 0 - // - Rn is non-zero and less than the current BASEPRI value - pri <<= (8 - __NVIC_PRIO_BITS); - __ASM volatile ("msr basepri_max, %0" : : "r" (pri) : "memory"); - return basepri; -} - -// "basepri" should be the value returned from raise_irq_pri -static inline void restore_irq_pri(uint32_t basepri) { - __set_BASEPRI(basepri); -} - #define MICROPY_BEGIN_ATOMIC_SECTION() disable_irq() #define MICROPY_END_ATOMIC_SECTION(state) enable_irq(state) diff --git a/ports/mimxrt/mphalport.h b/ports/mimxrt/mphalport.h index 1813a9834b165..36eb387798133 100644 --- a/ports/mimxrt/mphalport.h +++ b/ports/mimxrt/mphalport.h @@ -31,6 +31,7 @@ #include "ticks.h" #include "py/ringbuf.h" #include "pin.h" +#include "irq.h" #include "fsl_clock.h" #define MICROPY_HAL_VERSION "2.8.0" diff --git a/ports/mimxrt/pendsv.c b/ports/mimxrt/pendsv.c index 11f2ef5e1c86f..46d13a5aca245 100644 --- a/ports/mimxrt/pendsv.c +++ b/ports/mimxrt/pendsv.c @@ -28,9 +28,7 @@ #include "py/runtime.h" #include "pendsv.h" - -#define NVIC_PRIORITYGROUP_4 ((uint32_t)0x00000003) -#define IRQ_PRI_PENDSV NVIC_EncodePriority(NVIC_PRIORITYGROUP_4, 15, 0) +#include "irq.h" #if defined(PENDSV_DISPATCH_NUM_SLOTS) pendsv_dispatch_t pendsv_dispatch_table[PENDSV_DISPATCH_NUM_SLOTS]; pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy