From 9257a0f562a1cb939a902e7c41de5032b0f7de19 Mon Sep 17 00:00:00 2001 From: hathach Date: Fri, 18 Aug 2023 12:48:12 +0700 Subject: [PATCH 01/34] - update nrf52 bsp for cmake - add empty tuh_int_handler/tud_int_handler if corresponidng stack not enabled - add hcd_template.c --- hw/bsp/nrf/boards/adafruit_clue/board.cmake | 5 + .../nrf/boards/arduino_nano33_ble/board.cmake | 5 + .../circuitplayground_bluefruit/board.cmake | 5 + .../feather_nrf52840_express/board.cmake | 6 + .../boards/feather_nrf52840_sense/board.cmake | 5 + .../nrf/boards/itsybitsy_nrf52840/board.cmake | 5 + .../boards/nrf52840_mdk_dongle/board.cmake | 5 + hw/bsp/nrf/boards/pca10056/board.cmake | 3 - hw/bsp/nrf/boards/pca10059/board.cmake | 5 + hw/bsp/nrf/boards/pca10095/board.cmake | 4 - hw/bsp/nrf/boards/pca10100/board.cmake | 5 + .../nrf/boards/raytac_mdbt50q_rx/board.cmake | 5 + hw/bsp/nrf/family.cmake | 14 +- src/device/usbd.h | 6 +- src/host/hcd.h | 12 +- src/portable/template/dcd_template.c | 4 +- src/portable/template/hcd_template.c | 162 ++++++++++++++++++ src/tusb.h | 9 +- 18 files changed, 241 insertions(+), 24 deletions(-) create mode 100644 hw/bsp/nrf/boards/adafruit_clue/board.cmake create mode 100644 hw/bsp/nrf/boards/arduino_nano33_ble/board.cmake create mode 100644 hw/bsp/nrf/boards/circuitplayground_bluefruit/board.cmake create mode 100644 hw/bsp/nrf/boards/feather_nrf52840_express/board.cmake create mode 100644 hw/bsp/nrf/boards/feather_nrf52840_sense/board.cmake create mode 100644 hw/bsp/nrf/boards/itsybitsy_nrf52840/board.cmake create mode 100644 hw/bsp/nrf/boards/nrf52840_mdk_dongle/board.cmake create mode 100644 hw/bsp/nrf/boards/pca10059/board.cmake create mode 100644 hw/bsp/nrf/boards/pca10100/board.cmake create mode 100644 hw/bsp/nrf/boards/raytac_mdbt50q_rx/board.cmake create mode 100644 src/portable/template/hcd_template.c diff --git a/hw/bsp/nrf/boards/adafruit_clue/board.cmake b/hw/bsp/nrf/boards/adafruit_clue/board.cmake new file mode 100644 index 0000000000..eb97e5c551 --- /dev/null +++ b/hw/bsp/nrf/boards/adafruit_clue/board.cmake @@ -0,0 +1,5 @@ +set(MCU_VARIANT nrf52840) +set(LD_FILE_GNU ${CMAKE_CURRENT_LIST_DIR}/../../linker/nrf52840_s140_v6.ld) + +function(update_board TARGET) +endfunction() diff --git a/hw/bsp/nrf/boards/arduino_nano33_ble/board.cmake b/hw/bsp/nrf/boards/arduino_nano33_ble/board.cmake new file mode 100644 index 0000000000..93647063a3 --- /dev/null +++ b/hw/bsp/nrf/boards/arduino_nano33_ble/board.cmake @@ -0,0 +1,5 @@ +set(MCU_VARIANT nrf52840) +set(LD_FILE_GNU ${CMAKE_CURRENT_LIST_DIR}/arduino_nano33_ble.ld) + +function(update_board TARGET) +endfunction() diff --git a/hw/bsp/nrf/boards/circuitplayground_bluefruit/board.cmake b/hw/bsp/nrf/boards/circuitplayground_bluefruit/board.cmake new file mode 100644 index 0000000000..eb97e5c551 --- /dev/null +++ b/hw/bsp/nrf/boards/circuitplayground_bluefruit/board.cmake @@ -0,0 +1,5 @@ +set(MCU_VARIANT nrf52840) +set(LD_FILE_GNU ${CMAKE_CURRENT_LIST_DIR}/../../linker/nrf52840_s140_v6.ld) + +function(update_board TARGET) +endfunction() diff --git a/hw/bsp/nrf/boards/feather_nrf52840_express/board.cmake b/hw/bsp/nrf/boards/feather_nrf52840_express/board.cmake new file mode 100644 index 0000000000..0acbecf7a9 --- /dev/null +++ b/hw/bsp/nrf/boards/feather_nrf52840_express/board.cmake @@ -0,0 +1,6 @@ +set(MCU_VARIANT nrf52840) +set(LD_FILE_GNU ${CMAKE_CURRENT_LIST_DIR}/../../linker/nrf52840_s140_v6.ld) +# set(LD_FILE_GNU ${NRFX_DIR}/mdk/nrf52840_xxaa.ld) + +function(update_board TARGET) +endfunction() diff --git a/hw/bsp/nrf/boards/feather_nrf52840_sense/board.cmake b/hw/bsp/nrf/boards/feather_nrf52840_sense/board.cmake new file mode 100644 index 0000000000..eb97e5c551 --- /dev/null +++ b/hw/bsp/nrf/boards/feather_nrf52840_sense/board.cmake @@ -0,0 +1,5 @@ +set(MCU_VARIANT nrf52840) +set(LD_FILE_GNU ${CMAKE_CURRENT_LIST_DIR}/../../linker/nrf52840_s140_v6.ld) + +function(update_board TARGET) +endfunction() diff --git a/hw/bsp/nrf/boards/itsybitsy_nrf52840/board.cmake b/hw/bsp/nrf/boards/itsybitsy_nrf52840/board.cmake new file mode 100644 index 0000000000..eb97e5c551 --- /dev/null +++ b/hw/bsp/nrf/boards/itsybitsy_nrf52840/board.cmake @@ -0,0 +1,5 @@ +set(MCU_VARIANT nrf52840) +set(LD_FILE_GNU ${CMAKE_CURRENT_LIST_DIR}/../../linker/nrf52840_s140_v6.ld) + +function(update_board TARGET) +endfunction() diff --git a/hw/bsp/nrf/boards/nrf52840_mdk_dongle/board.cmake b/hw/bsp/nrf/boards/nrf52840_mdk_dongle/board.cmake new file mode 100644 index 0000000000..ffa5932c15 --- /dev/null +++ b/hw/bsp/nrf/boards/nrf52840_mdk_dongle/board.cmake @@ -0,0 +1,5 @@ +set(MCU_VARIANT nrf52840) +set(LD_FILE_GNU ${CMAKE_CURRENT_LIST_DIR}/nrf52840_mdk_dongle.ld) + +function(update_board TARGET) +endfunction() diff --git a/hw/bsp/nrf/boards/pca10056/board.cmake b/hw/bsp/nrf/boards/pca10056/board.cmake index b4fe39fc03..693d7beed2 100644 --- a/hw/bsp/nrf/boards/pca10056/board.cmake +++ b/hw/bsp/nrf/boards/pca10056/board.cmake @@ -2,7 +2,4 @@ set(MCU_VARIANT nrf52840) set(LD_FILE_GNU ${NRFX_DIR}/mdk/nrf52840_xxaa.ld) function(update_board TARGET) - target_compile_definitions(${TARGET} PUBLIC - NRF52840_XXAA - ) endfunction() diff --git a/hw/bsp/nrf/boards/pca10059/board.cmake b/hw/bsp/nrf/boards/pca10059/board.cmake new file mode 100644 index 0000000000..c79eb5964d --- /dev/null +++ b/hw/bsp/nrf/boards/pca10059/board.cmake @@ -0,0 +1,5 @@ +set(MCU_VARIANT nrf52840) +set(LD_FILE_GNU ${CMAKE_CURRENT_LIST_DIR}/pca10059.ld) + +function(update_board TARGET) +endfunction() diff --git a/hw/bsp/nrf/boards/pca10095/board.cmake b/hw/bsp/nrf/boards/pca10095/board.cmake index 1e72243c9b..ca5399a3a8 100644 --- a/hw/bsp/nrf/boards/pca10095/board.cmake +++ b/hw/bsp/nrf/boards/pca10095/board.cmake @@ -2,10 +2,6 @@ set(MCU_VARIANT nrf5340_application) set(LD_FILE_GNU ${NRFX_DIR}/mdk/nrf5340_xxaa_application.ld) function(update_board TARGET) - target_compile_definitions(${TARGET} PUBLIC - NRF5340_XXAA - NRF5340_XXAA_APPLICATION - ) target_sources(${TARGET} PRIVATE ${NRFX_DIR}/drivers/src/nrfx_usbreg.c ) diff --git a/hw/bsp/nrf/boards/pca10100/board.cmake b/hw/bsp/nrf/boards/pca10100/board.cmake new file mode 100644 index 0000000000..c300268159 --- /dev/null +++ b/hw/bsp/nrf/boards/pca10100/board.cmake @@ -0,0 +1,5 @@ +set(MCU_VARIANT nrf52833) +set(LD_FILE_GNU ${NRFX_DIR}/mdk/nrf52833_xxaa.ld) + +function(update_board TARGET) +endfunction() diff --git a/hw/bsp/nrf/boards/raytac_mdbt50q_rx/board.cmake b/hw/bsp/nrf/boards/raytac_mdbt50q_rx/board.cmake new file mode 100644 index 0000000000..693d7beed2 --- /dev/null +++ b/hw/bsp/nrf/boards/raytac_mdbt50q_rx/board.cmake @@ -0,0 +1,5 @@ +set(MCU_VARIANT nrf52840) +set(LD_FILE_GNU ${NRFX_DIR}/mdk/nrf52840_xxaa.ld) + +function(update_board TARGET) +endfunction() diff --git a/hw/bsp/nrf/family.cmake b/hw/bsp/nrf/family.cmake index 2b13249f48..6c24d3658b 100644 --- a/hw/bsp/nrf/family.cmake +++ b/hw/bsp/nrf/family.cmake @@ -33,13 +33,20 @@ function(add_board_target BOARD_TARGET) add_library(${BOARD_TARGET} STATIC # driver ${NRFX_DIR}/drivers/src/nrfx_power.c + ${NRFX_DIR}/drivers/src/nrfx_spim.c ${NRFX_DIR}/drivers/src/nrfx_uarte.c # mcu ${NRFX_DIR}/mdk/system_${MCU_VARIANT}.c ) - target_compile_definitions(${BOARD_TARGET} PUBLIC - CONFIG_GPIO_AS_PINRESET - ) + target_compile_definitions(${BOARD_TARGET} PUBLIC CONFIG_GPIO_AS_PINRESET) + + if (MCU_VARIANT STREQUAL "nrf52840") + target_compile_definitions(${BOARD_TARGET} PUBLIC NRF52840_XXAA) + elseif (MCU_VARIANT STREQUAL "nrf52833") + target_compile_definitions(${BOARD_TARGET} PUBLIC NRF52833_XXAA) + elseif (MCU_VARIANT STREQUAL "nrf5340_application") + target_compile_definitions(${BOARD_TARGET} PUBLIC NRF5340_XXAA NRF5340_XXAA_APPLICATION) + endif () if (TRACE_ETM STREQUAL "1") # ENABLE_TRACE will cause system_nrf5x.c to set up ETM trace @@ -115,6 +122,7 @@ function(family_configure_example TARGET RTOS) family_add_tinyusb(${TARGET} OPT_MCU_NRF5X ${RTOS}) target_sources(${TARGET}-tinyusb PUBLIC ${TOP}/src/portable/nordic/nrf5x/dcd_nrf5x.c + #${TOP}/src/portable/analog/max3421e/hcd_max3421e.c ) target_link_libraries(${TARGET}-tinyusb PUBLIC board_${BOARD}) diff --git a/src/device/usbd.h b/src/device/usbd.h index b11c1a09dd..782f538fd5 100644 --- a/src/device/usbd.h +++ b/src/device/usbd.h @@ -50,8 +50,7 @@ void tud_task_ext(uint32_t timeout_ms, bool in_isr); // Task function should be called in main/rtos loop TU_ATTR_ALWAYS_INLINE static inline -void tud_task (void) -{ +void tud_task (void) { tud_task_ext(UINT32_MAX, false); } @@ -80,8 +79,7 @@ bool tud_suspended(void); // Check if device is ready to transfer TU_ATTR_ALWAYS_INLINE static inline -bool tud_ready(void) -{ +bool tud_ready(void) { return tud_mounted() && !tud_suspended(); } diff --git a/src/host/hcd.h b/src/host/hcd.h index 9bcc1c6dfd..1b5038ef40 100644 --- a/src/host/hcd.h +++ b/src/host/hcd.h @@ -198,8 +198,7 @@ extern void hcd_event_handler(hcd_event_t const* event, bool in_isr); // Helper to send device attach event TU_ATTR_ALWAYS_INLINE static inline -void hcd_event_device_attach(uint8_t rhport, bool in_isr) -{ +void hcd_event_device_attach(uint8_t rhport, bool in_isr) { hcd_event_t event; event.rhport = rhport; event.event_id = HCD_EVENT_DEVICE_ATTACH; @@ -211,8 +210,7 @@ void hcd_event_device_attach(uint8_t rhport, bool in_isr) // Helper to send device removal event TU_ATTR_ALWAYS_INLINE static inline -void hcd_event_device_remove(uint8_t rhport, bool in_isr) -{ +void hcd_event_device_remove(uint8_t rhport, bool in_isr) { hcd_event_t event; event.rhport = rhport; event.event_id = HCD_EVENT_DEVICE_REMOVE; @@ -224,10 +222,8 @@ void hcd_event_device_remove(uint8_t rhport, bool in_isr) // Helper to send USB transfer event TU_ATTR_ALWAYS_INLINE static inline -void hcd_event_xfer_complete(uint8_t dev_addr, uint8_t ep_addr, uint32_t xferred_bytes, xfer_result_t result, bool in_isr) -{ - hcd_event_t event = - { +void hcd_event_xfer_complete(uint8_t dev_addr, uint8_t ep_addr, uint32_t xferred_bytes, xfer_result_t result, bool in_isr) { + hcd_event_t event = { .rhport = 0, // TODO correct rhport .event_id = HCD_EVENT_XFER_COMPLETE, .dev_addr = dev_addr, diff --git a/src/portable/template/dcd_template.c b/src/portable/template/dcd_template.c index 590dd9fcf6..12d610bd65 100644 --- a/src/portable/template/dcd_template.c +++ b/src/portable/template/dcd_template.c @@ -26,7 +26,7 @@ #include "tusb_option.h" -#if CFG_TUSB_MCU == OPT_MCU_NONE +#if CFG_TUD_ENABLED && CFG_TUSB_MCU == OPT_MCU_NONE #include "device/dcd.h" @@ -141,4 +141,6 @@ void dcd_edpt_clear_stall (uint8_t rhport, uint8_t ep_addr) (void) ep_addr; } + + #endif diff --git a/src/portable/template/hcd_template.c b/src/portable/template/hcd_template.c new file mode 100644 index 0000000000..3e3b915585 --- /dev/null +++ b/src/portable/template/hcd_template.c @@ -0,0 +1,162 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2023 Ha Thach (tinyusb.org) + * + * 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 is part of the TinyUSB stack. + */ + +#include "tusb_option.h" + +#if CFG_TUH_ENABLED && CFG_TUSB_MCU == OPT_MCU_NONE + +#include "host/hcd.h" + +//--------------------------------------------------------------------+ +// Controller API +//--------------------------------------------------------------------+ + +// optional hcd configuration, called by tuh_configure() +bool hcd_configure(uint8_t rhport, uint32_t cfg_id, const void* cfg_param) { + (void) rhport; + (void) cfg_id; + (void) cfg_param; + + return false; +} + +// Initialize controller to host mode +bool hcd_init(uint8_t rhport) { + (void) rhport; + + return false; +} + +// Interrupt Handler +void hcd_int_handler(uint8_t rhport) { + (void) rhport; +} + +// Enable USB interrupt +void hcd_int_enable (uint8_t rhport) { + (void) rhport; +} + +// Disable USB interrupt +void hcd_int_disable(uint8_t rhport) { + (void) rhport; +} + +// Get frame number (1ms) +uint32_t hcd_frame_number(uint8_t rhport) { + (void) rhport; + + return 0; +} + +//--------------------------------------------------------------------+ +// Port API +//--------------------------------------------------------------------+ + +// Get the current connect status of roothub port +bool hcd_port_connect_status(uint8_t rhport) { + (void) rhport; + + return false; +} + +// Reset USB bus on the port. Return immediately, bus reset sequence may not be complete. +// Some port would require hcd_port_reset_end() to be invoked after 10ms to complete the reset sequence. +void hcd_port_reset(uint8_t rhport) { + (void) rhport; +} + +// Complete bus reset sequence, may be required by some controllers +void hcd_port_reset_end(uint8_t rhport) { + (void) rhport; +} + +// Get port link speed +tusb_speed_t hcd_port_speed_get(uint8_t rhport) { + (void) rhport; + + return TUSB_SPEED_FULL; +} + +// HCD closes all opened endpoints belong to this device +void hcd_device_close(uint8_t rhport, uint8_t dev_addr) { + (void) rhport; + (void) dev_addr; +} + +//--------------------------------------------------------------------+ +// Endpoints API +//--------------------------------------------------------------------+ + +// Open an endpoint +bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const * ep_desc) { + (void) rhport; + (void) dev_addr; + (void) ep_desc; + + return false; +} + +// Submit a transfer, when complete hcd_event_xfer_complete() must be invoked +bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t * buffer, uint16_t buflen) { + (void) rhport; + (void) dev_addr; + (void) ep_addr; + (void) buffer; + (void) buflen; + + return false; +} + +// Abort a queued transfer. Note: it can only abort transfer that has not been started +// Return true if a queued transfer is aborted, false if there is no transfer to abort +bool hcd_edpt_abort_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr) { + (void) rhport; + (void) dev_addr; + (void) ep_addr; + + return false; +} + +// Submit a special transfer to send 8-byte Setup Packet, when complete hcd_event_xfer_complete() must be invoked +bool hcd_setup_send(uint8_t rhport, uint8_t dev_addr, uint8_t const setup_packet[8]) { + (void) rhport; + (void) dev_addr; + (void) setup_packet; + + return false; +} + +// clear stall, data toggle is also reset to DATA0 +bool hcd_edpt_clear_stall(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr) { + (void) rhport; + (void) dev_addr; + (void) ep_addr; + + return false; +} + +#endif diff --git a/src/tusb.h b/src/tusb.h index 37a521fa8f..d6534ca280 100644 --- a/src/tusb.h +++ b/src/tusb.h @@ -64,7 +64,10 @@ #if CFG_TUH_VENDOR #include "class/vendor/vendor_host.h" #endif - +#else + #ifndef tuh_int_handler + #define tuh_int_handler(_x) + #endif #endif //------------- DEVICE -------------// @@ -118,6 +121,10 @@ #if CFG_TUD_BTH #include "class/bth/bth_device.h" #endif +#else + #ifndef tud_int_handler + #define tud_int_handler(_x) + #endif #endif From 824e585e2b1f62d1ed03f480439e62e5410636b6 Mon Sep 17 00:00:00 2001 From: hathach Date: Fri, 18 Aug 2023 14:06:57 +0700 Subject: [PATCH 02/34] ground works for hcd max3421e --- .../feather_nrf52840_express/board.cmake | 4 +- .../boards/feather_nrf52840_express/board.h | 7 + hw/bsp/nrf/family.c | 80 +++-- hw/bsp/nrf/family.cmake | 2 +- hw/bsp/nrf/nrfx_config.h | 5 +- src/portable/analog/max3421e/hcd_max3421e.c | 302 ++++++++++++++++++ 6 files changed, 369 insertions(+), 31 deletions(-) create mode 100644 src/portable/analog/max3421e/hcd_max3421e.c diff --git a/hw/bsp/nrf/boards/feather_nrf52840_express/board.cmake b/hw/bsp/nrf/boards/feather_nrf52840_express/board.cmake index 0acbecf7a9..78ed982252 100644 --- a/hw/bsp/nrf/boards/feather_nrf52840_express/board.cmake +++ b/hw/bsp/nrf/boards/feather_nrf52840_express/board.cmake @@ -1,6 +1,6 @@ set(MCU_VARIANT nrf52840) -set(LD_FILE_GNU ${CMAKE_CURRENT_LIST_DIR}/../../linker/nrf52840_s140_v6.ld) -# set(LD_FILE_GNU ${NRFX_DIR}/mdk/nrf52840_xxaa.ld) +#set(LD_FILE_GNU ${CMAKE_CURRENT_LIST_DIR}/../../linker/nrf52840_s140_v6.ld) +set(LD_FILE_GNU ${NRFX_DIR}/mdk/nrf52840_xxaa.ld) function(update_board TARGET) endfunction() diff --git a/hw/bsp/nrf/boards/feather_nrf52840_express/board.h b/hw/bsp/nrf/boards/feather_nrf52840_express/board.h index 8e6ce32301..e19f88a3ce 100644 --- a/hw/bsp/nrf/boards/feather_nrf52840_express/board.h +++ b/hw/bsp/nrf/boards/feather_nrf52840_express/board.h @@ -45,6 +45,13 @@ #define UART_RX_PIN 24 #define UART_TX_PIN 25 +// SPI for USB host shield +#define SPI_SCK_PIN 14 +#define SPI_MOSI_PIN 13 +#define SPI_MISO_PIN 15 +#define SPI_CS_PIN 27 +#define MAX3241E_INT_PIN 26 + #ifdef __cplusplus } #endif diff --git a/hw/bsp/nrf/family.c b/hw/bsp/nrf/family.c index 9ca666e366..b6ed15122f 100644 --- a/hw/bsp/nrf/family.c +++ b/hw/bsp/nrf/family.c @@ -40,6 +40,7 @@ #include "hal/nrf_gpio.h" #include "drivers/include/nrfx_power.h" #include "drivers/include/nrfx_uarte.h" +#include "drivers/include/nrfx_spim.h" #ifdef SOFTDEVICE_PRESENT #include "nrf_sdm.h" @@ -54,8 +55,7 @@ //--------------------------------------------------------------------+ // Forward USB interrupt events to TinyUSB IRQ Handler //--------------------------------------------------------------------+ -void USBD_IRQHandler(void) -{ +void USBD_IRQHandler(void) { tud_int_handler(0); } @@ -81,6 +81,7 @@ enum { #endif static nrfx_uarte_t _uart_id = NRFX_UARTE_INSTANCE(0); +static nrfx_spim_t _spi = NRFX_SPIM_INSTANCE(0); // tinyusb function that handles power event (detected, ready, removed) // We must call it within SD's SOC event handler, or set it as power event handler if SD is not enabled. @@ -88,13 +89,11 @@ extern void tusb_hal_nrf_power_event(uint32_t event); // nrf power callback, could be unused if SD is enabled or usb is disabled (board_test example) -TU_ATTR_UNUSED static void power_event_handler(nrfx_power_usb_evt_t event) -{ +TU_ATTR_UNUSED static void power_event_handler(nrfx_power_usb_evt_t event) { tusb_hal_nrf_power_event((uint32_t) event); } -void board_init(void) -{ +void board_init(void) { // stop LF clock just in case we jump from application without reset NRF_CLOCK->TASKS_LFCLKSTOP = 1UL; @@ -113,8 +112,7 @@ void board_init(void) SysTick_Config(SystemCoreClock/1000); // UART - nrfx_uarte_config_t uart_cfg = - { + nrfx_uarte_config_t uart_cfg = { .pseltxd = UART_TX_PIN, .pselrxd = UART_RX_PIN, .pselcts = NRF_UARTE_PSEL_DISCONNECTED, @@ -175,45 +173,78 @@ void board_init(void) if ( usb_reg & VBUSDETECT_Msk ) tusb_hal_nrf_power_event(USB_EVT_DETECTED); if ( usb_reg & OUTPUTRDY_Msk ) tusb_hal_nrf_power_event(USB_EVT_READY); #endif + + (void) _spi; +#if CFG_TUH_ENABLED && defined(CFG_TUH_MAX3421E) && CFG_TUH_MAX3421E + // USB host using max3421e usb controller via SPI + nrfx_spim_config_t cfg = { + .sck_pin = SPI_SCK_PIN, + .mosi_pin = SPI_MOSI_PIN, + .miso_pin = SPI_MISO_PIN, + .ss_pin = SPI_CS_PIN, + .ss_active_high = false, + .irq_priority = 3, + .orc = 0xFF, + // default setting 4 Mhz, Mode 0, MSB first + .frequency = NRF_SPIM_FREQ_4M, + .mode = NRF_SPIM_MODE_0, + .bit_order = NRF_SPIM_BIT_ORDER_MSB_FIRST, + }; + + // no handler --> blocking + nrfx_spim_init(&_spi, &cfg, NULL, NULL); +#endif + } //--------------------------------------------------------------------+ // Board porting API //--------------------------------------------------------------------+ -void board_led_write(bool state) -{ - nrf_gpio_pin_write(LED_PIN, state ? LED_STATE_ON : (1-LED_STATE_ON)); +void board_led_write(bool state) { + nrf_gpio_pin_write(LED_PIN, state ? LED_STATE_ON : (1 - LED_STATE_ON)); } -uint32_t board_button_read(void) -{ +uint32_t board_button_read(void) { return BUTTON_STATE_ACTIVE == nrf_gpio_pin_read(BUTTON_PIN); } -int board_uart_read(uint8_t* buf, int len) -{ - (void) buf; (void) len; +int board_uart_read(uint8_t *buf, int len) { + (void) buf; + (void) len; return 0; // return NRFX_SUCCESS == nrfx_uart_rx(&_uart_id, buf, (size_t) len) ? len : 0; } -int board_uart_write(void const * buf, int len) -{ - return (NRFX_SUCCESS == nrfx_uarte_tx(&_uart_id, (uint8_t const*) buf, (size_t) len)) ? len : 0; +int board_uart_write(void const *buf, int len) { + return (NRFX_SUCCESS == nrfx_uarte_tx(&_uart_id, (uint8_t const *) buf, (size_t) len)) ? len : 0; } #if CFG_TUSB_OS == OPT_OS_NONE volatile uint32_t system_ticks = 0; -void SysTick_Handler (void) -{ + +void SysTick_Handler(void) { system_ticks++; } -uint32_t board_millis(void) -{ +uint32_t board_millis(void) { return system_ticks; } + +#endif + +#if CFG_TUH_ENABLED && defined(CFG_TUH_MAX3421E) && CFG_TUH_MAX3421E +// API: SPI transfer with MAX3421E, must be implemented by application +bool tuh_max3421e_spi_xfer_api(uint8_t rhport, uint8_t const * tx_buf, size_t tx_len, uint8_t * rx_buf, size_t rx_len) { + (void) rhport; + nrfx_spim_xfer_desc_t xfer = { + .p_tx_buffer = tx_buf, + .tx_length = tx_len, + .p_rx_buffer = rx_buf, + .rx_length = rx_len, + }; + return nrfx_spim_xfer(&_spi, &xfer, 0) == NRFX_SUCCESS; +} #endif #ifdef SOFTDEVICE_PRESENT @@ -251,8 +282,7 @@ void SD_EVT_IRQHandler(void) } } -void nrf_error_cb(uint32_t id, uint32_t pc, uint32_t info) -{ +void nrf_error_cb(uint32_t id, uint32_t pc, uint32_t info) { (void) id; (void) pc; (void) info; diff --git a/hw/bsp/nrf/family.cmake b/hw/bsp/nrf/family.cmake index 6c24d3658b..527251e716 100644 --- a/hw/bsp/nrf/family.cmake +++ b/hw/bsp/nrf/family.cmake @@ -122,7 +122,7 @@ function(family_configure_example TARGET RTOS) family_add_tinyusb(${TARGET} OPT_MCU_NRF5X ${RTOS}) target_sources(${TARGET}-tinyusb PUBLIC ${TOP}/src/portable/nordic/nrf5x/dcd_nrf5x.c - #${TOP}/src/portable/analog/max3421e/hcd_max3421e.c + ${TOP}/src/portable/analog/max3421e/hcd_max3421e.c ) target_link_libraries(${TARGET}-tinyusb PUBLIC board_${BOARD}) diff --git a/hw/bsp/nrf/nrfx_config.h b/hw/bsp/nrf/nrfx_config.h index 696a3fb04b..d0f718c6cb 100644 --- a/hw/bsp/nrf/nrfx_config.h +++ b/hw/bsp/nrf/nrfx_config.h @@ -9,9 +9,8 @@ #define NRFX_UARTE_ENABLED 1 #define NRFX_UARTE0_ENABLED 1 -#define NRFX_UARTE1_ENABLED 0 -#define NRFX_UARTE2_ENABLED 0 -#define NRFX_UARTE3_ENABLED 0 +#define NRFX_SPIM_ENABLED 1 +#define NRFX_SPIM0_ENABLED 1 #define NRFX_PRS_ENABLED 0 #define NRFX_USBREG_ENABLED 1 diff --git a/src/portable/analog/max3421e/hcd_max3421e.c b/src/portable/analog/max3421e/hcd_max3421e.c new file mode 100644 index 0000000000..7b9d73e4e5 --- /dev/null +++ b/src/portable/analog/max3421e/hcd_max3421e.c @@ -0,0 +1,302 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2023 Ha Thach (tinyusb.org) + * + * 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 is part of the TinyUSB stack. + */ + +#include "tusb_option.h" + +#if CFG_TUH_ENABLED && defined(CFG_TUH_MAX3421E) && CFG_TUH_MAX3421E + +#include "host/hcd.h" + +//--------------------------------------------------------------------+ +// +//--------------------------------------------------------------------+ + +// Command format is +// Reg [7:3] | 0 [2] | Dir [1] | Ack [0] + +enum { + CMDBYTE_WRITE = 0x02, +}; + +enum { + RCVVFIFO_ADDR = 1u << 3, // 0x08 + SNDFIFO_ADDR = 2u << 3, // 0x10 + SUDFIFO_ADDR = 4u << 3, // 0x20 + RCVBC_ADDR = 6u << 3, // 0x30 + SNDBC_ADDR = 7u << 3, // 0x38 + USBIRQ_ADDR = 13u << 3, // 0x68 + USBIEN_ADDR = 14u << 3, // 0x70 + USBCTL_ADDR = 15u << 3, // 0x78 + CPUCTL_ADDR = 16u << 3, // 0x80 + PINCTL_ADDR = 17u << 3, // 0x88 + REVISION_ADDR = 18u << 3, // 0x90 + HIRQ_ADDR = 25u << 3, // 0xC8 + HIEN_ADDR = 26u << 3, // 0xD0 + MODE_ADDR = 27u << 3, // 0xD8 + PERADDR_ADDR = 28u << 3, // 0xE0 + HCTL_ADDR = 29u << 3, // 0xE8 + HXFR_ADDR = 30u << 3, // 0xF0 + HRSL_ADDR = 31u << 3, // 0xF8 +}; + +enum { + USBIRQ_OSCOK_IRQ = 1u << 0, + USBIRQ_NOVBUS_IRQ = 1u << 5, + USBIRQ_VBUS_IRQ = 1u << 6, +}; + +enum { + USBCTL_PWRDOWN = 1u << 4, + USBCTL_CHIPRES = 1u << 5, +}; + +enum { + CPUCTL_IE = 1u << 0, + CPUCTL_PULSEWID0 = 1u << 6, + CPUCTL_PULSEWID1 = 1u << 7, +}; + +enum { + PINCTL_GPXA = 1u << 0, + PINCTL_GPXB = 1u << 1, + PINCTL_POSINT = 1u << 2, + PINCTL_INTLEVEL = 1u << 3, + PINCTL_FDUPSPI = 1u << 4, +}; + +enum { + HIRQ_BUSEVENT_IRQ = 1u << 0, + HIRQ_RWU_IRQ = 1u << 1, + HIRQ_RCVDAV_IRQ = 1u << 2, + HIRQ_SNDBAV_IRQ = 1u << 3, + HIRQ_SUSDN_IRQ = 1u << 4, + HIRQ_CONDET_IRQ = 1u << 5, + HIRQ_FRAME_IRQ = 1u << 6, + HIRQ_HXFRDN_IRQ = 1u << 7, +}; + +enum { + MODE_HOST = 1u << 0, + MODE_LOWSPEED = 1u << 1, + MODE_HUBPRE = 1u << 2, + MODE_SOFKAENAB = 1u << 3, + MODE_SEPIRQ = 1u << 4, + MODE_DELAYISO = 1u << 5, + MODE_DMPULLDN = 1u << 6, + MODE_DPPULLDN = 1u << 7, +}; + +enum { + HCTL_BUSRST = 1u << 1, + HCTL_FRMRST = 1u << 2, + HCTL_SAMPLEBUS = 1u << 3, + HCTL_SIGRSM = 1u << 4, + HCTL_RCVTOG0 = 1u << 5, + HCTL_RCVTOG1 = 1u << 6, + HCTL_SNDTOG0 = 1u << 7, + HCTL_SNDTOG1 = 1u << 8, +}; + +enum { + HXFR_EPNUM_MASK = 0x0f, + HXFR_SETUP = 1u << 4, + HXFR_OUT_NIN = 1u << 5, + HXFR_ISO = 1u << 6, + HXFR_HS = 1u << 7, +}; + +enum { + HRSL_RESULT_MASK = 0x0f, + HRSL_RCVTOGRD = 1u << 4, + HRSL_SNDTOGRD = 1u << 5, + HRSL_KSTATUS = 1u << 6, + HRSL_JSTATUS = 1u << 7, +}; + +// API: SPI transfer with MAX3421E, must be implemented by application +bool tuh_max3421e_spi_xfer_api(uint8_t rhport, uint8_t const * tx_buf, size_t tx_len, uint8_t * rx_buf, size_t rx_len); + +// return HIRQ register since we are in full-duplex mode +static uint8_t reg_write(uint8_t reg, uint8_t data) { + uint8_t tx_buf[2] = {reg | CMDBYTE_WRITE, data}; + uint8_t rx_buf[2] = {0, 0}; + tuh_max3421e_spi_xfer_api(0, tx_buf, 2, rx_buf, 2); + return rx_buf[0]; +} + +static uint8_t reg_read(uint8_t reg) { + uint8_t tx_buf[2] = {reg, 0}; + uint8_t rx_buf[2] = {0, 0}; + return tuh_max3421e_spi_xfer_api(0, tx_buf, 2, rx_buf, 2) ? rx_buf[1] : 0; +} + + +//--------------------------------------------------------------------+ +// Controller API +//--------------------------------------------------------------------+ + +// optional hcd configuration, called by tuh_configure() +bool hcd_configure(uint8_t rhport, uint32_t cfg_id, const void* cfg_param) { + (void) rhport; + (void) cfg_id; + (void) cfg_param; + + return false; +} + +// Initialize controller to host mode +bool hcd_init(uint8_t rhport) { + (void) rhport; + + // full duplex, interrupt level (should be configurable) + reg_write(PINCTL_ADDR, PINCTL_FDUPSPI | PINCTL_INTLEVEL); + + // reset + reg_write(USBCTL_ADDR, USBCTL_CHIPRES); + reg_write(USBCTL_ADDR, 0); + while( !(reg_read(USBIRQ_ADDR) & USBIRQ_OSCOK_IRQ) ) { + // wait for oscillator to stabilize + } + + // Mode: Host and DP/DM pull down + reg_write(MODE_ADDR, MODE_DPPULLDN | MODE_DMPULLDN | MODE_HOST); + + // Connection detection + reg_write(HIEN_ADDR, HIRQ_CONDET_IRQ /*| HIRQ_FRAME_IRQ */); + + return false; +} + +// Interrupt Handler +void hcd_int_handler(uint8_t rhport) { + (void) rhport; +} + +// Enable USB interrupt +void hcd_int_enable (uint8_t rhport) { + (void) rhport; +} + +// Disable USB interrupt +void hcd_int_disable(uint8_t rhport) { + (void) rhport; +} + +// Get frame number (1ms) +uint32_t hcd_frame_number(uint8_t rhport) { + (void) rhport; + + return 0; +} + +//--------------------------------------------------------------------+ +// Port API +//--------------------------------------------------------------------+ + +// Get the current connect status of roothub port +bool hcd_port_connect_status(uint8_t rhport) { + (void) rhport; + + return false; +} + +// Reset USB bus on the port. Return immediately, bus reset sequence may not be complete. +// Some port would require hcd_port_reset_end() to be invoked after 10ms to complete the reset sequence. +void hcd_port_reset(uint8_t rhport) { + (void) rhport; +} + +// Complete bus reset sequence, may be required by some controllers +void hcd_port_reset_end(uint8_t rhport) { + (void) rhport; +} + +// Get port link speed +tusb_speed_t hcd_port_speed_get(uint8_t rhport) { + (void) rhport; + + return TUSB_SPEED_FULL; +} + +// HCD closes all opened endpoints belong to this device +void hcd_device_close(uint8_t rhport, uint8_t dev_addr) { + (void) rhport; + (void) dev_addr; +} + +//--------------------------------------------------------------------+ +// Endpoints API +//--------------------------------------------------------------------+ + +// Open an endpoint +bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const * ep_desc) { + (void) rhport; + (void) dev_addr; + (void) ep_desc; + + return false; +} + +// Submit a transfer, when complete hcd_event_xfer_complete() must be invoked +bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t * buffer, uint16_t buflen) { + (void) rhport; + (void) dev_addr; + (void) ep_addr; + (void) buffer; + (void) buflen; + + return false; +} + +// Abort a queued transfer. Note: it can only abort transfer that has not been started +// Return true if a queued transfer is aborted, false if there is no transfer to abort +bool hcd_edpt_abort_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr) { + (void) rhport; + (void) dev_addr; + (void) ep_addr; + + return false; +} + +// Submit a special transfer to send 8-byte Setup Packet, when complete hcd_event_xfer_complete() must be invoked +bool hcd_setup_send(uint8_t rhport, uint8_t dev_addr, uint8_t const setup_packet[8]) { + (void) rhport; + (void) dev_addr; + (void) setup_packet; + + return false; +} + +// clear stall, data toggle is also reset to DATA0 +bool hcd_edpt_clear_stall(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr) { + (void) rhport; + (void) dev_addr; + (void) ep_addr; + + return false; +} + +#endif From cacc96b25dc04865389357467b7a6d92d040ef36 Mon Sep 17 00:00:00 2001 From: hathach Date: Fri, 18 Aug 2023 17:39:10 +0700 Subject: [PATCH 03/34] adding connection event handling, add nrf gpio interrupt for max2341e interrupt pin --- .../boards/feather_nrf52840_express/board.h | 2 +- hw/bsp/nrf/family.c | 55 +++++++++----- hw/bsp/nrf/family.cmake | 2 + hw/bsp/nrf/nrfx_config.h | 2 +- hw/bsp/nrf/nrfx_glue.h | 69 +++++++++++++++++ src/portable/analog/max3421e/hcd_max3421e.c | 76 ++++++++++++++++++- 6 files changed, 184 insertions(+), 22 deletions(-) diff --git a/hw/bsp/nrf/boards/feather_nrf52840_express/board.h b/hw/bsp/nrf/boards/feather_nrf52840_express/board.h index e19f88a3ce..7f042142e4 100644 --- a/hw/bsp/nrf/boards/feather_nrf52840_express/board.h +++ b/hw/bsp/nrf/boards/feather_nrf52840_express/board.h @@ -50,7 +50,7 @@ #define SPI_MOSI_PIN 13 #define SPI_MISO_PIN 15 #define SPI_CS_PIN 27 -#define MAX3241E_INT_PIN 26 +#define MAX3241E_INTR_PIN 26 #ifdef __cplusplus } diff --git a/hw/bsp/nrf/family.c b/hw/bsp/nrf/family.c index b6ed15122f..e58ee845bd 100644 --- a/hw/bsp/nrf/family.c +++ b/hw/bsp/nrf/family.c @@ -38,6 +38,7 @@ #include "nrfx.h" #include "hal/nrf_gpio.h" +#include "drivers/include/nrfx_gpiote.h" #include "drivers/include/nrfx_power.h" #include "drivers/include/nrfx_uarte.h" #include "drivers/include/nrfx_spim.h" @@ -81,18 +82,45 @@ enum { #endif static nrfx_uarte_t _uart_id = NRFX_UARTE_INSTANCE(0); -static nrfx_spim_t _spi = NRFX_SPIM_INSTANCE(0); // tinyusb function that handles power event (detected, ready, removed) // We must call it within SD's SOC event handler, or set it as power event handler if SD is not enabled. extern void tusb_hal_nrf_power_event(uint32_t event); - // nrf power callback, could be unused if SD is enabled or usb is disabled (board_test example) TU_ATTR_UNUSED static void power_event_handler(nrfx_power_usb_evt_t event) { tusb_hal_nrf_power_event((uint32_t) event); } +//------------- Host using MAX2341E -------------// +#if CFG_TUH_ENABLED && defined(CFG_TUH_MAX3421E) && CFG_TUH_MAX3421E +static nrfx_spim_t _spi = NRFX_SPIM_INSTANCE(0); + +void max2342e_int_handler(nrfx_gpiote_pin_t pin, nrf_gpiote_polarity_t action) { + if ( !(pin == MAX3241E_INTR_PIN && action == NRF_GPIOTE_POLARITY_HITOLO) ) return; + + tuh_int_handler(1); +} + +// API: SPI transfer with MAX3421E, must be implemented by application +bool tuh_max3421e_spi_xfer_api(uint8_t rhport, uint8_t const * tx_buf, size_t tx_len, uint8_t * rx_buf, size_t rx_len) { + (void) rhport; + nrfx_spim_xfer_desc_t xfer = { + .p_tx_buffer = tx_buf, + .tx_length = tx_len, + .p_rx_buffer = rx_buf, + .rx_length = rx_len, + }; + return nrfx_spim_xfer(&_spi, &xfer, 0) == NRFX_SUCCESS; +} + +#endif + + +//--------------------------------------------------------------------+ +// +//--------------------------------------------------------------------+ + void board_init(void) { // stop LF clock just in case we jump from application without reset NRF_CLOCK->TASKS_LFCLKSTOP = 1UL; @@ -174,7 +202,6 @@ void board_init(void) { if ( usb_reg & OUTPUTRDY_Msk ) tusb_hal_nrf_power_event(USB_EVT_READY); #endif - (void) _spi; #if CFG_TUH_ENABLED && defined(CFG_TUH_MAX3421E) && CFG_TUH_MAX3421E // USB host using max3421e usb controller via SPI nrfx_spim_config_t cfg = { @@ -193,6 +220,14 @@ void board_init(void) { // no handler --> blocking nrfx_spim_init(&_spi, &cfg, NULL, NULL); + + // max3421e interrupt pin + nrfx_gpiote_init(1); + nrfx_gpiote_in_config_t in_config = NRFX_GPIOTE_CONFIG_IN_SENSE_HITOLO(true); + in_config.pull = NRF_GPIO_PIN_PULLUP; + + nrfx_gpiote_in_init(MAX3241E_INTR_PIN, &in_config, max2342e_int_handler); + nrfx_gpiote_in_event_enable(MAX3241E_INTR_PIN, true); #endif } @@ -233,20 +268,6 @@ uint32_t board_millis(void) { #endif -#if CFG_TUH_ENABLED && defined(CFG_TUH_MAX3421E) && CFG_TUH_MAX3421E -// API: SPI transfer with MAX3421E, must be implemented by application -bool tuh_max3421e_spi_xfer_api(uint8_t rhport, uint8_t const * tx_buf, size_t tx_len, uint8_t * rx_buf, size_t rx_len) { - (void) rhport; - nrfx_spim_xfer_desc_t xfer = { - .p_tx_buffer = tx_buf, - .tx_length = tx_len, - .p_rx_buffer = rx_buf, - .rx_length = rx_len, - }; - return nrfx_spim_xfer(&_spi, &xfer, 0) == NRFX_SUCCESS; -} -#endif - #ifdef SOFTDEVICE_PRESENT // process SOC event from SD uint32_t proc_soc(void) diff --git a/hw/bsp/nrf/family.cmake b/hw/bsp/nrf/family.cmake index 527251e716..8bf7bcb52e 100644 --- a/hw/bsp/nrf/family.cmake +++ b/hw/bsp/nrf/family.cmake @@ -32,6 +32,8 @@ function(add_board_target BOARD_TARGET) if (NOT TARGET ${BOARD_TARGET}) add_library(${BOARD_TARGET} STATIC # driver + ${NRFX_DIR}/helpers/nrfx_flag32_allocator.c + ${NRFX_DIR}/drivers/src/nrfx_gpiote.c ${NRFX_DIR}/drivers/src/nrfx_power.c ${NRFX_DIR}/drivers/src/nrfx_spim.c ${NRFX_DIR}/drivers/src/nrfx_uarte.c diff --git a/hw/bsp/nrf/nrfx_config.h b/hw/bsp/nrf/nrfx_config.h index d0f718c6cb..e3d0ea91b0 100644 --- a/hw/bsp/nrf/nrfx_config.h +++ b/hw/bsp/nrf/nrfx_config.h @@ -5,6 +5,7 @@ #define NRFX_POWER_DEFAULT_CONFIG_IRQ_PRIORITY 7 #define NRFX_CLOCK_ENABLED 0 +#define NRFX_GPIOTE_ENABLED 1 #define NRFX_UARTE_ENABLED 1 #define NRFX_UARTE0_ENABLED 1 @@ -41,5 +42,4 @@ #error "Unknown device." #endif - #endif // NRFX_CONFIG_H__ diff --git a/hw/bsp/nrf/nrfx_glue.h b/hw/bsp/nrf/nrfx_glue.h index cdf49b4ab7..ef756c6703 100644 --- a/hw/bsp/nrf/nrfx_glue.h +++ b/hw/bsp/nrf/nrfx_glue.h @@ -220,6 +220,75 @@ static inline bool _NRFX_IRQ_IS_PENDING(IRQn_Type irq_number) /** @} */ +//------------------------------------------------------------------------------ + +#include + +/** + * @brief Atomic 32 bit unsigned type. + */ +#define nrfx_atomic_t nrfx_atomic_u32_t + +/** + * @brief Stores value to an atomic object and returns previously stored value. + * + * @param[in] p_data Atomic memory pointer. + * @param[in] value Value to store. + * + * @return Old value stored into atomic object. + */ +#define NRFX_ATOMIC_FETCH_STORE(p_data, value) nrfx_atomic_u32_fetch_store(p_data, value) + +/** + * @brief Performs logical OR operation on an atomic object and returns previously stored value. + * + * @param[in] p_data Atomic memory pointer. + * @param[in] value Value of second operand of OR operation. + * + * @return Old value stored into atomic object. + */ +#define NRFX_ATOMIC_FETCH_OR(p_data, value) nrfx_atomic_u32_fetch_or(p_data, value) + +/** + * @brief Performs logical AND operation on an atomic object and returns previously stored value. + * + * @param[in] p_data Atomic memory pointer. + * @param[in] value Value of second operand of AND operation. + * + * @return Old value stored into atomic object. + */ +#define NRFX_ATOMIC_FETCH_AND(p_data, value) nrfx_atomic_u32_fetch_and(p_data, value) + +/** + * @brief Performs logical XOR operation on an atomic object and returns previously stored value. + * + * @param[in] p_data Atomic memory pointer. + * @param[in] value Value of second operand of XOR operation. + * + * @return Old value stored into atomic object. + */ +#define NRFX_ATOMIC_FETCH_XOR(p_data, value) nrfx_atomic_u32_fetch_xor(p_data, value) + +/** + * @brief Performs logical ADD operation on an atomic object and returns previously stored value. + * + * @param[in] p_data Atomic memory pointer. + * @param[in] value Value of second operand of ADD operation. + * + * @return Old value stored into atomic object. + */ +#define NRFX_ATOMIC_FETCH_ADD(p_data, value) nrfx_atomic_u32_fetch_add(p_data, value) + +/** + * @brief Performs logical SUB operation on an atomic object and returns previously stored value. + * + * @param[in] p_data Atomic memory pointer. + * @param[in] value Value of second operand of SUB operation. + * + * @return Old value stored into atomic object. + */ +#define NRFX_ATOMIC_FETCH_SUB(p_data, value) nrfx_atomic_u32_fetch_sub(p_data, value) + #ifdef __cplusplus } #endif diff --git a/src/portable/analog/max3421e/hcd_max3421e.c b/src/portable/analog/max3421e/hcd_max3421e.c index 7b9d73e4e5..a89581b9c4 100644 --- a/src/portable/analog/max3421e/hcd_max3421e.c +++ b/src/portable/analog/max3421e/hcd_max3421e.c @@ -136,6 +136,20 @@ enum { HRSL_JSTATUS = 1u << 7, }; +//--------------------------------------------------------------------+ +// +//--------------------------------------------------------------------+ + +//typedef struct { +// uint8_t mode +//} max2341e_data_t; +// +//max2341e_data_t max2341e_data; + +//--------------------------------------------------------------------+ +// +//--------------------------------------------------------------------+ + // API: SPI transfer with MAX3421E, must be implemented by application bool tuh_max3421e_spi_xfer_api(uint8_t rhport, uint8_t const * tx_buf, size_t tx_len, uint8_t * rx_buf, size_t rx_len); @@ -144,6 +158,7 @@ static uint8_t reg_write(uint8_t reg, uint8_t data) { uint8_t tx_buf[2] = {reg | CMDBYTE_WRITE, data}; uint8_t rx_buf[2] = {0, 0}; tuh_max3421e_spi_xfer_api(0, tx_buf, 2, rx_buf, 2); + TU_LOG2("HIRQ: %02X\r\n", rx_buf[0]); return rx_buf[0]; } @@ -167,6 +182,48 @@ bool hcd_configure(uint8_t rhport, uint32_t cfg_id, const void* cfg_param) { return false; } +tusb_speed_t handle_connect_irq(uint8_t rhport) { + (void) rhport; + + uint8_t const hrsl = reg_read(HRSL_ADDR); + uint8_t const jk = hrsl & (HRSL_JSTATUS | HRSL_KSTATUS); + + tusb_speed_t speed; + uint8_t new_mode = MODE_DPPULLDN | MODE_DMPULLDN | MODE_HOST; + + switch(jk) { + case 0x00: + // SEO is disconnected + speed = TUSB_SPEED_INVALID; + break; + + case (HRSL_JSTATUS | HRSL_KSTATUS): + // SE1 is illegal + speed = TUSB_SPEED_INVALID; + break; + + default: { + // Low speed if (LS = 1 and J-state) or (LS = 0 and K-State) + uint8_t const mode = reg_read(MODE_ADDR); + uint8_t const ls_bit = mode & MODE_LOWSPEED; + + if ( (ls_bit && (jk == HRSL_JSTATUS)) || (!ls_bit && (jk == HRSL_KSTATUS)) ) { + speed = TUSB_SPEED_LOW; + new_mode |= MODE_LOWSPEED; + } else { + speed = TUSB_SPEED_FULL; + } + + new_mode |= MODE_SOFKAENAB; // enable SOF since there is new device + + break; + } + } + + reg_write(MODE_ADDR, new_mode); + return speed; +} + // Initialize controller to host mode bool hcd_init(uint8_t rhport) { (void) rhport; @@ -184,15 +241,28 @@ bool hcd_init(uint8_t rhport) { // Mode: Host and DP/DM pull down reg_write(MODE_ADDR, MODE_DPPULLDN | MODE_DMPULLDN | MODE_HOST); - // Connection detection - reg_write(HIEN_ADDR, HIRQ_CONDET_IRQ /*| HIRQ_FRAME_IRQ */); + // Enable Connection IRQ + reg_write(HIEN_ADDR, HIRQ_CONDET_IRQ); - return false; + // Note: if device is already connected, CONDET IRQ may not be triggered. We need to detect it by sampling bus signal + reg_write(HCTL_ADDR, HCTL_SAMPLEBUS); + while( !(reg_read(HCTL_ADDR) & HCTL_SAMPLEBUS) ) {} + + handle_connect_irq(rhport); + reg_write(HIRQ_ADDR, HIRQ_CONDET_IRQ); + + // Enable Interrupt pin + reg_write(CPUCTL_ADDR, CPUCTL_IE); + + return true; } // Interrupt Handler void hcd_int_handler(uint8_t rhport) { (void) rhport; + + uint8_t hirq = reg_read(HIRQ_ADDR); + TU_LOG3_INT(hirq); } // Enable USB interrupt From b4134394166c1f77463b5cb62f28cff465fde174 Mon Sep 17 00:00:00 2001 From: hathach Date: Tue, 22 Aug 2023 19:57:59 +0700 Subject: [PATCH 04/34] able to detect new device and start enumerating --- src/portable/analog/max3421e/hcd_max3421e.c | 70 +++++++++++++++------ 1 file changed, 51 insertions(+), 19 deletions(-) diff --git a/src/portable/analog/max3421e/hcd_max3421e.c b/src/portable/analog/max3421e/hcd_max3421e.c index a89581b9c4..870c616a97 100644 --- a/src/portable/analog/max3421e/hcd_max3421e.c +++ b/src/portable/analog/max3421e/hcd_max3421e.c @@ -140,11 +140,13 @@ enum { // //--------------------------------------------------------------------+ -//typedef struct { -// uint8_t mode -//} max2341e_data_t; -// -//max2341e_data_t max2341e_data; +typedef struct { + uint8_t mode; + + volatile uint16_t frame_count; +} max2341e_data_t; + +static max2341e_data_t _hcd_data; //--------------------------------------------------------------------+ // @@ -168,6 +170,11 @@ static uint8_t reg_read(uint8_t reg) { return tuh_max3421e_spi_xfer_api(0, tx_buf, 2, rx_buf, 2) ? rx_buf[1] : 0; } +static inline uint8_t mode_write(uint8_t data) { + _hcd_data.mode = data; + return reg_write(MODE_ADDR, data); +} + //--------------------------------------------------------------------+ // Controller API @@ -220,7 +227,8 @@ tusb_speed_t handle_connect_irq(uint8_t rhport) { } } - reg_write(MODE_ADDR, new_mode); + mode_write(new_mode); + TU_LOG2_INT(speed); return speed; } @@ -228,6 +236,8 @@ tusb_speed_t handle_connect_irq(uint8_t rhport) { bool hcd_init(uint8_t rhport) { (void) rhport; + tu_memclr(&_hcd_data, sizeof(_hcd_data)); + // full duplex, interrupt level (should be configurable) reg_write(PINCTL_ADDR, PINCTL_FDUPSPI | PINCTL_INTLEVEL); @@ -239,17 +249,21 @@ bool hcd_init(uint8_t rhport) { } // Mode: Host and DP/DM pull down - reg_write(MODE_ADDR, MODE_DPPULLDN | MODE_DMPULLDN | MODE_HOST); + mode_write(MODE_DPPULLDN | MODE_DMPULLDN | MODE_HOST); // Enable Connection IRQ - reg_write(HIEN_ADDR, HIRQ_CONDET_IRQ); + reg_write(HIEN_ADDR, HIRQ_CONDET_IRQ | HIRQ_FRAME_IRQ); - // Note: if device is already connected, CONDET IRQ may not be triggered. We need to detect it by sampling bus signal + #if 0 + // Note: if device is already connected, CONDET IRQ may not be triggered. + // We need to detect it by sampling bus signal. FIXME not working reg_write(HCTL_ADDR, HCTL_SAMPLEBUS); - while( !(reg_read(HCTL_ADDR) & HCTL_SAMPLEBUS) ) {} + while ( reg_read(HCTL_ADDR) & HCTL_SAMPLEBUS ) {} - handle_connect_irq(rhport); - reg_write(HIRQ_ADDR, HIRQ_CONDET_IRQ); + if ( TUSB_SPEED_INVALID != handle_connect_irq(rhport) ) { + reg_write(HIRQ_ADDR, HIRQ_CONDET_IRQ); // clear connect irq + } + #endif // Enable Interrupt pin reg_write(CPUCTL_ADDR, CPUCTL_IE); @@ -262,7 +276,26 @@ void hcd_int_handler(uint8_t rhport) { (void) rhport; uint8_t hirq = reg_read(HIRQ_ADDR); - TU_LOG3_INT(hirq); + TU_LOG3_HEX(hirq); + + if (hirq & HIRQ_CONDET_IRQ) { + tusb_speed_t speed = handle_connect_irq(rhport); + + if (speed == TUSB_SPEED_INVALID) { + hcd_event_device_remove(rhport, true); + }else { + hcd_event_device_attach(rhport, true); + } + } + + if (hirq & HIRQ_FRAME_IRQ) { + _hcd_data.frame_count++; + } + + // clear all interrupt + if ( hirq ) { + reg_write(HIRQ_ADDR, hirq); + } } // Enable USB interrupt @@ -278,8 +311,7 @@ void hcd_int_disable(uint8_t rhport) { // Get frame number (1ms) uint32_t hcd_frame_number(uint8_t rhport) { (void) rhport; - - return 0; + return (uint32_t ) _hcd_data.frame_count; } //--------------------------------------------------------------------+ @@ -289,26 +321,26 @@ uint32_t hcd_frame_number(uint8_t rhport) { // Get the current connect status of roothub port bool hcd_port_connect_status(uint8_t rhport) { (void) rhport; - - return false; + return (_hcd_data.mode & MODE_SOFKAENAB) ? true : false; } // Reset USB bus on the port. Return immediately, bus reset sequence may not be complete. // Some port would require hcd_port_reset_end() to be invoked after 10ms to complete the reset sequence. void hcd_port_reset(uint8_t rhport) { (void) rhport; + reg_write(HCTL_ADDR, HCTL_BUSRST); } // Complete bus reset sequence, may be required by some controllers void hcd_port_reset_end(uint8_t rhport) { (void) rhport; + reg_write(HCTL_ADDR, 0); } // Get port link speed tusb_speed_t hcd_port_speed_get(uint8_t rhport) { (void) rhport; - - return TUSB_SPEED_FULL; + return (_hcd_data.mode & MODE_LOWSPEED) ? TUSB_SPEED_LOW : TUSB_SPEED_FULL; } // HCD closes all opened endpoints belong to this device From 274578ff46c31b231b3553dc9a20895646313130 Mon Sep 17 00:00:00 2001 From: hathach Date: Tue, 22 Aug 2023 23:17:12 +0700 Subject: [PATCH 05/34] able to send setup packet --- .../boards/feather_nrf52840_express/board.h | 8 +- hw/bsp/nrf/family.c | 36 +++- src/host/hcd.h | 2 +- src/host/usbh.c | 32 +--- src/portable/analog/max3421e/hcd_max3421e.c | 173 ++++++++++++++---- 5 files changed, 179 insertions(+), 72 deletions(-) diff --git a/hw/bsp/nrf/boards/feather_nrf52840_express/board.h b/hw/bsp/nrf/boards/feather_nrf52840_express/board.h index 7f042142e4..e6e7590acc 100644 --- a/hw/bsp/nrf/boards/feather_nrf52840_express/board.h +++ b/hw/bsp/nrf/boards/feather_nrf52840_express/board.h @@ -46,10 +46,10 @@ #define UART_TX_PIN 25 // SPI for USB host shield -#define SPI_SCK_PIN 14 -#define SPI_MOSI_PIN 13 -#define SPI_MISO_PIN 15 -#define SPI_CS_PIN 27 +#define MAX3421E_SCK_PIN 14 +#define MAX3421E_MOSI_PIN 13 +#define MAX3421E_MISO_PIN 15 +#define MAX3421E_CS_PIN 27 #define MAX3241E_INTR_PIN 26 #ifdef __cplusplus diff --git a/hw/bsp/nrf/family.c b/hw/bsp/nrf/family.c index e58ee845bd..862f67bc7b 100644 --- a/hw/bsp/nrf/family.c +++ b/hw/bsp/nrf/family.c @@ -96,22 +96,38 @@ TU_ATTR_UNUSED static void power_event_handler(nrfx_power_usb_evt_t event) { #if CFG_TUH_ENABLED && defined(CFG_TUH_MAX3421E) && CFG_TUH_MAX3421E static nrfx_spim_t _spi = NRFX_SPIM_INSTANCE(0); -void max2342e_int_handler(nrfx_gpiote_pin_t pin, nrf_gpiote_polarity_t action) { +void max3421e_int_handler(nrfx_gpiote_pin_t pin, nrf_gpiote_polarity_t action) { if ( !(pin == MAX3241E_INTR_PIN && action == NRF_GPIOTE_POLARITY_HITOLO) ) return; tuh_int_handler(1); } +static inline void max3421e_cs_assert(bool active) { + nrf_gpio_pin_write(MAX3421E_CS_PIN, active ? 0 : 1); +} + +//--------------------------------------------------------------------+ // API: SPI transfer with MAX3421E, must be implemented by application -bool tuh_max3421e_spi_xfer_api(uint8_t rhport, uint8_t const * tx_buf, size_t tx_len, uint8_t * rx_buf, size_t rx_len) { +//--------------------------------------------------------------------+ + +bool tuh_max3421e_spi_xfer_api(uint8_t rhport, uint8_t const * tx_buf, size_t tx_len, + uint8_t * rx_buf, size_t rx_len, bool keep_cs) { (void) rhport; + + max3421e_cs_assert(true); + nrfx_spim_xfer_desc_t xfer = { .p_tx_buffer = tx_buf, .tx_length = tx_len, .p_rx_buffer = rx_buf, .rx_length = rx_len, }; - return nrfx_spim_xfer(&_spi, &xfer, 0) == NRFX_SUCCESS; + + bool ret = (nrfx_spim_xfer(&_spi, &xfer, 0) == NRFX_SUCCESS); + + if ( !keep_cs ) max3421e_cs_assert(false); + + return ret; } #endif @@ -203,12 +219,16 @@ void board_init(void) { #endif #if CFG_TUH_ENABLED && defined(CFG_TUH_MAX3421E) && CFG_TUH_MAX3421E + // manually manage CS + nrf_gpio_cfg_output(MAX3421E_CS_PIN); + max3421e_cs_assert(false); + // USB host using max3421e usb controller via SPI nrfx_spim_config_t cfg = { - .sck_pin = SPI_SCK_PIN, - .mosi_pin = SPI_MOSI_PIN, - .miso_pin = SPI_MISO_PIN, - .ss_pin = SPI_CS_PIN, + .sck_pin = MAX3421E_SCK_PIN, + .mosi_pin = MAX3421E_MOSI_PIN, + .miso_pin = MAX3421E_MISO_PIN, + .ss_pin = NRFX_SPIM_PIN_NOT_USED, .ss_active_high = false, .irq_priority = 3, .orc = 0xFF, @@ -226,7 +246,7 @@ void board_init(void) { nrfx_gpiote_in_config_t in_config = NRFX_GPIOTE_CONFIG_IN_SENSE_HITOLO(true); in_config.pull = NRF_GPIO_PIN_PULLUP; - nrfx_gpiote_in_init(MAX3241E_INTR_PIN, &in_config, max2342e_int_handler); + nrfx_gpiote_in_init(MAX3241E_INTR_PIN, &in_config, max3421e_int_handler); nrfx_gpiote_in_event_enable(MAX3241E_INTR_PIN, true); #endif diff --git a/src/host/hcd.h b/src/host/hcd.h index 1b5038ef40..079877b79b 100644 --- a/src/host/hcd.h +++ b/src/host/hcd.h @@ -177,7 +177,7 @@ bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t * bool hcd_edpt_abort_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr); // Submit a special transfer to send 8-byte Setup Packet, when complete hcd_event_xfer_complete() must be invoked -bool hcd_setup_send(uint8_t rhport, uint8_t dev_addr, uint8_t const setup_packet[8]); +bool hcd_setup_send(uint8_t rhport, uint8_t daddr, uint8_t const setup_packet[8]); // clear stall, data toggle is also reset to DATA0 bool hcd_edpt_clear_stall(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr); diff --git a/src/host/usbh.c b/src/host/usbh.c index 5423df6693..7a09f5b6e2 100644 --- a/src/host/usbh.c +++ b/src/host/usbh.c @@ -552,8 +552,7 @@ static void _control_blocking_complete_cb(tuh_xfer_t* xfer) } // TODO timeout_ms is not supported yet -bool tuh_control_xfer (tuh_xfer_t* xfer) -{ +bool tuh_control_xfer (tuh_xfer_t* xfer) { // EP0 with setup packet TU_VERIFY(xfer->ep_addr == 0 && xfer->setup); @@ -565,8 +564,7 @@ bool tuh_control_xfer (tuh_xfer_t* xfer) (void) osal_mutex_lock(_usbh_mutex, OSAL_TIMEOUT_WAIT_FOREVER); bool const is_idle = (_ctrl_xfer.stage == CONTROL_STAGE_IDLE); - if (is_idle) - { + if (is_idle) { _ctrl_xfer.stage = CONTROL_STAGE_SETUP; _ctrl_xfer.daddr = daddr; _ctrl_xfer.actual_len = 0; @@ -588,11 +586,9 @@ bool tuh_control_xfer (tuh_xfer_t* xfer) TU_LOG_PTR(CFG_TUH_LOG_LEVEL, xfer->setup); TU_LOG_USBH("\r\n"); - if (xfer->complete_cb) - { + if (xfer->complete_cb) { TU_ASSERT( hcd_setup_send(rhport, daddr, (uint8_t const*) &_ctrl_xfer.request) ); - }else - { + }else { // blocking if complete callback is not provided // change callback to internal blocking, and result as user argument volatile xfer_result_t result = XFER_RESULT_INVALID; @@ -656,15 +652,13 @@ static void _xfer_complete(uint8_t daddr, xfer_result_t result) } } -static bool usbh_control_xfer_cb (uint8_t dev_addr, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) -{ +static bool usbh_control_xfer_cb (uint8_t dev_addr, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) { (void) ep_addr; const uint8_t rhport = usbh_get_rhport(dev_addr); tusb_control_request_t const * request = &_ctrl_xfer.request; - if (XFER_RESULT_SUCCESS != result) - { + if (XFER_RESULT_SUCCESS != result) { TU_LOG1("[%u:%u] Control %s, xferred_bytes = %lu\r\n", rhport, dev_addr, result == XFER_RESULT_STALLED ? "STALLED" : "FAILED", xferred_bytes); #if CFG_TUSB_DEBUG == 1 TU_LOG1_PTR(request); @@ -673,13 +667,10 @@ static bool usbh_control_xfer_cb (uint8_t dev_addr, uint8_t ep_addr, xfer_result // terminate transfer if any stage failed _xfer_complete(dev_addr, result); - }else - { - switch(_ctrl_xfer.stage) - { + }else { + switch(_ctrl_xfer.stage) { case CONTROL_STAGE_SETUP: - if (request->wLength) - { + if (request->wLength) { // DATA stage: initial data toggle is always 1 _set_control_xfer_stage(CONTROL_STAGE_DATA); TU_ASSERT( hcd_edpt_xfer(rhport, dev_addr, tu_edpt_addr(0, request->bmRequestType_bit.direction), _ctrl_xfer.buffer, request->wLength) ); @@ -688,8 +679,7 @@ static bool usbh_control_xfer_cb (uint8_t dev_addr, uint8_t ep_addr, xfer_result TU_ATTR_FALLTHROUGH; case CONTROL_STAGE_DATA: - if (request->wLength) - { + if (request->wLength) { TU_LOG_USBH("[%u:%u] Control data:\r\n", rhport, dev_addr); TU_LOG_MEM(CFG_TUH_LOG_LEVEL, _ctrl_xfer.buffer, xferred_bytes, 2); } @@ -1538,9 +1528,7 @@ static bool enum_new_device(hcd_event_t* event) xfer.result = XFER_RESULT_SUCCESS; xfer.user_data = ENUM_ADDR0_DEVICE_DESC; - process_enumeration(&xfer); - } #if CFG_TUH_HUB else diff --git a/src/portable/analog/max3421e/hcd_max3421e.c b/src/portable/analog/max3421e/hcd_max3421e.c index 870c616a97..c9596f695a 100644 --- a/src/portable/analog/max3421e/hcd_max3421e.c +++ b/src/portable/analog/max3421e/hcd_max3421e.c @@ -136,30 +136,64 @@ enum { HRSL_JSTATUS = 1u << 7, }; +enum { + HRSL_SUCCESS = 0, + HRSL_BUSY, + HRSL_BAD_REQ, + HRSL_UNDEF, + HRSL_NAK, + HRSL_STALL, + HRSL_TOG_ERR, + HRSL_WRONG_PID, + HRSL_BAD_BYTECOUNT, + HRSL_PID_ERR, + HRSL_PKT_ERR, + HRSL_CRC_ERR, + HRSL_K_ERR, + HRSL_J_ERR, + HRSL_TIMEOUT, + HRSL_BABBLE, +}; + + //--------------------------------------------------------------------+ // //--------------------------------------------------------------------+ typedef struct { + // cached register uint8_t mode; + uint8_t peraddr; + uint8_t hxfr; volatile uint16_t frame_count; + + struct { + uint16_t packet_size; + uint16_t total_len; + uint8_t xfer_type; + }ep[8][2]; } max2341e_data_t; static max2341e_data_t _hcd_data; //--------------------------------------------------------------------+ -// +// API: SPI transfer with MAX3421E, must be implemented by application //--------------------------------------------------------------------+ -// API: SPI transfer with MAX3421E, must be implemented by application -bool tuh_max3421e_spi_xfer_api(uint8_t rhport, uint8_t const * tx_buf, size_t tx_len, uint8_t * rx_buf, size_t rx_len); +bool tuh_max3421e_spi_xfer_api(uint8_t rhport, uint8_t const * tx_buf, size_t tx_len, + uint8_t * rx_buf, size_t rx_len, bool keep_cs); +//void tuh_max3421e_int_enable(uint8_t rhport, bool enabled); + +//--------------------------------------------------------------------+ +// +//--------------------------------------------------------------------+ // return HIRQ register since we are in full-duplex mode static uint8_t reg_write(uint8_t reg, uint8_t data) { uint8_t tx_buf[2] = {reg | CMDBYTE_WRITE, data}; uint8_t rx_buf[2] = {0, 0}; - tuh_max3421e_spi_xfer_api(0, tx_buf, 2, rx_buf, 2); + tuh_max3421e_spi_xfer_api(0, tx_buf, 2, rx_buf, 2, false); TU_LOG2("HIRQ: %02X\r\n", rx_buf[0]); return rx_buf[0]; } @@ -167,7 +201,7 @@ static uint8_t reg_write(uint8_t reg, uint8_t data) { static uint8_t reg_read(uint8_t reg) { uint8_t tx_buf[2] = {reg, 0}; uint8_t rx_buf[2] = {0, 0}; - return tuh_max3421e_spi_xfer_api(0, tx_buf, 2, rx_buf, 2) ? rx_buf[1] : 0; + return tuh_max3421e_spi_xfer_api(0, tx_buf, 2, rx_buf, 2, false) ? rx_buf[1] : 0; } static inline uint8_t mode_write(uint8_t data) { @@ -175,6 +209,24 @@ static inline uint8_t mode_write(uint8_t data) { return reg_write(MODE_ADDR, data); } +static inline uint8_t peraddr_write(uint8_t data) { + if ( _hcd_data.peraddr == data ) return 0; // no need to change address + + _hcd_data.peraddr = data; + return reg_write(PERADDR_ADDR, data); +} + +static inline uint8_t hxfr_write(uint8_t data) { + _hcd_data.hxfr = data; + return reg_write(HXFR_ADDR, data); +} + +static void fifo_write(uint8_t reg, uint8_t const * buffer, uint16_t len) { + uint8_t tx_buf[1] = {reg | CMDBYTE_WRITE}; + tuh_max3421e_spi_xfer_api(0, tx_buf, 1, NULL, 0, true); + tuh_max3421e_spi_xfer_api(0, buffer, len, NULL, 0, false); +} + //--------------------------------------------------------------------+ // Controller API @@ -252,7 +304,7 @@ bool hcd_init(uint8_t rhport) { mode_write(MODE_DPPULLDN | MODE_DMPULLDN | MODE_HOST); // Enable Connection IRQ - reg_write(HIEN_ADDR, HIRQ_CONDET_IRQ | HIRQ_FRAME_IRQ); + reg_write(HIEN_ADDR, HIRQ_CONDET_IRQ | HIRQ_FRAME_IRQ | HIRQ_HXFRDN_IRQ); #if 0 // Note: if device is already connected, CONDET IRQ may not be triggered. @@ -271,33 +323,6 @@ bool hcd_init(uint8_t rhport) { return true; } -// Interrupt Handler -void hcd_int_handler(uint8_t rhport) { - (void) rhport; - - uint8_t hirq = reg_read(HIRQ_ADDR); - TU_LOG3_HEX(hirq); - - if (hirq & HIRQ_CONDET_IRQ) { - tusb_speed_t speed = handle_connect_irq(rhport); - - if (speed == TUSB_SPEED_INVALID) { - hcd_event_device_remove(rhport, true); - }else { - hcd_event_device_attach(rhport, true); - } - } - - if (hirq & HIRQ_FRAME_IRQ) { - _hcd_data.frame_count++; - } - - // clear all interrupt - if ( hirq ) { - reg_write(HIRQ_ADDR, hirq); - } -} - // Enable USB interrupt void hcd_int_enable (uint8_t rhport) { (void) rhport; @@ -359,7 +384,12 @@ bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const (void) dev_addr; (void) ep_desc; - return false; + uint8_t ep_num = tu_edpt_number(ep_desc->bEndpointAddress); + uint8_t ep_dir = tu_edpt_dir(ep_desc->bEndpointAddress); + + _hcd_data.ep[ep_num][ep_dir].packet_size = tu_edpt_packet_size(ep_desc); + + return true; } // Submit a transfer, when complete hcd_event_xfer_complete() must be invoked @@ -384,12 +414,18 @@ bool hcd_edpt_abort_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr) { } // Submit a special transfer to send 8-byte Setup Packet, when complete hcd_event_xfer_complete() must be invoked -bool hcd_setup_send(uint8_t rhport, uint8_t dev_addr, uint8_t const setup_packet[8]) { +bool hcd_setup_send(uint8_t rhport, uint8_t daddr, uint8_t const setup_packet[8]) { (void) rhport; - (void) dev_addr; + (void) daddr; (void) setup_packet; - return false; + _hcd_data.ep[0][0].total_len = 8; + + peraddr_write(daddr); + fifo_write(SUDFIFO_ADDR, setup_packet, 8); + hxfr_write(HXFR_SETUP); + + return true; } // clear stall, data toggle is also reset to DATA0 @@ -401,4 +437,67 @@ bool hcd_edpt_clear_stall(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr) { return false; } +// Interrupt Handler +void hcd_int_handler(uint8_t rhport) { + uint8_t hirq = reg_read(HIRQ_ADDR); + TU_LOG3_HEX(hirq); + + if (hirq & HIRQ_CONDET_IRQ) { + tusb_speed_t speed = handle_connect_irq(rhport); + + if (speed == TUSB_SPEED_INVALID) { + hcd_event_device_remove(rhport, true); + }else { + hcd_event_device_attach(rhport, true); + } + } + + if (hirq & HIRQ_FRAME_IRQ) { + _hcd_data.frame_count++; + } + + if (hirq & HIRQ_HXFRDN_IRQ) { + uint8_t const hrsl = reg_read(HRSL_ADDR); + uint8_t const result = hrsl & HRSL_RESULT_MASK; + uint8_t xfer_result; + + TU_LOG3("HRSL: %02X\r\n", hrsl); + switch(result) { + case HRSL_SUCCESS: + xfer_result = XFER_RESULT_SUCCESS; + break; + + case HRSL_STALL: + xfer_result = XFER_RESULT_STALLED; + break; + + default: + xfer_result = XFER_RESULT_FAILED; + break; + } + + uint8_t ep_dir = 0; + uint8_t ep_num = _hcd_data.hxfr & HXFR_EPNUM_MASK; + uint8_t const xfer_type = _hcd_data.hxfr & 0xf0; + + if ( xfer_type & HXFR_SETUP ) { + // SETUP transfer + ep_dir = 0; + }else if ( !(xfer_type & HXFR_OUT_NIN) ) { + // IN transfer + ep_dir = 1; + } + + uint8_t const ep_addr = tu_edpt_addr(ep_num, ep_dir); + uint16_t xferred_len = _hcd_data.ep[ep_num][ep_dir].total_len; + + hcd_event_xfer_complete(_hcd_data.peraddr, ep_addr, xferred_len, xfer_result, true); + } + + // clear all interrupt + if ( hirq ) { + reg_write(HIRQ_ADDR, hirq); + } +} + #endif From e3f3179924f7c84c4bb3e69234720f9afc178727 Mon Sep 17 00:00:00 2001 From: hathach Date: Wed, 23 Aug 2023 15:08:12 +0700 Subject: [PATCH 06/34] able to get 8 byte descriptor, but read(RCVBC) always return 0 - rename max3421e to max3421 - fix incorrect bitmask for HCTL, fix initial device connect - fix bus reset cause connect IRQ --- hw/bsp/nrf/family.c | 24 +- hw/bsp/nrf/family.cmake | 2 +- src/host/hcd.h | 2 +- .../hcd_max3421e.c => max3421/hcd_max3421.c} | 280 ++++++++++++------ 4 files changed, 206 insertions(+), 102 deletions(-) rename src/portable/analog/{max3421e/hcd_max3421e.c => max3421/hcd_max3421.c} (67%) diff --git a/hw/bsp/nrf/family.c b/hw/bsp/nrf/family.c index 862f67bc7b..45a5166a75 100644 --- a/hw/bsp/nrf/family.c +++ b/hw/bsp/nrf/family.c @@ -93,7 +93,7 @@ TU_ATTR_UNUSED static void power_event_handler(nrfx_power_usb_evt_t event) { } //------------- Host using MAX2341E -------------// -#if CFG_TUH_ENABLED && defined(CFG_TUH_MAX3421E) && CFG_TUH_MAX3421E +#if CFG_TUH_ENABLED && defined(CFG_TUH_MAX3421) && CFG_TUH_MAX3421 static nrfx_spim_t _spi = NRFX_SPIM_INSTANCE(0); void max3421e_int_handler(nrfx_gpiote_pin_t pin, nrf_gpiote_polarity_t action) { @@ -102,19 +102,17 @@ void max3421e_int_handler(nrfx_gpiote_pin_t pin, nrf_gpiote_polarity_t action) { tuh_int_handler(1); } -static inline void max3421e_cs_assert(bool active) { - nrf_gpio_pin_write(MAX3421E_CS_PIN, active ? 0 : 1); -} - //--------------------------------------------------------------------+ // API: SPI transfer with MAX3421E, must be implemented by application //--------------------------------------------------------------------+ -bool tuh_max3421e_spi_xfer_api(uint8_t rhport, uint8_t const * tx_buf, size_t tx_len, - uint8_t * rx_buf, size_t rx_len, bool keep_cs) { +void tuh_max3421_spi_cs_api(uint8_t rhport, bool active) { (void) rhport; + nrf_gpio_pin_write(MAX3421E_CS_PIN, active ? 0 : 1); +} - max3421e_cs_assert(true); +bool tuh_max3421_spi_xfer_api(uint8_t rhport, uint8_t const * tx_buf, size_t tx_len, uint8_t * rx_buf, size_t rx_len) { + (void) rhport; nrfx_spim_xfer_desc_t xfer = { .p_tx_buffer = tx_buf, @@ -123,11 +121,7 @@ bool tuh_max3421e_spi_xfer_api(uint8_t rhport, uint8_t const * tx_buf, size_t tx .rx_length = rx_len, }; - bool ret = (nrfx_spim_xfer(&_spi, &xfer, 0) == NRFX_SUCCESS); - - if ( !keep_cs ) max3421e_cs_assert(false); - - return ret; + return (nrfx_spim_xfer(&_spi, &xfer, 0) == NRFX_SUCCESS); } #endif @@ -218,10 +212,10 @@ void board_init(void) { if ( usb_reg & OUTPUTRDY_Msk ) tusb_hal_nrf_power_event(USB_EVT_READY); #endif -#if CFG_TUH_ENABLED && defined(CFG_TUH_MAX3421E) && CFG_TUH_MAX3421E +#if CFG_TUH_ENABLED && defined(CFG_TUH_MAX3421) && CFG_TUH_MAX3421 // manually manage CS nrf_gpio_cfg_output(MAX3421E_CS_PIN); - max3421e_cs_assert(false); + tuh_max3421_spi_cs_api(0, false); // USB host using max3421e usb controller via SPI nrfx_spim_config_t cfg = { diff --git a/hw/bsp/nrf/family.cmake b/hw/bsp/nrf/family.cmake index 8bf7bcb52e..ff6b882cea 100644 --- a/hw/bsp/nrf/family.cmake +++ b/hw/bsp/nrf/family.cmake @@ -124,7 +124,7 @@ function(family_configure_example TARGET RTOS) family_add_tinyusb(${TARGET} OPT_MCU_NRF5X ${RTOS}) target_sources(${TARGET}-tinyusb PUBLIC ${TOP}/src/portable/nordic/nrf5x/dcd_nrf5x.c - ${TOP}/src/portable/analog/max3421e/hcd_max3421e.c + ${TOP}/src/portable/analog/max3421/hcd_max3421.c ) target_link_libraries(${TARGET}-tinyusb PUBLIC board_${BOARD}) diff --git a/src/host/hcd.h b/src/host/hcd.h index 079877b79b..1f01a1a2f5 100644 --- a/src/host/hcd.h +++ b/src/host/hcd.h @@ -170,7 +170,7 @@ void hcd_device_close(uint8_t rhport, uint8_t dev_addr); bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const * ep_desc); // Submit a transfer, when complete hcd_event_xfer_complete() must be invoked -bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t * buffer, uint16_t buflen); +bool hcd_edpt_xfer(uint8_t rhport, uint8_t daddr, uint8_t ep_addr, uint8_t * buffer, uint16_t buflen); // Abort a queued transfer. Note: it can only abort transfer that has not been started // Return true if a queued transfer is aborted, false if there is no transfer to abort diff --git a/src/portable/analog/max3421e/hcd_max3421e.c b/src/portable/analog/max3421/hcd_max3421.c similarity index 67% rename from src/portable/analog/max3421e/hcd_max3421e.c rename to src/portable/analog/max3421/hcd_max3421.c index c9596f695a..edcb6ca6f7 100644 --- a/src/portable/analog/max3421e/hcd_max3421e.c +++ b/src/portable/analog/max3421/hcd_max3421.c @@ -26,7 +26,7 @@ #include "tusb_option.h" -#if CFG_TUH_ENABLED && defined(CFG_TUH_MAX3421E) && CFG_TUH_MAX3421E +#if CFG_TUH_ENABLED && defined(CFG_TUH_MAX3421) && CFG_TUH_MAX3421 #include "host/hcd.h" @@ -110,14 +110,14 @@ enum { }; enum { - HCTL_BUSRST = 1u << 1, - HCTL_FRMRST = 1u << 2, - HCTL_SAMPLEBUS = 1u << 3, - HCTL_SIGRSM = 1u << 4, - HCTL_RCVTOG0 = 1u << 5, - HCTL_RCVTOG1 = 1u << 6, - HCTL_SNDTOG0 = 1u << 7, - HCTL_SNDTOG1 = 1u << 8, + HCTL_BUSRST = 1u << 0, + HCTL_FRMRST = 1u << 1, + HCTL_SAMPLEBUS = 1u << 2, + HCTL_SIGRSM = 1u << 3, + HCTL_RCVTOG0 = 1u << 4, + HCTL_RCVTOG1 = 1u << 5, + HCTL_SNDTOG0 = 1u << 6, + HCTL_SNDTOG1 = 1u << 7, }; enum { @@ -155,45 +155,73 @@ enum { HRSL_BABBLE, }; +enum { + DEFAULT_HIEN = HIRQ_CONDET_IRQ | HIRQ_FRAME_IRQ | HIRQ_HXFRDN_IRQ +}; //--------------------------------------------------------------------+ // //--------------------------------------------------------------------+ typedef struct { + uint8_t xfer_type; + uint8_t data_toggle; + uint16_t packet_size; + + uint16_t total_len; + uint16_t xferred_len; + uint8_t* buf; +} hcd_ep_t; + +typedef struct { + bool inited; + // cached register + uint8_t sndbc; uint8_t mode; uint8_t peraddr; uint8_t hxfr; volatile uint16_t frame_count; - struct { - uint16_t packet_size; - uint16_t total_len; - uint8_t xfer_type; - }ep[8][2]; -} max2341e_data_t; + hcd_ep_t ep[8][2]; +} max2341_data_t; -static max2341e_data_t _hcd_data; +static max2341_data_t _hcd_data; //--------------------------------------------------------------------+ // API: SPI transfer with MAX3421E, must be implemented by application //--------------------------------------------------------------------+ -bool tuh_max3421e_spi_xfer_api(uint8_t rhport, uint8_t const * tx_buf, size_t tx_len, - uint8_t * rx_buf, size_t rx_len, bool keep_cs); +void tuh_max3421_spi_cs_api(uint8_t rhport, bool active); +bool tuh_max3421_spi_xfer_api(uint8_t rhport, uint8_t const * tx_buf, size_t tx_len, uint8_t * rx_buf, size_t rx_len); + //void tuh_max3421e_int_enable(uint8_t rhport, bool enabled); //--------------------------------------------------------------------+ // //--------------------------------------------------------------------+ +static void fifo_write(uint8_t reg, uint8_t const * buffer, uint16_t len) { + reg |= CMDBYTE_WRITE; + + tuh_max3421_spi_cs_api(0, true); + + tuh_max3421_spi_xfer_api(0, ®, 1, NULL, 0); + tuh_max3421_spi_xfer_api(0, buffer, len, NULL, 0); + + tuh_max3421_spi_cs_api(0, false); +} + // return HIRQ register since we are in full-duplex mode static uint8_t reg_write(uint8_t reg, uint8_t data) { uint8_t tx_buf[2] = {reg | CMDBYTE_WRITE, data}; uint8_t rx_buf[2] = {0, 0}; - tuh_max3421e_spi_xfer_api(0, tx_buf, 2, rx_buf, 2, false); + + tuh_max3421_spi_cs_api(0, true); + tuh_max3421_spi_xfer_api(0, tx_buf, 2, rx_buf, 2); + tuh_max3421_spi_cs_api(0, false); + TU_LOG2("HIRQ: %02X\r\n", rx_buf[0]); return rx_buf[0]; } @@ -201,7 +229,12 @@ static uint8_t reg_write(uint8_t reg, uint8_t data) { static uint8_t reg_read(uint8_t reg) { uint8_t tx_buf[2] = {reg, 0}; uint8_t rx_buf[2] = {0, 0}; - return tuh_max3421e_spi_xfer_api(0, tx_buf, 2, rx_buf, 2, false) ? rx_buf[1] : 0; + + tuh_max3421_spi_cs_api(0, true); + bool ret = tuh_max3421_spi_xfer_api(0, tx_buf, 2, rx_buf, 2); + tuh_max3421_spi_cs_api(0, false); + + return ret ? rx_buf[1] : 0; } static inline uint8_t mode_write(uint8_t data) { @@ -221,10 +254,9 @@ static inline uint8_t hxfr_write(uint8_t data) { return reg_write(HXFR_ADDR, data); } -static void fifo_write(uint8_t reg, uint8_t const * buffer, uint16_t len) { - uint8_t tx_buf[1] = {reg | CMDBYTE_WRITE}; - tuh_max3421e_spi_xfer_api(0, tx_buf, 1, NULL, 0, true); - tuh_max3421e_spi_xfer_api(0, buffer, len, NULL, 0, false); +static inline uint8_t sndbc_write(uint8_t data) { + _hcd_data.sndbc = data; + return reg_write(SNDBC_ADDR, data); } @@ -290,8 +322,8 @@ bool hcd_init(uint8_t rhport) { tu_memclr(&_hcd_data, sizeof(_hcd_data)); - // full duplex, interrupt level (should be configurable) - reg_write(PINCTL_ADDR, PINCTL_FDUPSPI | PINCTL_INTLEVEL); + // full duplex, interrupt negative edge + reg_write(PINCTL_ADDR, PINCTL_FDUPSPI); // reset reg_write(USBCTL_ADDR, USBCTL_CHIPRES); @@ -303,19 +335,16 @@ bool hcd_init(uint8_t rhport) { // Mode: Host and DP/DM pull down mode_write(MODE_DPPULLDN | MODE_DMPULLDN | MODE_HOST); - // Enable Connection IRQ - reg_write(HIEN_ADDR, HIRQ_CONDET_IRQ | HIRQ_FRAME_IRQ | HIRQ_HXFRDN_IRQ); + // bus reset, this will trigger CONDET IRQ if device is already connected + reg_write(HCTL_ADDR, HCTL_BUSRST); - #if 0 - // Note: if device is already connected, CONDET IRQ may not be triggered. - // We need to detect it by sampling bus signal. FIXME not working - reg_write(HCTL_ADDR, HCTL_SAMPLEBUS); - while ( reg_read(HCTL_ADDR) & HCTL_SAMPLEBUS ) {} + // clear all previously pending IRQ + reg_write(HIRQ_ADDR, 0xff); - if ( TUSB_SPEED_INVALID != handle_connect_irq(rhport) ) { - reg_write(HIRQ_ADDR, HIRQ_CONDET_IRQ); // clear connect irq - } - #endif + _hcd_data.inited = true; + + // Enable Connection IRQ + reg_write(HIEN_ADDR, DEFAULT_HIEN); // Enable Interrupt pin reg_write(CPUCTL_ADDR, CPUCTL_IE); @@ -353,6 +382,10 @@ bool hcd_port_connect_status(uint8_t rhport) { // Some port would require hcd_port_reset_end() to be invoked after 10ms to complete the reset sequence. void hcd_port_reset(uint8_t rhport) { (void) rhport; + // Bus reset will also trigger CONDET IRQ, disable it + uint8_t hien = DEFAULT_HIEN & ~HIRQ_CONDET_IRQ; + reg_write(HIEN_ADDR, hien); + reg_write(HCTL_ADDR, HCTL_BUSRST); } @@ -360,6 +393,10 @@ void hcd_port_reset(uint8_t rhport) { void hcd_port_reset_end(uint8_t rhport) { (void) rhport; reg_write(HCTL_ADDR, 0); + + // Bus reset will also trigger CONDET IRQ, clear and re-enable it after reset + reg_write(HIRQ_ADDR, HIRQ_CONDET_IRQ); + reg_write(HIEN_ADDR, DEFAULT_HIEN); } // Get port link speed @@ -393,14 +430,51 @@ bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const } // Submit a transfer, when complete hcd_event_xfer_complete() must be invoked -bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t * buffer, uint16_t buflen) { +bool hcd_edpt_xfer(uint8_t rhport, uint8_t daddr, uint8_t ep_addr, uint8_t * buffer, uint16_t buflen) { (void) rhport; - (void) dev_addr; - (void) ep_addr; - (void) buffer; - (void) buflen; - return false; + uint8_t const ep_num = tu_edpt_number(ep_addr); + uint8_t const ep_dir = tu_edpt_dir(ep_addr); + + hcd_ep_t* ep = &_hcd_data.ep[ep_num][ep_dir]; + + ep->buf = buffer; + ep->total_len = buflen; + ep->xferred_len = 0; + + uint8_t hirq = peraddr_write(daddr); + + uint8_t hctl = 0; + uint8_t hxfr = ep_num; + if ( ep_num == 0 ) { + ep->data_toggle = 1; + if ( buffer == NULL || buflen == 0 ) { + // ZLP for ACK stage + hxfr |= HXFR_HS; + } + } else if ( ep->xfer_type == TUSB_XFER_ISOCHRONOUS ) { + hxfr |= HXFR_ISO; + } + + if ( 0 == ep_dir ) { + // Page 12: Programming BULK-OUT Transfers + TU_ASSERT(hirq & HIRQ_RCVDAV_IRQ); + + uint8_t const xact_len = (uint8_t) tu_min16(buflen, ep->packet_size); + fifo_write(SNDFIFO_ADDR, buffer, xact_len); + reg_write(SNDBC_ADDR, xact_len); + + hctl = (ep->data_toggle ? HCTL_SNDTOG1 : HCTL_SNDTOG0); + hxfr |= HXFR_OUT_NIN; + } else { + // Page 13: Programming BULK-IN Transfers + hctl = (ep->data_toggle ? HCTL_RCVTOG1 : HCTL_RCVTOG0); + } + + reg_write(HCTL_ADDR, hctl); + hxfr_write(hxfr); + + return true; } // Abort a queued transfer. Note: it can only abort transfer that has not been started @@ -416,10 +490,10 @@ bool hcd_edpt_abort_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr) { // Submit a special transfer to send 8-byte Setup Packet, when complete hcd_event_xfer_complete() must be invoked bool hcd_setup_send(uint8_t rhport, uint8_t daddr, uint8_t const setup_packet[8]) { (void) rhport; - (void) daddr; - (void) setup_packet; - _hcd_data.ep[0][0].total_len = 8; + hcd_ep_t* ep = &_hcd_data.ep[0][0]; + ep->total_len = 8; + ep->xferred_len = 0; peraddr_write(daddr); fifo_write(SUDFIFO_ADDR, setup_packet, 8); @@ -437,11 +511,79 @@ bool hcd_edpt_clear_stall(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr) { return false; } +static void handle_xfer_done(uint8_t rhport) { + (void) rhport; + + uint8_t const hrsl = reg_read(HRSL_ADDR); + uint8_t const result = hrsl & HRSL_RESULT_MASK; + uint8_t xfer_result; + + TU_LOG3("HRSL: %02X\r\n", hrsl); + switch(result) { + case HRSL_SUCCESS: + xfer_result = XFER_RESULT_SUCCESS; + break; + + case HRSL_STALL: + xfer_result = XFER_RESULT_STALLED; + break; + + case HRSL_BAD_REQ: + // occurred when initialized without any pending transfer. Skip for now + return; + + default: + xfer_result = XFER_RESULT_FAILED; + break; + } + + uint8_t ep_dir = 0; + uint8_t ep_num = _hcd_data.hxfr & HXFR_EPNUM_MASK; + uint8_t const xfer_type = _hcd_data.hxfr & 0xf0; + + hcd_ep_t * ep; + + if ( (xfer_type & HXFR_SETUP) || (xfer_type & HXFR_OUT_NIN) ) { + // SETUP or OUT transfer + ep_dir = 0; + ep = &_hcd_data.ep[ep_num][ep_dir]; + + uint8_t const xact_len = (xfer_type & HXFR_SETUP) ? 8 : _hcd_data.sndbc; + ep->xferred_len += xact_len; + + if ( xact_len < ep->packet_size || ep->xferred_len >= ep->total_len ) { + hcd_event_xfer_complete(_hcd_data.peraddr, ep_num, ep->xferred_len, xfer_result, true); + }else { + // more to transfer + } + } else { + // IN transfer + ep_dir = 1; + ep = &_hcd_data.ep[ep_num][ep_dir]; + uint8_t const xact_len = reg_read(RCVBC_ADDR); + ep->xferred_len += xact_len; + + // short packet or all bytes transferred + if ( xact_len < ep->packet_size || ep->xferred_len >= ep->total_len ) { + hcd_event_xfer_complete(_hcd_data.peraddr, TUSB_DIR_IN_MASK | ep_num, ep->xferred_len, xfer_result, true); + }else { + // more to transfer + } + } +} + // Interrupt Handler void hcd_int_handler(uint8_t rhport) { + // not initialized, do nothing + if ( !_hcd_data.inited ) return; + uint8_t hirq = reg_read(HIRQ_ADDR); TU_LOG3_HEX(hirq); + if (hirq & HIRQ_FRAME_IRQ) { + _hcd_data.frame_count++; + } + if (hirq & HIRQ_CONDET_IRQ) { tusb_speed_t speed = handle_connect_irq(rhport); @@ -452,49 +594,17 @@ void hcd_int_handler(uint8_t rhport) { } } - if (hirq & HIRQ_FRAME_IRQ) { - _hcd_data.frame_count++; - } - if (hirq & HIRQ_HXFRDN_IRQ) { - uint8_t const hrsl = reg_read(HRSL_ADDR); - uint8_t const result = hrsl & HRSL_RESULT_MASK; - uint8_t xfer_result; - - TU_LOG3("HRSL: %02X\r\n", hrsl); - switch(result) { - case HRSL_SUCCESS: - xfer_result = XFER_RESULT_SUCCESS; - break; - - case HRSL_STALL: - xfer_result = XFER_RESULT_STALLED; - break; - - default: - xfer_result = XFER_RESULT_FAILED; - break; - } - - uint8_t ep_dir = 0; - uint8_t ep_num = _hcd_data.hxfr & HXFR_EPNUM_MASK; - uint8_t const xfer_type = _hcd_data.hxfr & 0xf0; - - if ( xfer_type & HXFR_SETUP ) { - // SETUP transfer - ep_dir = 0; - }else if ( !(xfer_type & HXFR_OUT_NIN) ) { - // IN transfer - ep_dir = 1; - } - - uint8_t const ep_addr = tu_edpt_addr(ep_num, ep_dir); - uint16_t xferred_len = _hcd_data.ep[ep_num][ep_dir].total_len; + handle_xfer_done(rhport); + } - hcd_event_xfer_complete(_hcd_data.peraddr, ep_addr, xferred_len, xfer_result, true); + if ( hirq & HIRQ_RCVDAV_IRQ ) { + TU_LOG3("RCVDAV\r\n"); + TU_LOG3_INT(reg_read(RCVBC_ADDR)); } - // clear all interrupt + // clear all interrupt execept SNDBAV_IRQ + hirq &= ~HIRQ_SNDBAV_IRQ; if ( hirq ) { reg_write(HIRQ_ADDR, hirq); } From 2c237b1ae4b3ffd38fc74df29da63b01348afd1d Mon Sep 17 00:00:00 2001 From: hathach Date: Wed, 23 Aug 2023 17:49:28 +0700 Subject: [PATCH 07/34] able to complete 1st get device descriptor and set address --- src/portable/analog/max3421/hcd_max3421.c | 180 +++++++++++++++------- 1 file changed, 126 insertions(+), 54 deletions(-) diff --git a/src/portable/analog/max3421/hcd_max3421.c b/src/portable/analog/max3421/hcd_max3421.c index edcb6ca6f7..467d7410ab 100644 --- a/src/portable/analog/max3421/hcd_max3421.c +++ b/src/portable/analog/max3421/hcd_max3421.c @@ -156,7 +156,7 @@ enum { }; enum { - DEFAULT_HIEN = HIRQ_CONDET_IRQ | HIRQ_FRAME_IRQ | HIRQ_HXFRDN_IRQ + DEFAULT_HIEN = HIRQ_CONDET_IRQ | HIRQ_FRAME_IRQ | HIRQ_HXFRDN_IRQ | HIRQ_RCVDAV_IRQ }; //--------------------------------------------------------------------+ @@ -178,6 +178,8 @@ typedef struct { // cached register uint8_t sndbc; + uint8_t hirq; + uint8_t hien; uint8_t mode; uint8_t peraddr; uint8_t hxfr; @@ -203,60 +205,86 @@ bool tuh_max3421_spi_xfer_api(uint8_t rhport, uint8_t const * tx_buf, size_t tx_ //--------------------------------------------------------------------+ static void fifo_write(uint8_t reg, uint8_t const * buffer, uint16_t len) { + uint8_t const rhport = 0; + uint8_t hirq; reg |= CMDBYTE_WRITE; - tuh_max3421_spi_cs_api(0, true); + tuh_max3421_spi_cs_api(rhport, true); - tuh_max3421_spi_xfer_api(0, ®, 1, NULL, 0); - tuh_max3421_spi_xfer_api(0, buffer, len, NULL, 0); + tuh_max3421_spi_xfer_api(rhport, ®, 1, &hirq, 1); + _hcd_data.hirq = hirq; + tuh_max3421_spi_xfer_api(rhport, buffer, len, NULL, 0); + + tuh_max3421_spi_cs_api(rhport, false); - tuh_max3421_spi_cs_api(0, false); } -// return HIRQ register since we are in full-duplex mode -static uint8_t reg_write(uint8_t reg, uint8_t data) { +static void fifo_read(uint8_t * buffer, uint16_t len) { + uint8_t const rhport = 0; + uint8_t hirq; + uint8_t const reg = RCVVFIFO_ADDR; + + tuh_max3421_spi_cs_api(rhport, true); + + tuh_max3421_spi_xfer_api(rhport, ®, 1, &hirq, 0); + _hcd_data.hirq = hirq; + tuh_max3421_spi_xfer_api(rhport, NULL, 0, buffer, len); + + tuh_max3421_spi_cs_api(rhport, false); +} + +static void reg_write(uint8_t reg, uint8_t data) { + uint8_t const rhport = 0; uint8_t tx_buf[2] = {reg | CMDBYTE_WRITE, data}; uint8_t rx_buf[2] = {0, 0}; - tuh_max3421_spi_cs_api(0, true); - tuh_max3421_spi_xfer_api(0, tx_buf, 2, rx_buf, 2); - tuh_max3421_spi_cs_api(0, false); + tuh_max3421_spi_cs_api(rhport, true); + tuh_max3421_spi_xfer_api(rhport, tx_buf, 2, rx_buf, 2); + tuh_max3421_spi_cs_api(rhport, false); - TU_LOG2("HIRQ: %02X\r\n", rx_buf[0]); - return rx_buf[0]; + // HIRQ register since we are in full-duplex mode + _hcd_data.hirq = rx_buf[0]; + TU_LOG3_HEX(_hcd_data.hirq); } static uint8_t reg_read(uint8_t reg) { + uint8_t const rhport = 0; uint8_t tx_buf[2] = {reg, 0}; uint8_t rx_buf[2] = {0, 0}; - tuh_max3421_spi_cs_api(0, true); - bool ret = tuh_max3421_spi_xfer_api(0, tx_buf, 2, rx_buf, 2); - tuh_max3421_spi_cs_api(0, false); + tuh_max3421_spi_cs_api(rhport, true); + bool ret = tuh_max3421_spi_xfer_api(rhport, tx_buf, 2, rx_buf, 2); + tuh_max3421_spi_cs_api(rhport, false); + _hcd_data.hirq = rx_buf[0]; return ret ? rx_buf[1] : 0; } -static inline uint8_t mode_write(uint8_t data) { +static inline void hien_write(uint8_t data) { + _hcd_data.hien = data; + reg_write(HIEN_ADDR, data); +} + +static inline void mode_write(uint8_t data) { _hcd_data.mode = data; - return reg_write(MODE_ADDR, data); + reg_write(MODE_ADDR, data); } -static inline uint8_t peraddr_write(uint8_t data) { - if ( _hcd_data.peraddr == data ) return 0; // no need to change address +static inline void peraddr_write(uint8_t data) { + if ( _hcd_data.peraddr == data ) return; // no need to change address _hcd_data.peraddr = data; - return reg_write(PERADDR_ADDR, data); + reg_write(PERADDR_ADDR, data); } -static inline uint8_t hxfr_write(uint8_t data) { +static inline void hxfr_write(uint8_t data) { _hcd_data.hxfr = data; - return reg_write(HXFR_ADDR, data); + reg_write(HXFR_ADDR, data); } -static inline uint8_t sndbc_write(uint8_t data) { +static inline void sndbc_write(uint8_t data) { _hcd_data.sndbc = data; - return reg_write(SNDBC_ADDR, data); + reg_write(SNDBC_ADDR, data); } @@ -335,16 +363,16 @@ bool hcd_init(uint8_t rhport) { // Mode: Host and DP/DM pull down mode_write(MODE_DPPULLDN | MODE_DMPULLDN | MODE_HOST); - // bus reset, this will trigger CONDET IRQ if device is already connected - reg_write(HCTL_ADDR, HCTL_BUSRST); + // frame reset & bus reset, this will trigger CONDET IRQ if device is already connected + reg_write(HCTL_ADDR, HCTL_BUSRST | HCTL_FRMRST); // clear all previously pending IRQ reg_write(HIRQ_ADDR, 0xff); _hcd_data.inited = true; - // Enable Connection IRQ - reg_write(HIEN_ADDR, DEFAULT_HIEN); + // Enable IRQ + hien_write(DEFAULT_HIEN); // Enable Interrupt pin reg_write(CPUCTL_ADDR, CPUCTL_IE); @@ -383,8 +411,8 @@ bool hcd_port_connect_status(uint8_t rhport) { void hcd_port_reset(uint8_t rhport) { (void) rhport; // Bus reset will also trigger CONDET IRQ, disable it - uint8_t hien = DEFAULT_HIEN & ~HIRQ_CONDET_IRQ; - reg_write(HIEN_ADDR, hien); + uint8_t const hien = DEFAULT_HIEN & ~HIRQ_CONDET_IRQ; + hien_write(hien); reg_write(HCTL_ADDR, HCTL_BUSRST); } @@ -396,7 +424,7 @@ void hcd_port_reset_end(uint8_t rhport) { // Bus reset will also trigger CONDET IRQ, clear and re-enable it after reset reg_write(HIRQ_ADDR, HIRQ_CONDET_IRQ); - reg_write(HIEN_ADDR, DEFAULT_HIEN); + hien_write(DEFAULT_HIEN); } // Get port link speed @@ -426,6 +454,10 @@ bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const _hcd_data.ep[ep_num][ep_dir].packet_size = tu_edpt_packet_size(ep_desc); + if (ep_desc->bEndpointAddress == 0) { + _hcd_data.ep[ep_num][1].packet_size = tu_edpt_packet_size(ep_desc); + } + return true; } @@ -442,15 +474,18 @@ bool hcd_edpt_xfer(uint8_t rhport, uint8_t daddr, uint8_t ep_addr, uint8_t * buf ep->total_len = buflen; ep->xferred_len = 0; - uint8_t hirq = peraddr_write(daddr); + peraddr_write(daddr); uint8_t hctl = 0; uint8_t hxfr = ep_num; if ( ep_num == 0 ) { ep->data_toggle = 1; if ( buffer == NULL || buflen == 0 ) { - // ZLP for ACK stage + // ZLP for ACK stage, use HS hxfr |= HXFR_HS; + hxfr |= (ep_dir ? 0 : HXFR_OUT_NIN); + hxfr_write(hxfr); + return true; } } else if ( ep->xfer_type == TUSB_XFER_ISOCHRONOUS ) { hxfr |= HXFR_ISO; @@ -458,7 +493,7 @@ bool hcd_edpt_xfer(uint8_t rhport, uint8_t daddr, uint8_t ep_addr, uint8_t * buf if ( 0 == ep_dir ) { // Page 12: Programming BULK-OUT Transfers - TU_ASSERT(hirq & HIRQ_RCVDAV_IRQ); + TU_ASSERT(_hcd_data.hirq & HIRQ_SNDBAV_IRQ); uint8_t const xact_len = (uint8_t) tu_min16(buflen, ep->packet_size); fifo_write(SNDFIFO_ADDR, buffer, xact_len); @@ -516,7 +551,7 @@ static void handle_xfer_done(uint8_t rhport) { uint8_t const hrsl = reg_read(HRSL_ADDR); uint8_t const result = hrsl & HRSL_RESULT_MASK; - uint8_t xfer_result; + xfer_result_t xfer_result; TU_LOG3("HRSL: %02X\r\n", hrsl); switch(result) { @@ -537,18 +572,21 @@ static void handle_xfer_done(uint8_t rhport) { break; } - uint8_t ep_dir = 0; uint8_t ep_num = _hcd_data.hxfr & HXFR_EPNUM_MASK; uint8_t const xfer_type = _hcd_data.hxfr & 0xf0; - hcd_ep_t * ep; - if ( (xfer_type & HXFR_SETUP) || (xfer_type & HXFR_OUT_NIN) ) { // SETUP or OUT transfer - ep_dir = 0; - ep = &_hcd_data.ep[ep_num][ep_dir]; + hcd_ep_t *ep = &_hcd_data.ep[ep_num][0]; + uint8_t xact_len; + if (xfer_type & HXFR_SETUP) { + xact_len = 8; + } else if ( xfer_type & HXFR_HS ) { + xact_len = 0; + } else { + xact_len = _hcd_data.sndbc; + } - uint8_t const xact_len = (xfer_type & HXFR_SETUP) ? 8 : _hcd_data.sndbc; ep->xferred_len += xact_len; if ( xact_len < ep->packet_size || ep->xferred_len >= ep->total_len ) { @@ -558,10 +596,27 @@ static void handle_xfer_done(uint8_t rhport) { } } else { // IN transfer - ep_dir = 1; - ep = &_hcd_data.ep[ep_num][ep_dir]; - uint8_t const xact_len = reg_read(RCVBC_ADDR); - ep->xferred_len += xact_len; + hcd_ep_t *ep = &_hcd_data.ep[ep_num][1]; + uint8_t xact_len; + + if ( xfer_type & HXFR_HS ) { + xact_len = 0; + } else { + // RCVDAV_IRQ can trigger 2 times (dual buffered) + while ( _hcd_data.hirq & HIRQ_RCVDAV_IRQ ) { + uint8_t rcvbc = reg_read(RCVBC_ADDR); + xact_len = (uint8_t) tu_min16(rcvbc, ep->total_len - ep->xferred_len); + if ( xact_len ) { + fifo_read(ep->buf, xact_len); + ep->buf += xact_len; + ep->xferred_len += xact_len; + } + + // ack RCVDVAV IRQ + reg_write(HIRQ_ADDR, HIRQ_RCVDAV_IRQ); + _hcd_data.hirq = reg_read(HIRQ_ADDR); + } + } // short packet or all bytes transferred if ( xact_len < ep->packet_size || ep->xferred_len >= ep->total_len ) { @@ -572,13 +627,35 @@ static void handle_xfer_done(uint8_t rhport) { } } +#if CFG_TUSB_DEBUG >= 3 +void print_hirq(uint8_t hirq) { + TU_LOG3_HEX(hirq); + + if (hirq & HIRQ_HXFRDN_IRQ) TU_LOG3(" HXFRDN"); + if (hirq & HIRQ_FRAME_IRQ) TU_LOG3(" FRAME"); + if (hirq & HIRQ_CONDET_IRQ) TU_LOG3(" CONDET"); + if (hirq & HIRQ_SUSDN_IRQ) TU_LOG3(" SUSDN"); + if (hirq & HIRQ_SNDBAV_IRQ) TU_LOG3(" SNDBAV"); + if (hirq & HIRQ_RCVDAV_IRQ) TU_LOG3(" RCVDAV"); + if (hirq & HIRQ_RWU_IRQ) TU_LOG3(" RWU"); + if (hirq & HIRQ_BUSEVENT_IRQ) TU_LOG3(" BUSEVENT"); + + TU_LOG3("\r\n"); +} + +#else + #define print_hirq(hirq) +#endif + // Interrupt Handler void hcd_int_handler(uint8_t rhport) { // not initialized, do nothing if ( !_hcd_data.inited ) return; - uint8_t hirq = reg_read(HIRQ_ADDR); - TU_LOG3_HEX(hirq); + uint8_t hirq = reg_read(HIRQ_ADDR) & _hcd_data.hien; + if (!hirq) return; + + print_hirq(hirq); if (hirq & HIRQ_FRAME_IRQ) { _hcd_data.frame_count++; @@ -598,13 +675,8 @@ void hcd_int_handler(uint8_t rhport) { handle_xfer_done(rhport); } - if ( hirq & HIRQ_RCVDAV_IRQ ) { - TU_LOG3("RCVDAV\r\n"); - TU_LOG3_INT(reg_read(RCVBC_ADDR)); - } - - // clear all interrupt execept SNDBAV_IRQ - hirq &= ~HIRQ_SNDBAV_IRQ; + // clear all interrupt except SNDBAV_IRQ and RCVDAV_IRQ must be clear after pulling data from FIFO + hirq &= ~ (HIRQ_SNDBAV_IRQ | HIRQ_RCVDAV_IRQ); if ( hirq ) { reg_write(HIRQ_ADDR, hirq); } From 3ed5d6c3724cfa9699d403a76a00f1b04672e2b5 Mon Sep 17 00:00:00 2001 From: hathach Date: Thu, 24 Aug 2023 16:27:12 +0700 Subject: [PATCH 08/34] complete enumeration --- hw/bsp/nrf/family.c | 5 +- src/portable/analog/max3421/hcd_max3421.c | 68 ++++++++++++++--------- 2 files changed, 47 insertions(+), 26 deletions(-) diff --git a/hw/bsp/nrf/family.c b/hw/bsp/nrf/family.c index 45a5166a75..368763b841 100644 --- a/hw/bsp/nrf/family.c +++ b/hw/bsp/nrf/family.c @@ -105,6 +105,10 @@ void max3421e_int_handler(nrfx_gpiote_pin_t pin, nrf_gpiote_polarity_t action) { //--------------------------------------------------------------------+ // API: SPI transfer with MAX3421E, must be implemented by application //--------------------------------------------------------------------+ +void tuh_max3421e_int_api(uint8_t rhport, bool enabled) { + (void) rhport; + nrfx_gpiote_trigger_enable(MAX3241E_INTR_PIN, enabled); +} void tuh_max3421_spi_cs_api(uint8_t rhport, bool active) { (void) rhport; @@ -241,7 +245,6 @@ void board_init(void) { in_config.pull = NRF_GPIO_PIN_PULLUP; nrfx_gpiote_in_init(MAX3241E_INTR_PIN, &in_config, max3421e_int_handler); - nrfx_gpiote_in_event_enable(MAX3241E_INTR_PIN, true); #endif } diff --git a/src/portable/analog/max3421/hcd_max3421.c b/src/portable/analog/max3421/hcd_max3421.c index 467d7410ab..514cf34b79 100644 --- a/src/portable/analog/max3421/hcd_max3421.c +++ b/src/portable/analog/max3421/hcd_max3421.c @@ -166,6 +166,7 @@ enum { typedef struct { uint8_t xfer_type; uint8_t data_toggle; + uint8_t xfer_complete; uint16_t packet_size; uint16_t total_len; @@ -244,7 +245,6 @@ static void reg_write(uint8_t reg, uint8_t data) { // HIRQ register since we are in full-duplex mode _hcd_data.hirq = rx_buf[0]; - TU_LOG3_HEX(_hcd_data.hirq); } static uint8_t reg_read(uint8_t reg) { @@ -473,6 +473,7 @@ bool hcd_edpt_xfer(uint8_t rhport, uint8_t daddr, uint8_t ep_addr, uint8_t * buf ep->buf = buffer; ep->total_len = buflen; ep->xferred_len = 0; + ep->xfer_complete = 0; peraddr_write(daddr); @@ -595,34 +596,19 @@ static void handle_xfer_done(uint8_t rhport) { // more to transfer } } else { - // IN transfer + // IN transfer: fifo data is already received in RCVDAV IRQ hcd_ep_t *ep = &_hcd_data.ep[ep_num][1]; - uint8_t xact_len; if ( xfer_type & HXFR_HS ) { - xact_len = 0; - } else { - // RCVDAV_IRQ can trigger 2 times (dual buffered) - while ( _hcd_data.hirq & HIRQ_RCVDAV_IRQ ) { - uint8_t rcvbc = reg_read(RCVBC_ADDR); - xact_len = (uint8_t) tu_min16(rcvbc, ep->total_len - ep->xferred_len); - if ( xact_len ) { - fifo_read(ep->buf, xact_len); - ep->buf += xact_len; - ep->xferred_len += xact_len; - } - - // ack RCVDVAV IRQ - reg_write(HIRQ_ADDR, HIRQ_RCVDAV_IRQ); - _hcd_data.hirq = reg_read(HIRQ_ADDR); - } + ep->xfer_complete = 1; } // short packet or all bytes transferred - if ( xact_len < ep->packet_size || ep->xferred_len >= ep->total_len ) { + if ( ep->xfer_complete ) { hcd_event_xfer_complete(_hcd_data.peraddr, TUSB_DIR_IN_MASK | ep_num, ep->xferred_len, xfer_result, true); }else { // more to transfer + hxfr_write(_hcd_data.hxfr); } } } @@ -655,7 +641,7 @@ void hcd_int_handler(uint8_t rhport) { uint8_t hirq = reg_read(HIRQ_ADDR) & _hcd_data.hien; if (!hirq) return; - print_hirq(hirq); +// print_hirq(hirq); if (hirq & HIRQ_FRAME_IRQ) { _hcd_data.frame_count++; @@ -671,12 +657,44 @@ void hcd_int_handler(uint8_t rhport) { } } - if (hirq & HIRQ_HXFRDN_IRQ) { - handle_xfer_done(rhport); + // queue more transfer in handle_xfer_done() can cause hirq to be set again while external IRQ may not catch and/or + // not call this handler again. So we need to loop until all IRQ are cleared + while ( hirq & (HIRQ_RCVDAV_IRQ | HIRQ_HXFRDN_IRQ) ) { + if ( hirq & HIRQ_RCVDAV_IRQ ) { + uint8_t ep_num = _hcd_data.hxfr & HXFR_EPNUM_MASK; + hcd_ep_t *ep = &_hcd_data.ep[ep_num][1]; + uint8_t xact_len; + + // RCVDAV_IRQ can trigger 2 times (dual buffered) + while ( hirq & HIRQ_RCVDAV_IRQ ) { + uint8_t rcvbc = reg_read(RCVBC_ADDR); + xact_len = (uint8_t) tu_min16(rcvbc, ep->total_len - ep->xferred_len); + if ( xact_len ) { + fifo_read(ep->buf, xact_len); + ep->buf += xact_len; + ep->xferred_len += xact_len; + } + + // ack RCVDVAV IRQ + reg_write(HIRQ_ADDR, HIRQ_RCVDAV_IRQ); + hirq = reg_read(HIRQ_ADDR); + } + + if ( xact_len < ep->packet_size || ep->xferred_len >= ep->total_len ) { + ep->xfer_complete = 1; + } + } + + if ( hirq & HIRQ_HXFRDN_IRQ ) { + reg_write(HIRQ_ADDR, HIRQ_HXFRDN_IRQ); + handle_xfer_done(rhport); + } + + hirq = reg_read(HIRQ_ADDR); } - // clear all interrupt except SNDBAV_IRQ and RCVDAV_IRQ must be clear after pulling data from FIFO - hirq &= ~ (HIRQ_SNDBAV_IRQ | HIRQ_RCVDAV_IRQ); + // clear all interrupt except SNDBAV_IRQ (never clear by us). Note RCVDAV_IRQ, HXFRDN_IRQ already clear while processing + hirq &= ~HIRQ_SNDBAV_IRQ; if ( hirq ) { reg_write(HIRQ_ADDR, hirq); } From 344932d27e1f65932ce922b639370ecc4fff2153 Mon Sep 17 00:00:00 2001 From: hathach Date: Thu, 24 Aug 2023 16:27:32 +0700 Subject: [PATCH 09/34] add tuh_max3421e_int_api(), retry control if received NAK --- src/portable/analog/max3421/hcd_max3421.c | 60 +++++++++++++++-------- 1 file changed, 40 insertions(+), 20 deletions(-) diff --git a/src/portable/analog/max3421/hcd_max3421.c b/src/portable/analog/max3421/hcd_max3421.c index 514cf34b79..b4f75e3923 100644 --- a/src/portable/analog/max3421/hcd_max3421.c +++ b/src/portable/analog/max3421/hcd_max3421.c @@ -28,6 +28,7 @@ #if CFG_TUH_ENABLED && defined(CFG_TUH_MAX3421) && CFG_TUH_MAX3421 +#include #include "host/hcd.h" //--------------------------------------------------------------------+ @@ -164,11 +165,15 @@ enum { //--------------------------------------------------------------------+ typedef struct { - uint8_t xfer_type; - uint8_t data_toggle; - uint8_t xfer_complete; uint16_t packet_size; + struct TU_ATTR_PACKED { + uint8_t is_iso : 1; + uint8_t data_toggle : 1; + uint8_t xfer_queued : 1; + uint8_t xfer_complete : 1; + }; + uint16_t total_len; uint16_t xferred_len; uint8_t* buf; @@ -176,6 +181,7 @@ typedef struct { typedef struct { bool inited; + atomic_bool busy; // busy transferring // cached register uint8_t sndbc; @@ -198,8 +204,7 @@ static max2341_data_t _hcd_data; void tuh_max3421_spi_cs_api(uint8_t rhport, bool active); bool tuh_max3421_spi_xfer_api(uint8_t rhport, uint8_t const * tx_buf, size_t tx_len, uint8_t * rx_buf, size_t rx_len); - -//void tuh_max3421e_int_enable(uint8_t rhport, bool enabled); +void tuh_max3421e_int_api(uint8_t rhport, bool enabled); //--------------------------------------------------------------------+ // @@ -348,6 +353,9 @@ tusb_speed_t handle_connect_irq(uint8_t rhport) { bool hcd_init(uint8_t rhport) { (void) rhport; + TU_LOG2_INT(sizeof(hcd_ep_t)); + TU_LOG2_INT(sizeof(max2341_data_t)); + tu_memclr(&_hcd_data, sizeof(_hcd_data)); // full duplex, interrupt negative edge @@ -382,12 +390,12 @@ bool hcd_init(uint8_t rhport) { // Enable USB interrupt void hcd_int_enable (uint8_t rhport) { - (void) rhport; + tuh_max3421e_int_api(rhport, true); } // Disable USB interrupt void hcd_int_disable(uint8_t rhport) { - (void) rhport; + tuh_max3421e_int_api(rhport, false); } // Get frame number (1ms) @@ -447,17 +455,20 @@ void hcd_device_close(uint8_t rhport, uint8_t dev_addr) { bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const * ep_desc) { (void) rhport; (void) dev_addr; - (void) ep_desc; uint8_t ep_num = tu_edpt_number(ep_desc->bEndpointAddress); uint8_t ep_dir = tu_edpt_dir(ep_desc->bEndpointAddress); - _hcd_data.ep[ep_num][ep_dir].packet_size = tu_edpt_packet_size(ep_desc); + hcd_ep_t * ep = &_hcd_data.ep[ep_num][ep_dir]; + + ep->packet_size = tu_edpt_packet_size(ep_desc); if (ep_desc->bEndpointAddress == 0) { - _hcd_data.ep[ep_num][1].packet_size = tu_edpt_packet_size(ep_desc); + _hcd_data.ep[0][1].packet_size = ep->packet_size; } + ep->is_iso = (TUSB_XFER_ISOCHRONOUS == ep_desc->bmAttributes.xfer) ? 1 : 0; + return true; } @@ -474,11 +485,13 @@ bool hcd_edpt_xfer(uint8_t rhport, uint8_t daddr, uint8_t ep_addr, uint8_t * buf ep->total_len = buflen; ep->xferred_len = 0; ep->xfer_complete = 0; + ep->xfer_queued = 1; peraddr_write(daddr); uint8_t hctl = 0; uint8_t hxfr = ep_num; + if ( ep_num == 0 ) { ep->data_toggle = 1; if ( buffer == NULL || buflen == 0 ) { @@ -488,7 +501,7 @@ bool hcd_edpt_xfer(uint8_t rhport, uint8_t daddr, uint8_t ep_addr, uint8_t * buf hxfr_write(hxfr); return true; } - } else if ( ep->xfer_type == TUSB_XFER_ISOCHRONOUS ) { + } else if ( ep->is_iso ) { hxfr |= HXFR_ISO; } @@ -551,11 +564,13 @@ static void handle_xfer_done(uint8_t rhport) { (void) rhport; uint8_t const hrsl = reg_read(HRSL_ADDR); - uint8_t const result = hrsl & HRSL_RESULT_MASK; + uint8_t const hresult = hrsl & HRSL_RESULT_MASK; + uint8_t ep_num = _hcd_data.hxfr & HXFR_EPNUM_MASK; + xfer_result_t xfer_result; - TU_LOG3("HRSL: %02X\r\n", hrsl); - switch(result) { + //TU_LOG3("HRSL: %02X\r\n", hrsl); + switch(hresult) { case HRSL_SUCCESS: xfer_result = XFER_RESULT_SUCCESS; break; @@ -568,21 +583,26 @@ static void handle_xfer_done(uint8_t rhport) { // occurred when initialized without any pending transfer. Skip for now return; + case HRSL_NAK: + // NAK on control, retry immediately + if (ep_num == 0) hxfr_write(_hcd_data.hxfr); + return; + default: xfer_result = XFER_RESULT_FAILED; break; } - uint8_t ep_num = _hcd_data.hxfr & HXFR_EPNUM_MASK; - uint8_t const xfer_type = _hcd_data.hxfr & 0xf0; + uint8_t const hxfr_type = _hcd_data.hxfr & 0xf0; - if ( (xfer_type & HXFR_SETUP) || (xfer_type & HXFR_OUT_NIN) ) { + if ( (hxfr_type & HXFR_SETUP) || (hxfr_type & HXFR_OUT_NIN) ) { // SETUP or OUT transfer hcd_ep_t *ep = &_hcd_data.ep[ep_num][0]; uint8_t xact_len; - if (xfer_type & HXFR_SETUP) { + + if ( hxfr_type & HXFR_SETUP) { xact_len = 8; - } else if ( xfer_type & HXFR_HS ) { + } else if ( hxfr_type & HXFR_HS ) { xact_len = 0; } else { xact_len = _hcd_data.sndbc; @@ -599,7 +619,7 @@ static void handle_xfer_done(uint8_t rhport) { // IN transfer: fifo data is already received in RCVDAV IRQ hcd_ep_t *ep = &_hcd_data.ep[ep_num][1]; - if ( xfer_type & HXFR_HS ) { + if ( hxfr_type & HXFR_HS ) { ep->xfer_complete = 1; } From e6cf125e537125fc7303afc7d0703a3de6b8b334 Mon Sep 17 00:00:00 2001 From: hathach Date: Thu, 24 Aug 2023 16:46:20 +0700 Subject: [PATCH 10/34] save data toggle, always retry NAK. work with msc device --- src/portable/analog/max3421/hcd_max3421.c | 24 ++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/src/portable/analog/max3421/hcd_max3421.c b/src/portable/analog/max3421/hcd_max3421.c index b4f75e3923..9579409c5d 100644 --- a/src/portable/analog/max3421/hcd_max3421.c +++ b/src/portable/analog/max3421/hcd_max3421.c @@ -492,7 +492,9 @@ bool hcd_edpt_xfer(uint8_t rhport, uint8_t daddr, uint8_t ep_addr, uint8_t * buf uint8_t hctl = 0; uint8_t hxfr = ep_num; - if ( ep_num == 0 ) { + if ( ep->is_iso ) { + hxfr |= HXFR_ISO; + } else if ( ep_num == 0 ) { ep->data_toggle = 1; if ( buffer == NULL || buflen == 0 ) { // ZLP for ACK stage, use HS @@ -501,8 +503,6 @@ bool hcd_edpt_xfer(uint8_t rhport, uint8_t daddr, uint8_t ep_addr, uint8_t * buf hxfr_write(hxfr); return true; } - } else if ( ep->is_iso ) { - hxfr |= HXFR_ISO; } if ( 0 == ep_dir ) { @@ -511,7 +511,7 @@ bool hcd_edpt_xfer(uint8_t rhport, uint8_t daddr, uint8_t ep_addr, uint8_t * buf uint8_t const xact_len = (uint8_t) tu_min16(buflen, ep->packet_size); fifo_write(SNDFIFO_ADDR, buffer, xact_len); - reg_write(SNDBC_ADDR, xact_len); + sndbc_write(xact_len); hctl = (ep->data_toggle ? HCTL_SNDTOG1 : HCTL_SNDTOG0); hxfr |= HXFR_OUT_NIN; @@ -585,7 +585,10 @@ static void handle_xfer_done(uint8_t rhport) { case HRSL_NAK: // NAK on control, retry immediately - if (ep_num == 0) hxfr_write(_hcd_data.hxfr); + //if (ep_num == 0) + { + hxfr_write(_hcd_data.hxfr); + } return; default: @@ -609,8 +612,14 @@ static void handle_xfer_done(uint8_t rhport) { } ep->xferred_len += xact_len; + ep->buf += xact_len; if ( xact_len < ep->packet_size || ep->xferred_len >= ep->total_len ) { + if ( ep_num ) { + // save data toggle for non-control + ep->data_toggle = (hrsl & HRSL_SNDTOGRD) ? 1 : 0; + } + hcd_event_xfer_complete(_hcd_data.peraddr, ep_num, ep->xferred_len, xfer_result, true); }else { // more to transfer @@ -625,6 +634,11 @@ static void handle_xfer_done(uint8_t rhport) { // short packet or all bytes transferred if ( ep->xfer_complete ) { + if ( ep_num ) { + // save data toggle for non-control + ep->data_toggle = (hrsl & HRSL_RCVTOGRD) ? 1 : 0; + } + hcd_event_xfer_complete(_hcd_data.peraddr, TUSB_DIR_IN_MASK | ep_num, ep->xferred_len, xfer_result, true); }else { // more to transfer From f5ebc1700f4bde1cc166bf5f3d8eb69d8832722a Mon Sep 17 00:00:00 2001 From: hathach Date: Fri, 25 Aug 2023 12:12:44 +0700 Subject: [PATCH 11/34] add spi lock with interrupt enable/disable --- src/portable/analog/max3421/hcd_max3421.c | 176 +++++++++++----------- 1 file changed, 91 insertions(+), 85 deletions(-) diff --git a/src/portable/analog/max3421/hcd_max3421.c b/src/portable/analog/max3421/hcd_max3421.c index 9579409c5d..0144deca69 100644 --- a/src/portable/analog/max3421/hcd_max3421.c +++ b/src/portable/analog/max3421/hcd_max3421.c @@ -180,7 +180,6 @@ typedef struct { } hcd_ep_t; typedef struct { - bool inited; atomic_bool busy; // busy transferring // cached register @@ -194,6 +193,8 @@ typedef struct { volatile uint16_t frame_count; hcd_ep_t ep[8][2]; + + OSAL_MUTEX_DEF(spi_mutex); } max2341_data_t; static max2341_data_t _hcd_data; @@ -210,86 +211,106 @@ void tuh_max3421e_int_api(uint8_t rhport, bool enabled); // //--------------------------------------------------------------------+ -static void fifo_write(uint8_t reg, uint8_t const * buffer, uint16_t len) { - uint8_t const rhport = 0; +static void max3421_spi_lock(uint8_t rhport, bool in_isr) { + // disable interrupt and mutex lock (for pre-emptive RTOS) if not in_isr + if (!in_isr) { + tuh_max3421e_int_api(rhport, false); + } + + // assert CS + tuh_max3421_spi_cs_api(rhport, true); +} + +static void max3421_spi_unlock(uint8_t rhport, bool in_isr) { + // de-assert CS + tuh_max3421_spi_cs_api(rhport, false); + + // mutex unlock and re-enable interrupt + if (!in_isr) { + tuh_max3421e_int_api(rhport, true); + } +} + +static void fifo_write(uint8_t rhport, uint8_t reg, uint8_t const * buffer, uint16_t len, bool in_isr) { uint8_t hirq; reg |= CMDBYTE_WRITE; - tuh_max3421_spi_cs_api(rhport, true); + max3421_spi_lock(rhport, in_isr); tuh_max3421_spi_xfer_api(rhport, ®, 1, &hirq, 1); _hcd_data.hirq = hirq; tuh_max3421_spi_xfer_api(rhport, buffer, len, NULL, 0); - tuh_max3421_spi_cs_api(rhport, false); + max3421_spi_unlock(rhport, in_isr); } -static void fifo_read(uint8_t * buffer, uint16_t len) { - uint8_t const rhport = 0; +static void fifo_read(uint8_t rhport, uint8_t * buffer, uint16_t len, bool in_isr) { uint8_t hirq; uint8_t const reg = RCVVFIFO_ADDR; - tuh_max3421_spi_cs_api(rhport, true); + max3421_spi_lock(rhport, in_isr); tuh_max3421_spi_xfer_api(rhport, ®, 1, &hirq, 0); _hcd_data.hirq = hirq; tuh_max3421_spi_xfer_api(rhport, NULL, 0, buffer, len); - tuh_max3421_spi_cs_api(rhport, false); + max3421_spi_unlock(rhport, in_isr); } -static void reg_write(uint8_t reg, uint8_t data) { - uint8_t const rhport = 0; +static void reg_write(uint8_t rhport, uint8_t reg, uint8_t data, bool in_isr) { uint8_t tx_buf[2] = {reg | CMDBYTE_WRITE, data}; uint8_t rx_buf[2] = {0, 0}; - tuh_max3421_spi_cs_api(rhport, true); + max3421_spi_lock(rhport, in_isr); + tuh_max3421_spi_xfer_api(rhport, tx_buf, 2, rx_buf, 2); - tuh_max3421_spi_cs_api(rhport, false); + + max3421_spi_unlock(rhport, in_isr); // HIRQ register since we are in full-duplex mode _hcd_data.hirq = rx_buf[0]; } -static uint8_t reg_read(uint8_t reg) { - uint8_t const rhport = 0; +static uint8_t reg_read(uint8_t rhport, uint8_t reg, bool in_isr) { uint8_t tx_buf[2] = {reg, 0}; uint8_t rx_buf[2] = {0, 0}; - tuh_max3421_spi_cs_api(rhport, true); + max3421_spi_lock(rhport, in_isr); + bool ret = tuh_max3421_spi_xfer_api(rhport, tx_buf, 2, rx_buf, 2); - tuh_max3421_spi_cs_api(rhport, false); + + max3421_spi_unlock(rhport, in_isr); _hcd_data.hirq = rx_buf[0]; return ret ? rx_buf[1] : 0; } -static inline void hien_write(uint8_t data) { +static inline void hien_write(uint8_t rhport, uint8_t data, bool in_isr) { _hcd_data.hien = data; - reg_write(HIEN_ADDR, data); + reg_write(rhport, HIEN_ADDR, data, in_isr); } -static inline void mode_write(uint8_t data) { +static inline void mode_write(uint8_t rhport, uint8_t data, bool in_isr) { _hcd_data.mode = data; - reg_write(MODE_ADDR, data); + reg_write(rhport, MODE_ADDR, data, in_isr); } -static inline void peraddr_write(uint8_t data) { +static inline void peraddr_write(uint8_t rhport, uint8_t data, bool in_isr) { if ( _hcd_data.peraddr == data ) return; // no need to change address _hcd_data.peraddr = data; - reg_write(PERADDR_ADDR, data); + reg_write(rhport, PERADDR_ADDR, data, in_isr); } -static inline void hxfr_write(uint8_t data) { +static inline void hxfr_write(uint8_t rhport, uint8_t data, bool in_isr) { _hcd_data.hxfr = data; - reg_write(HXFR_ADDR, data); + reg_write(rhport, HXFR_ADDR, data, in_isr); } -static inline void sndbc_write(uint8_t data) { +static inline void sndbc_write(uint8_t rhport, uint8_t data, bool in_isr) { _hcd_data.sndbc = data; - reg_write(SNDBC_ADDR, data); + reg_write(rhport, SNDBC_ADDR, data, in_isr); } @@ -307,9 +328,7 @@ bool hcd_configure(uint8_t rhport, uint32_t cfg_id, const void* cfg_param) { } tusb_speed_t handle_connect_irq(uint8_t rhport) { - (void) rhport; - - uint8_t const hrsl = reg_read(HRSL_ADDR); + uint8_t const hrsl = reg_read(rhport, HRSL_ADDR, true); uint8_t const jk = hrsl & (HRSL_JSTATUS | HRSL_KSTATUS); tusb_speed_t speed; @@ -328,7 +347,7 @@ tusb_speed_t handle_connect_irq(uint8_t rhport) { default: { // Low speed if (LS = 1 and J-state) or (LS = 0 and K-State) - uint8_t const mode = reg_read(MODE_ADDR); + uint8_t const mode = reg_read(rhport, MODE_ADDR, true); uint8_t const ls_bit = mode & MODE_LOWSPEED; if ( (ls_bit && (jk == HRSL_JSTATUS)) || (!ls_bit && (jk == HRSL_KSTATUS)) ) { @@ -344,7 +363,7 @@ tusb_speed_t handle_connect_irq(uint8_t rhport) { } } - mode_write(new_mode); + mode_write(rhport, new_mode, true); TU_LOG2_INT(speed); return speed; } @@ -358,32 +377,32 @@ bool hcd_init(uint8_t rhport) { tu_memclr(&_hcd_data, sizeof(_hcd_data)); + hcd_int_disable(rhport); + // full duplex, interrupt negative edge - reg_write(PINCTL_ADDR, PINCTL_FDUPSPI); + reg_write(rhport, PINCTL_ADDR, PINCTL_FDUPSPI, false); // reset - reg_write(USBCTL_ADDR, USBCTL_CHIPRES); - reg_write(USBCTL_ADDR, 0); - while( !(reg_read(USBIRQ_ADDR) & USBIRQ_OSCOK_IRQ) ) { + reg_write(rhport, USBCTL_ADDR, USBCTL_CHIPRES, false); + reg_write(rhport, USBCTL_ADDR, 0, false); + while( !(reg_read(rhport, USBIRQ_ADDR, false) & USBIRQ_OSCOK_IRQ) ) { // wait for oscillator to stabilize } // Mode: Host and DP/DM pull down - mode_write(MODE_DPPULLDN | MODE_DMPULLDN | MODE_HOST); + mode_write(rhport, MODE_DPPULLDN | MODE_DMPULLDN | MODE_HOST, false); // frame reset & bus reset, this will trigger CONDET IRQ if device is already connected - reg_write(HCTL_ADDR, HCTL_BUSRST | HCTL_FRMRST); + reg_write(rhport, HCTL_ADDR, HCTL_BUSRST | HCTL_FRMRST, false); // clear all previously pending IRQ - reg_write(HIRQ_ADDR, 0xff); - - _hcd_data.inited = true; + reg_write(rhport, HIRQ_ADDR, 0xff, false); // Enable IRQ - hien_write(DEFAULT_HIEN); + hien_write(rhport, DEFAULT_HIEN, false); // Enable Interrupt pin - reg_write(CPUCTL_ADDR, CPUCTL_IE); + reg_write(rhport, CPUCTL_ADDR, CPUCTL_IE, false); return true; } @@ -417,22 +436,20 @@ bool hcd_port_connect_status(uint8_t rhport) { // Reset USB bus on the port. Return immediately, bus reset sequence may not be complete. // Some port would require hcd_port_reset_end() to be invoked after 10ms to complete the reset sequence. void hcd_port_reset(uint8_t rhport) { - (void) rhport; // Bus reset will also trigger CONDET IRQ, disable it uint8_t const hien = DEFAULT_HIEN & ~HIRQ_CONDET_IRQ; - hien_write(hien); + hien_write(rhport, hien, false); - reg_write(HCTL_ADDR, HCTL_BUSRST); + reg_write(rhport, HCTL_ADDR, HCTL_BUSRST, false); } // Complete bus reset sequence, may be required by some controllers void hcd_port_reset_end(uint8_t rhport) { - (void) rhport; - reg_write(HCTL_ADDR, 0); + reg_write(rhport, HCTL_ADDR, 0, false); // Bus reset will also trigger CONDET IRQ, clear and re-enable it after reset - reg_write(HIRQ_ADDR, HIRQ_CONDET_IRQ); - hien_write(DEFAULT_HIEN); + reg_write(rhport, HIRQ_ADDR, HIRQ_CONDET_IRQ, false); + hien_write(rhport, DEFAULT_HIEN, false); } // Get port link speed @@ -487,7 +504,7 @@ bool hcd_edpt_xfer(uint8_t rhport, uint8_t daddr, uint8_t ep_addr, uint8_t * buf ep->xfer_complete = 0; ep->xfer_queued = 1; - peraddr_write(daddr); + peraddr_write(rhport, daddr, false); uint8_t hctl = 0; uint8_t hxfr = ep_num; @@ -500,7 +517,7 @@ bool hcd_edpt_xfer(uint8_t rhport, uint8_t daddr, uint8_t ep_addr, uint8_t * buf // ZLP for ACK stage, use HS hxfr |= HXFR_HS; hxfr |= (ep_dir ? 0 : HXFR_OUT_NIN); - hxfr_write(hxfr); + hxfr_write(rhport, hxfr, false); return true; } } @@ -510,8 +527,8 @@ bool hcd_edpt_xfer(uint8_t rhport, uint8_t daddr, uint8_t ep_addr, uint8_t * buf TU_ASSERT(_hcd_data.hirq & HIRQ_SNDBAV_IRQ); uint8_t const xact_len = (uint8_t) tu_min16(buflen, ep->packet_size); - fifo_write(SNDFIFO_ADDR, buffer, xact_len); - sndbc_write(xact_len); + fifo_write(rhport, SNDFIFO_ADDR, buffer, xact_len, false); + sndbc_write(rhport, xact_len, false); hctl = (ep->data_toggle ? HCTL_SNDTOG1 : HCTL_SNDTOG0); hxfr |= HXFR_OUT_NIN; @@ -520,8 +537,8 @@ bool hcd_edpt_xfer(uint8_t rhport, uint8_t daddr, uint8_t ep_addr, uint8_t * buf hctl = (ep->data_toggle ? HCTL_RCVTOG1 : HCTL_RCVTOG0); } - reg_write(HCTL_ADDR, hctl); - hxfr_write(hxfr); + reg_write(rhport, HCTL_ADDR, hctl, false); + hxfr_write(rhport, hxfr, false); return true; } @@ -544,9 +561,9 @@ bool hcd_setup_send(uint8_t rhport, uint8_t daddr, uint8_t const setup_packet[8] ep->total_len = 8; ep->xferred_len = 0; - peraddr_write(daddr); - fifo_write(SUDFIFO_ADDR, setup_packet, 8); - hxfr_write(HXFR_SETUP); + peraddr_write(rhport, daddr, false); + fifo_write(rhport, SUDFIFO_ADDR, setup_packet, 8, false); + hxfr_write(rhport, HXFR_SETUP, false); return true; } @@ -561,9 +578,7 @@ bool hcd_edpt_clear_stall(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr) { } static void handle_xfer_done(uint8_t rhport) { - (void) rhport; - - uint8_t const hrsl = reg_read(HRSL_ADDR); + uint8_t const hrsl = reg_read(rhport, HRSL_ADDR, true); uint8_t const hresult = hrsl & HRSL_RESULT_MASK; uint8_t ep_num = _hcd_data.hxfr & HXFR_EPNUM_MASK; @@ -587,7 +602,7 @@ static void handle_xfer_done(uint8_t rhport) { // NAK on control, retry immediately //if (ep_num == 0) { - hxfr_write(_hcd_data.hxfr); + hxfr_write(rhport, _hcd_data.hxfr, true); } return; @@ -615,11 +630,8 @@ static void handle_xfer_done(uint8_t rhport) { ep->buf += xact_len; if ( xact_len < ep->packet_size || ep->xferred_len >= ep->total_len ) { - if ( ep_num ) { - // save data toggle for non-control - ep->data_toggle = (hrsl & HRSL_SNDTOGRD) ? 1 : 0; - } - + // save data toggle + ep->data_toggle = (hrsl & HRSL_SNDTOGRD) ? 1 : 0; hcd_event_xfer_complete(_hcd_data.peraddr, ep_num, ep->xferred_len, xfer_result, true); }else { // more to transfer @@ -634,15 +646,12 @@ static void handle_xfer_done(uint8_t rhport) { // short packet or all bytes transferred if ( ep->xfer_complete ) { - if ( ep_num ) { - // save data toggle for non-control - ep->data_toggle = (hrsl & HRSL_RCVTOGRD) ? 1 : 0; - } - + // save data toggle + ep->data_toggle = (hrsl & HRSL_RCVTOGRD) ? 1 : 0; hcd_event_xfer_complete(_hcd_data.peraddr, TUSB_DIR_IN_MASK | ep_num, ep->xferred_len, xfer_result, true); }else { // more to transfer - hxfr_write(_hcd_data.hxfr); + hxfr_write(rhport, _hcd_data.hxfr, true); } } } @@ -669,10 +678,7 @@ void print_hirq(uint8_t hirq) { // Interrupt Handler void hcd_int_handler(uint8_t rhport) { - // not initialized, do nothing - if ( !_hcd_data.inited ) return; - - uint8_t hirq = reg_read(HIRQ_ADDR) & _hcd_data.hien; + uint8_t hirq = reg_read(rhport, HIRQ_ADDR, true) & _hcd_data.hien; if (!hirq) return; // print_hirq(hirq); @@ -701,17 +707,17 @@ void hcd_int_handler(uint8_t rhport) { // RCVDAV_IRQ can trigger 2 times (dual buffered) while ( hirq & HIRQ_RCVDAV_IRQ ) { - uint8_t rcvbc = reg_read(RCVBC_ADDR); + uint8_t rcvbc = reg_read(rhport, RCVBC_ADDR, true); xact_len = (uint8_t) tu_min16(rcvbc, ep->total_len - ep->xferred_len); if ( xact_len ) { - fifo_read(ep->buf, xact_len); + fifo_read(rhport, ep->buf, xact_len, true); ep->buf += xact_len; ep->xferred_len += xact_len; } // ack RCVDVAV IRQ - reg_write(HIRQ_ADDR, HIRQ_RCVDAV_IRQ); - hirq = reg_read(HIRQ_ADDR); + reg_write(rhport, HIRQ_ADDR, HIRQ_RCVDAV_IRQ, true); + hirq = reg_read(rhport, HIRQ_ADDR, true); } if ( xact_len < ep->packet_size || ep->xferred_len >= ep->total_len ) { @@ -720,17 +726,17 @@ void hcd_int_handler(uint8_t rhport) { } if ( hirq & HIRQ_HXFRDN_IRQ ) { - reg_write(HIRQ_ADDR, HIRQ_HXFRDN_IRQ); + reg_write(rhport, HIRQ_ADDR, HIRQ_HXFRDN_IRQ, true); handle_xfer_done(rhport); } - hirq = reg_read(HIRQ_ADDR); + hirq = reg_read(rhport, HIRQ_ADDR, true); } // clear all interrupt except SNDBAV_IRQ (never clear by us). Note RCVDAV_IRQ, HXFRDN_IRQ already clear while processing hirq &= ~HIRQ_SNDBAV_IRQ; if ( hirq ) { - reg_write(HIRQ_ADDR, hirq); + reg_write(rhport, HIRQ_ADDR, hirq, true); } } From 09ceaa6cf37d29e605495716fc2497ed5228a37f Mon Sep 17 00:00:00 2001 From: hathach Date: Fri, 25 Aug 2023 13:18:47 +0700 Subject: [PATCH 12/34] add osal mutex for spi --- src/portable/analog/max3421/hcd_max3421.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/portable/analog/max3421/hcd_max3421.c b/src/portable/analog/max3421/hcd_max3421.c index 0144deca69..09845ffe49 100644 --- a/src/portable/analog/max3421/hcd_max3421.c +++ b/src/portable/analog/max3421/hcd_max3421.c @@ -194,7 +194,10 @@ typedef struct { hcd_ep_t ep[8][2]; - OSAL_MUTEX_DEF(spi_mutex); + OSAL_MUTEX_DEF(spi_mutexdef); +#if OSAL_MUTEX_REQUIRED + osal_mutex_t spi_mutex; +#endif } max2341_data_t; static max2341_data_t _hcd_data; @@ -215,6 +218,7 @@ static void max3421_spi_lock(uint8_t rhport, bool in_isr) { // disable interrupt and mutex lock (for pre-emptive RTOS) if not in_isr if (!in_isr) { tuh_max3421e_int_api(rhport, false); + (void) osal_mutex_lock(_hcd_data.spi_mutex, OSAL_TIMEOUT_WAIT_FOREVER); } // assert CS @@ -228,6 +232,7 @@ static void max3421_spi_unlock(uint8_t rhport, bool in_isr) { // mutex unlock and re-enable interrupt if (!in_isr) { tuh_max3421e_int_api(rhport, true); + (void) osal_mutex_unlock(_hcd_data.spi_mutex); } } @@ -372,12 +377,16 @@ tusb_speed_t handle_connect_irq(uint8_t rhport) { bool hcd_init(uint8_t rhport) { (void) rhport; + hcd_int_disable(rhport); + TU_LOG2_INT(sizeof(hcd_ep_t)); TU_LOG2_INT(sizeof(max2341_data_t)); tu_memclr(&_hcd_data, sizeof(_hcd_data)); - hcd_int_disable(rhport); +#if OSAL_MUTEX_REQUIRED + _hcd_data.spi_mutex = osal_mutex_create(&_hcd_data.spi_mutexdef); +#endif // full duplex, interrupt negative edge reg_write(rhport, PINCTL_ADDR, PINCTL_FDUPSPI, false); From ecf2f910424b53fecc3ca82ae410f054518cc752 Mon Sep 17 00:00:00 2001 From: hathach Date: Fri, 25 Aug 2023 16:36:28 +0700 Subject: [PATCH 13/34] use endpoint pool for more flexible multiple devices support --- src/portable/analog/max3421/hcd_max3421.c | 178 +++++++++++++++------- 1 file changed, 121 insertions(+), 57 deletions(-) diff --git a/src/portable/analog/max3421/hcd_max3421.c b/src/portable/analog/max3421/hcd_max3421.c index 09845ffe49..b0325f240a 100644 --- a/src/portable/analog/max3421/hcd_max3421.c +++ b/src/portable/analog/max3421/hcd_max3421.c @@ -165,22 +165,26 @@ enum { //--------------------------------------------------------------------+ typedef struct { - uint16_t packet_size; - struct TU_ATTR_PACKED { + uint8_t ep_dir : 1; uint8_t is_iso : 1; uint8_t data_toggle : 1; - uint8_t xfer_queued : 1; + uint8_t xfer_pending : 1; uint8_t xfer_complete : 1; }; + struct TU_ATTR_PACKED { + uint8_t daddr : 4; + uint8_t ep_num : 4; + }; + uint16_t packet_size; uint16_t total_len; uint16_t xferred_len; uint8_t* buf; -} hcd_ep_t; +} max3421_ep_t; typedef struct { - atomic_bool busy; // busy transferring + atomic_flag busy; // busy transferring // cached register uint8_t sndbc; @@ -192,15 +196,16 @@ typedef struct { volatile uint16_t frame_count; - hcd_ep_t ep[8][2]; + max3421_ep_t ep0_addr0; // control endpoint for addr0 + max3421_ep_t ep[CFG_TUH_MAX3421_ENDPOINT_TOTAL]; OSAL_MUTEX_DEF(spi_mutexdef); #if OSAL_MUTEX_REQUIRED osal_mutex_t spi_mutex; #endif -} max2341_data_t; +} max3421_data_t; -static max2341_data_t _hcd_data; +static max3421_data_t _hcd_data; //--------------------------------------------------------------------+ // API: SPI transfer with MAX3421E, must be implemented by application @@ -211,7 +216,7 @@ bool tuh_max3421_spi_xfer_api(uint8_t rhport, uint8_t const * tx_buf, size_t tx_ void tuh_max3421e_int_api(uint8_t rhport, bool enabled); //--------------------------------------------------------------------+ -// +// SPI Helper //--------------------------------------------------------------------+ static void max3421_spi_lock(uint8_t rhport, bool in_isr) { @@ -318,6 +323,44 @@ static inline void sndbc_write(uint8_t rhport, uint8_t data, bool in_isr) { reg_write(rhport, SNDBC_ADDR, data, in_isr); } +//--------------------------------------------------------------------+ +// Endpoint helper +//--------------------------------------------------------------------+ + +static max3421_ep_t* find_ep_not_addr0(uint8_t daddr, uint8_t ep_num, uint8_t ep_dir) { + for(size_t i=0; idaddr && ep_num == ep->ep_num && (ep_dir == ep->ep_dir || ep_num == 0) ) { + return ep; + } + } + + return NULL; +} + +// daddr = 0 and ep_num = 0 means find a free (allocate) endpoint +TU_ATTR_ALWAYS_INLINE static inline max3421_ep_t * allocate_ep(void) { + return find_ep_not_addr0(0, 0, 0); +} + +// free all endpoints belong to device address +static void free_ep(uint8_t daddr) { + for (size_t i=0; idaddr == daddr) { + tu_memclr(ep, sizeof(max3421_ep_t)); + } + } +} + +TU_ATTR_ALWAYS_INLINE static inline max3421_ep_t * find_opened_ep(uint8_t daddr, uint8_t ep_num, uint8_t ep_dir) { + if (daddr == 0 && ep_num == 0) { + return &_hcd_data.ep0_addr0; + }else{ + return find_ep_not_addr0(daddr, ep_num, ep_dir); + } +} //--------------------------------------------------------------------+ // Controller API @@ -379,8 +422,8 @@ bool hcd_init(uint8_t rhport) { hcd_int_disable(rhport); - TU_LOG2_INT(sizeof(hcd_ep_t)); - TU_LOG2_INT(sizeof(max2341_data_t)); + TU_LOG2_INT(sizeof(max3421_ep_t)); + TU_LOG2_INT(sizeof(max3421_data_t)); tu_memclr(&_hcd_data, sizeof(_hcd_data)); @@ -478,22 +521,29 @@ void hcd_device_close(uint8_t rhport, uint8_t dev_addr) { //--------------------------------------------------------------------+ // Open an endpoint -bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const * ep_desc) { +bool hcd_edpt_open(uint8_t rhport, uint8_t daddr, tusb_desc_endpoint_t const * ep_desc) { (void) rhport; - (void) dev_addr; + (void) daddr; uint8_t ep_num = tu_edpt_number(ep_desc->bEndpointAddress); uint8_t ep_dir = tu_edpt_dir(ep_desc->bEndpointAddress); - hcd_ep_t * ep = &_hcd_data.ep[ep_num][ep_dir]; - - ep->packet_size = tu_edpt_packet_size(ep_desc); + max3421_ep_t * ep; + if (daddr == 0 && ep_num == 0) { + ep = &_hcd_data.ep0_addr0; + }else { + ep = allocate_ep(); + TU_ASSERT(ep); + ep->daddr = daddr; + ep->ep_num = ep_num; + ep->ep_dir = ep_dir; + } - if (ep_desc->bEndpointAddress == 0) { - _hcd_data.ep[0][1].packet_size = ep->packet_size; + if ( TUSB_XFER_ISOCHRONOUS == ep_desc->bmAttributes.xfer ) { + ep->is_iso = 1; } - ep->is_iso = (TUSB_XFER_ISOCHRONOUS == ep_desc->bmAttributes.xfer) ? 1 : 0; + ep->packet_size = tu_edpt_packet_size(ep_desc); return true; } @@ -505,49 +555,54 @@ bool hcd_edpt_xfer(uint8_t rhport, uint8_t daddr, uint8_t ep_addr, uint8_t * buf uint8_t const ep_num = tu_edpt_number(ep_addr); uint8_t const ep_dir = tu_edpt_dir(ep_addr); - hcd_ep_t* ep = &_hcd_data.ep[ep_num][ep_dir]; + max3421_ep_t* ep = find_opened_ep(daddr, ep_num, ep_dir); + TU_ASSERT(ep); ep->buf = buffer; ep->total_len = buflen; ep->xferred_len = 0; ep->xfer_complete = 0; - ep->xfer_queued = 1; - - peraddr_write(rhport, daddr, false); - - uint8_t hctl = 0; - uint8_t hxfr = ep_num; - - if ( ep->is_iso ) { - hxfr |= HXFR_ISO; - } else if ( ep_num == 0 ) { - ep->data_toggle = 1; - if ( buffer == NULL || buflen == 0 ) { - // ZLP for ACK stage, use HS - hxfr |= HXFR_HS; - hxfr |= (ep_dir ? 0 : HXFR_OUT_NIN); - hxfr_write(rhport, hxfr, false); - return true; + ep->xfer_pending = 1; + + // carry out transfer if not busy +// if ( atomic_flag_test_and_set(&_hcd_data.busy) ) + { + peraddr_write(rhport, daddr, false); + + uint8_t hctl = 0; + uint8_t hxfr = ep_num; + + if ( ep->is_iso ) { + hxfr |= HXFR_ISO; + } else if ( ep_num == 0 ) { + ep->data_toggle = 1; + if ( buffer == NULL || buflen == 0 ) { + // ZLP for ACK stage, use HS + hxfr |= HXFR_HS; + hxfr |= (ep_dir ? 0 : HXFR_OUT_NIN); + hxfr_write(rhport, hxfr, false); + return true; + } } - } - if ( 0 == ep_dir ) { - // Page 12: Programming BULK-OUT Transfers - TU_ASSERT(_hcd_data.hirq & HIRQ_SNDBAV_IRQ); + if ( 0 == ep_dir ) { + // Page 12: Programming BULK-OUT Transfers + TU_ASSERT(_hcd_data.hirq & HIRQ_SNDBAV_IRQ); - uint8_t const xact_len = (uint8_t) tu_min16(buflen, ep->packet_size); - fifo_write(rhport, SNDFIFO_ADDR, buffer, xact_len, false); - sndbc_write(rhport, xact_len, false); + uint8_t const xact_len = (uint8_t) tu_min16(buflen, ep->packet_size); + fifo_write(rhport, SNDFIFO_ADDR, buffer, xact_len, false); + sndbc_write(rhport, xact_len, false); - hctl = (ep->data_toggle ? HCTL_SNDTOG1 : HCTL_SNDTOG0); - hxfr |= HXFR_OUT_NIN; - } else { - // Page 13: Programming BULK-IN Transfers - hctl = (ep->data_toggle ? HCTL_RCVTOG1 : HCTL_RCVTOG0); - } + hctl = (ep->data_toggle ? HCTL_SNDTOG1 : HCTL_SNDTOG0); + hxfr |= HXFR_OUT_NIN; + } else { + // Page 13: Programming BULK-IN Transfers + hctl = (ep->data_toggle ? HCTL_RCVTOG1 : HCTL_RCVTOG0); + } - reg_write(rhport, HCTL_ADDR, hctl, false); - hxfr_write(rhport, hxfr, false); + reg_write(rhport, HCTL_ADDR, hctl, false); + hxfr_write(rhport, hxfr, false); + } return true; } @@ -566,7 +621,7 @@ bool hcd_edpt_abort_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr) { bool hcd_setup_send(uint8_t rhport, uint8_t daddr, uint8_t const setup_packet[8]) { (void) rhport; - hcd_ep_t* ep = &_hcd_data.ep[0][0]; + max3421_ep_t* ep = find_opened_ep(daddr, 0, 0); ep->total_len = 8; ep->xferred_len = 0; @@ -624,7 +679,7 @@ static void handle_xfer_done(uint8_t rhport) { if ( (hxfr_type & HXFR_SETUP) || (hxfr_type & HXFR_OUT_NIN) ) { // SETUP or OUT transfer - hcd_ep_t *ep = &_hcd_data.ep[ep_num][0]; + max3421_ep_t *ep = find_opened_ep(_hcd_data.peraddr, ep_num, 0); uint8_t xact_len; if ( hxfr_type & HXFR_SETUP) { @@ -644,10 +699,15 @@ static void handle_xfer_done(uint8_t rhport) { hcd_event_xfer_complete(_hcd_data.peraddr, ep_num, ep->xferred_len, xfer_result, true); }else { // more to transfer + xact_len = (uint8_t) tu_min16(ep->total_len - ep->xferred_len, ep->packet_size); + fifo_write(rhport, SNDFIFO_ADDR, ep->buf, xact_len, true); + sndbc_write(rhport, xact_len, true); + + hxfr_write(rhport, _hcd_data.hxfr, true); } } else { // IN transfer: fifo data is already received in RCVDAV IRQ - hcd_ep_t *ep = &_hcd_data.ep[ep_num][1]; + max3421_ep_t *ep = find_opened_ep(_hcd_data.peraddr, ep_num, 1); if ( hxfr_type & HXFR_HS ) { ep->xfer_complete = 1; @@ -702,6 +762,10 @@ void hcd_int_handler(uint8_t rhport) { if (speed == TUSB_SPEED_INVALID) { hcd_event_device_remove(rhport, true); }else { + // FIXME multiple MAX3421 rootdevice address is not 1 + uint8_t const daddr = 1; + free_ep(daddr); + hcd_event_device_attach(rhport, true); } } @@ -710,8 +774,8 @@ void hcd_int_handler(uint8_t rhport) { // not call this handler again. So we need to loop until all IRQ are cleared while ( hirq & (HIRQ_RCVDAV_IRQ | HIRQ_HXFRDN_IRQ) ) { if ( hirq & HIRQ_RCVDAV_IRQ ) { - uint8_t ep_num = _hcd_data.hxfr & HXFR_EPNUM_MASK; - hcd_ep_t *ep = &_hcd_data.ep[ep_num][1]; + uint8_t const ep_num = _hcd_data.hxfr & HXFR_EPNUM_MASK; + max3421_ep_t *ep = find_opened_ep(_hcd_data.peraddr, ep_num, 1); uint8_t xact_len; // RCVDAV_IRQ can trigger 2 times (dual buffered) From ac00b9147298184ca0bd1eadac3a02e7e867085d Mon Sep 17 00:00:00 2001 From: hathach Date: Fri, 25 Aug 2023 17:26:57 +0700 Subject: [PATCH 14/34] add xact_out(), xact_in() to manage transfer --- src/portable/analog/max3421/hcd_max3421.c | 143 ++++++++++++++-------- 1 file changed, 89 insertions(+), 54 deletions(-) diff --git a/src/portable/analog/max3421/hcd_max3421.c b/src/portable/analog/max3421/hcd_max3421.c index b0325f240a..00b36201ca 100644 --- a/src/portable/analog/max3421/hcd_max3421.c +++ b/src/portable/analog/max3421/hcd_max3421.c @@ -331,7 +331,7 @@ static max3421_ep_t* find_ep_not_addr0(uint8_t daddr, uint8_t ep_num, uint8_t ep for(size_t i=0; idaddr && ep_num == ep->ep_num && (ep_dir == ep->ep_dir || ep_num == 0) ) { + if (daddr == ep->daddr && ep_num == ep->ep_num && (ep_dir == ep->ep_dir || ep_num == 0)) { return ep; } } @@ -362,6 +362,28 @@ TU_ATTR_ALWAYS_INLINE static inline max3421_ep_t * find_opened_ep(uint8_t daddr, } } +//static max3421_ep_t * find_next_pending_ep(max3421_ep_t * cur_ep) { +// size_t idx = cur_ep - _hcd_data.ep; +// +// // starting from next endpoint +// for (size_t i = idx + 1; i < CFG_TUH_MAX3421_ENDPOINT_TOTAL; i++) { +// max3421_ep_t* ep = &_hcd_data.ep[i]; +// if (ep->xfer_pending) { +// return ep; +// } +// } +// +// // wrap around including current endpoint +// for (size_t i = 0; i <= idx; i++) { +// max3421_ep_t* ep = &_hcd_data.ep[i]; +// if (ep->xfer_pending) { +// return ep; +// } +// } +// +// return NULL; +//} + //--------------------------------------------------------------------+ // Controller API //--------------------------------------------------------------------+ @@ -548,6 +570,37 @@ bool hcd_edpt_open(uint8_t rhport, uint8_t daddr, tusb_desc_endpoint_t const * e return true; } +void xact_out(uint8_t rhport, max3421_ep_t *ep, bool switch_ep, bool in_isr) { + // Page 12: Programming BULK-OUT Transfers + // TODO double buffered + if (switch_ep) { + peraddr_write(rhport, ep->daddr, in_isr); + + uint8_t const hctl = (ep->data_toggle ? HCTL_SNDTOG1 : HCTL_SNDTOG0); + reg_write(rhport, HCTL_ADDR, hctl, in_isr); + } + + uint8_t const xact_len = (uint8_t) tu_min16(ep->total_len - ep->xferred_len, ep->packet_size); + fifo_write(rhport, SNDFIFO_ADDR, ep->buf, xact_len, in_isr); + sndbc_write(rhport, xact_len, in_isr); + + uint8_t const hxfr = ep->ep_num | HXFR_OUT_NIN | (ep->is_iso ? HXFR_ISO : 0); + hxfr_write(rhport, hxfr, in_isr); +} + +void xact_in(uint8_t rhport, max3421_ep_t *ep, bool switch_ep, bool in_isr) { + // Page 13: Programming BULK-IN Transfers + if (switch_ep) { + peraddr_write(rhport, ep->daddr, in_isr); + + uint8_t const hctl = (ep->data_toggle ? HCTL_RCVTOG1 : HCTL_RCVTOG0); + reg_write(rhport, HCTL_ADDR, hctl, in_isr); + } + + uint8_t const hxfr = ep->ep_num | (ep->is_iso ? HXFR_ISO : 0); + hxfr_write(rhport, hxfr, in_isr); +} + // Submit a transfer, when complete hcd_event_xfer_complete() must be invoked bool hcd_edpt_xfer(uint8_t rhport, uint8_t daddr, uint8_t ep_addr, uint8_t * buffer, uint16_t buflen) { (void) rhport; @@ -567,17 +620,14 @@ bool hcd_edpt_xfer(uint8_t rhport, uint8_t daddr, uint8_t ep_addr, uint8_t * buf // carry out transfer if not busy // if ( atomic_flag_test_and_set(&_hcd_data.busy) ) { - peraddr_write(rhport, daddr, false); - - uint8_t hctl = 0; uint8_t hxfr = ep_num; - if ( ep->is_iso ) { - hxfr |= HXFR_ISO; - } else if ( ep_num == 0 ) { + if ( ep_num == 0 ) { ep->data_toggle = 1; if ( buffer == NULL || buflen == 0 ) { // ZLP for ACK stage, use HS + peraddr_write(rhport, daddr, false); + hxfr |= HXFR_HS; hxfr |= (ep_dir ? 0 : HXFR_OUT_NIN); hxfr_write(rhport, hxfr, false); @@ -586,22 +636,11 @@ bool hcd_edpt_xfer(uint8_t rhport, uint8_t daddr, uint8_t ep_addr, uint8_t * buf } if ( 0 == ep_dir ) { - // Page 12: Programming BULK-OUT Transfers TU_ASSERT(_hcd_data.hirq & HIRQ_SNDBAV_IRQ); - - uint8_t const xact_len = (uint8_t) tu_min16(buflen, ep->packet_size); - fifo_write(rhport, SNDFIFO_ADDR, buffer, xact_len, false); - sndbc_write(rhport, xact_len, false); - - hctl = (ep->data_toggle ? HCTL_SNDTOG1 : HCTL_SNDTOG0); - hxfr |= HXFR_OUT_NIN; + xact_out(rhport, ep, true, false); } else { - // Page 13: Programming BULK-IN Transfers - hctl = (ep->data_toggle ? HCTL_RCVTOG1 : HCTL_RCVTOG0); + xact_in(rhport, ep, true, false); } - - reg_write(rhport, HCTL_ADDR, hctl, false); - hxfr_write(rhport, hxfr, false); } return true; @@ -644,7 +683,12 @@ bool hcd_edpt_clear_stall(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr) { static void handle_xfer_done(uint8_t rhport) { uint8_t const hrsl = reg_read(rhport, HRSL_ADDR, true); uint8_t const hresult = hrsl & HRSL_RESULT_MASK; - uint8_t ep_num = _hcd_data.hxfr & HXFR_EPNUM_MASK; + + uint8_t const ep_num = _hcd_data.hxfr & HXFR_EPNUM_MASK; + uint8_t const hxfr_type = _hcd_data.hxfr & 0xf0; + uint8_t const ep_dir = ((hxfr_type & HXFR_SETUP) || (hxfr_type & HXFR_OUT_NIN)) ? 0 : 1; + + max3421_ep_t *ep = find_opened_ep(_hcd_data.peraddr, ep_num, ep_dir); xfer_result_t xfer_result; @@ -663,10 +707,11 @@ static void handle_xfer_done(uint8_t rhport) { return; case HRSL_NAK: - // NAK on control, retry immediately - //if (ep_num == 0) - { + if (ep_num == 0) { + // NAK on control, retry immediately hxfr_write(rhport, _hcd_data.hxfr, true); + }else { + // NAK on non-control, find next pending to switch } return; @@ -675,16 +720,28 @@ static void handle_xfer_done(uint8_t rhport) { break; } - uint8_t const hxfr_type = _hcd_data.hxfr & 0xf0; + if (ep_dir) { + // IN transfer: fifo data is already received in RCVDAV IRQ + if ( hxfr_type & HXFR_HS ) { + ep->xfer_complete = 1; + } - if ( (hxfr_type & HXFR_SETUP) || (hxfr_type & HXFR_OUT_NIN) ) { + // short packet or all bytes transferred + if ( ep->xfer_complete ) { + // save data toggle + ep->data_toggle = (hrsl & HRSL_RCVTOGRD) ? 1 : 0; + hcd_event_xfer_complete(_hcd_data.peraddr, TUSB_DIR_IN_MASK | ep_num, ep->xferred_len, xfer_result, true); + }else { + // more to transfer + hxfr_write(rhport, _hcd_data.hxfr, true); + } + } else { // SETUP or OUT transfer - max3421_ep_t *ep = find_opened_ep(_hcd_data.peraddr, ep_num, 0); uint8_t xact_len; - if ( hxfr_type & HXFR_SETUP) { + if (hxfr_type & HXFR_SETUP) { xact_len = 8; - } else if ( hxfr_type & HXFR_HS ) { + } else if (hxfr_type & HXFR_HS) { xact_len = 0; } else { xact_len = _hcd_data.sndbc; @@ -693,34 +750,12 @@ static void handle_xfer_done(uint8_t rhport) { ep->xferred_len += xact_len; ep->buf += xact_len; - if ( xact_len < ep->packet_size || ep->xferred_len >= ep->total_len ) { + if (xact_len < ep->packet_size || ep->xferred_len >= ep->total_len) { // save data toggle ep->data_toggle = (hrsl & HRSL_SNDTOGRD) ? 1 : 0; hcd_event_xfer_complete(_hcd_data.peraddr, ep_num, ep->xferred_len, xfer_result, true); - }else { - // more to transfer - xact_len = (uint8_t) tu_min16(ep->total_len - ep->xferred_len, ep->packet_size); - fifo_write(rhport, SNDFIFO_ADDR, ep->buf, xact_len, true); - sndbc_write(rhport, xact_len, true); - - hxfr_write(rhport, _hcd_data.hxfr, true); - } - } else { - // IN transfer: fifo data is already received in RCVDAV IRQ - max3421_ep_t *ep = find_opened_ep(_hcd_data.peraddr, ep_num, 1); - - if ( hxfr_type & HXFR_HS ) { - ep->xfer_complete = 1; - } - - // short packet or all bytes transferred - if ( ep->xfer_complete ) { - // save data toggle - ep->data_toggle = (hrsl & HRSL_RCVTOGRD) ? 1 : 0; - hcd_event_xfer_complete(_hcd_data.peraddr, TUSB_DIR_IN_MASK | ep_num, ep->xferred_len, xfer_result, true); - }else { - // more to transfer - hxfr_write(rhport, _hcd_data.hxfr, true); + } else { + xact_out(rhport, ep, false, true); } } } From cd7464a8847db5efa14f568bdf8746d898fc7eb4 Mon Sep 17 00:00:00 2001 From: hathach Date: Fri, 25 Aug 2023 17:37:09 +0700 Subject: [PATCH 15/34] try next endpoint when received NAK --- src/portable/analog/max3421/hcd_max3421.c | 58 +++++++++++++++-------- 1 file changed, 37 insertions(+), 21 deletions(-) diff --git a/src/portable/analog/max3421/hcd_max3421.c b/src/portable/analog/max3421/hcd_max3421.c index 00b36201ca..e546f99cef 100644 --- a/src/portable/analog/max3421/hcd_max3421.c +++ b/src/portable/analog/max3421/hcd_max3421.c @@ -362,27 +362,27 @@ TU_ATTR_ALWAYS_INLINE static inline max3421_ep_t * find_opened_ep(uint8_t daddr, } } -//static max3421_ep_t * find_next_pending_ep(max3421_ep_t * cur_ep) { -// size_t idx = cur_ep - _hcd_data.ep; -// -// // starting from next endpoint -// for (size_t i = idx + 1; i < CFG_TUH_MAX3421_ENDPOINT_TOTAL; i++) { -// max3421_ep_t* ep = &_hcd_data.ep[i]; -// if (ep->xfer_pending) { -// return ep; -// } -// } -// -// // wrap around including current endpoint -// for (size_t i = 0; i <= idx; i++) { -// max3421_ep_t* ep = &_hcd_data.ep[i]; -// if (ep->xfer_pending) { -// return ep; -// } -// } -// -// return NULL; -//} +static max3421_ep_t * find_next_pending_ep(max3421_ep_t * cur_ep) { + size_t idx = cur_ep - _hcd_data.ep; + + // starting from next endpoint + for (size_t i = idx + 1; i < CFG_TUH_MAX3421_ENDPOINT_TOTAL; i++) { + max3421_ep_t* ep = &_hcd_data.ep[i]; + if (ep->xfer_pending) { + return ep; + } + } + + // wrap around including current endpoint + for (size_t i = 0; i <= idx; i++) { + max3421_ep_t* ep = &_hcd_data.ep[i]; + if (ep->xfer_pending) { + return ep; + } + } + + return NULL; +} //--------------------------------------------------------------------+ // Controller API @@ -443,6 +443,7 @@ bool hcd_init(uint8_t rhport) { (void) rhport; hcd_int_disable(rhport); + tuh_max3421_spi_cs_api(rhport, false); TU_LOG2_INT(sizeof(max3421_ep_t)); TU_LOG2_INT(sizeof(max3421_data_t)); @@ -689,6 +690,7 @@ static void handle_xfer_done(uint8_t rhport) { uint8_t const ep_dir = ((hxfr_type & HXFR_SETUP) || (hxfr_type & HXFR_OUT_NIN)) ? 0 : 1; max3421_ep_t *ep = find_opened_ep(_hcd_data.peraddr, ep_num, ep_dir); + TU_ASSERT(ep, ); xfer_result_t xfer_result; @@ -712,6 +714,20 @@ static void handle_xfer_done(uint8_t rhport) { hxfr_write(rhport, _hcd_data.hxfr, true); }else { // NAK on non-control, find next pending to switch + max3421_ep_t *next_ep = find_next_pending_ep(ep); + TU_ASSERT(next_ep, ); + + if (ep == next_ep) { + // only one pending, retry immediately + hxfr_write(rhport, _hcd_data.hxfr, true); + }else { + // switch to next pending TODO could have issue with double buffered if not clear previously out data + if ( ep_dir ) { + xact_in(rhport, next_ep, true, true); + } else { + xact_out(rhport, next_ep, true, true); + } + } } return; From 502b1bdda62f0f207d9a51daf134574e455f3aa2 Mon Sep 17 00:00:00 2001 From: hathach Date: Sun, 27 Aug 2023 23:45:34 +0700 Subject: [PATCH 16/34] more update to transaction --- examples/host/cdc_msc_hid/src/tusb_config.h | 9 ++-- .../host/msc_file_explorer/src/tusb_config.h | 10 ++-- src/common/tusb_mcu.h | 12 +++++ src/host/hcd.h | 4 +- src/host/usbh.c | 1 + src/portable/analog/max3421/hcd_max3421.c | 51 ++++++++++++------- 6 files changed, 62 insertions(+), 25 deletions(-) diff --git a/examples/host/cdc_msc_hid/src/tusb_config.h b/examples/host/cdc_msc_hid/src/tusb_config.h index abb75f0684..7d621d466c 100644 --- a/examples/host/cdc_msc_hid/src/tusb_config.h +++ b/examples/host/cdc_msc_hid/src/tusb_config.h @@ -35,9 +35,12 @@ //--------------------------------------------------------------------+ #if CFG_TUSB_MCU == OPT_MCU_RP2040 -// change to 1 if using pico-pio-usb as host controller for raspberry rp2040 -#define CFG_TUH_RPI_PIO_USB 0 -#define BOARD_TUH_RHPORT CFG_TUH_RPI_PIO_USB + // change to 1 if using pico-pio-usb as host controller for raspberry rp2040 + #define CFG_TUH_RPI_PIO_USB 0 + #define BOARD_TUH_RHPORT CFG_TUH_RPI_PIO_USB +#elif CFG_TUSB_MCU == OPT_MCU_NRF5X + // Use external USB controller (via SPI) MAX3421E (aka usb host shield) + #define CFG_TUH_MAX3421 1 #endif // RHPort number used for host can be defined by board.mk, default to port 0 diff --git a/examples/host/msc_file_explorer/src/tusb_config.h b/examples/host/msc_file_explorer/src/tusb_config.h index 1e0d067bf4..bb2fd4cf56 100644 --- a/examples/host/msc_file_explorer/src/tusb_config.h +++ b/examples/host/msc_file_explorer/src/tusb_config.h @@ -35,11 +35,15 @@ //--------------------------------------------------------------------+ #if CFG_TUSB_MCU == OPT_MCU_RP2040 -// change to 1 if using pico-pio-usb as host controller for raspberry rp2040 -#define CFG_TUH_RPI_PIO_USB 0 -#define BOARD_TUH_RHPORT CFG_TUH_RPI_PIO_USB + // change to 1 if using pico-pio-usb as host controller for raspberry rp2040 + #define CFG_TUH_RPI_PIO_USB 0 + #define BOARD_TUH_RHPORT CFG_TUH_RPI_PIO_US +#elif CFG_TUSB_MCU == OPT_MCU_NRF5X + // Use external USB controller (via SPI) MAX3421E (aka usb host shield) + #define CFG_TUH_MAX3421 1 #endif + // RHPort number used for host can be defined by board.mk, default to port 0 #ifndef BOARD_TUH_RHPORT #define BOARD_TUH_RHPORT 0 diff --git a/src/common/tusb_mcu.h b/src/common/tusb_mcu.h index 35f94efbcc..21939df7c6 100644 --- a/src/common/tusb_mcu.h +++ b/src/common/tusb_mcu.h @@ -385,6 +385,18 @@ #define TUP_RHPORT_HIGHSPEED 1 #endif + +//--------------------------------------------------------------------+ +// External USB controller +//--------------------------------------------------------------------+ + +#if defined(CFG_TUH_MAX3421) & CFG_TUH_MAX3421 + #ifndef CFG_TUH_MAX3421_ENDPOINT_TOTAL + #define CFG_TUH_MAX3421_ENDPOINT_TOTAL (8 + 4*(CFG_TUH_DEVICE_MAX-1)) + #endif +#endif + + //--------------------------------------------------------------------+ // Default Values //--------------------------------------------------------------------+ diff --git a/src/host/hcd.h b/src/host/hcd.h index 1f01a1a2f5..e25b20ea33 100644 --- a/src/host/hcd.h +++ b/src/host/hcd.h @@ -39,7 +39,7 @@ // Configuration //--------------------------------------------------------------------+ -// Max number of endpoints per device +// Max number of endpoints pair per device // TODO optimize memory usage #ifndef CFG_TUH_ENDPOINT_MAX #define CFG_TUH_ENDPOINT_MAX 16 @@ -167,7 +167,7 @@ void hcd_device_close(uint8_t rhport, uint8_t dev_addr); //--------------------------------------------------------------------+ // Open an endpoint -bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const * ep_desc); +bool hcd_edpt_open(uint8_t rhport, uint8_t daddr, tusb_desc_endpoint_t const * ep_desc); // Submit a transfer, when complete hcd_event_xfer_complete() must be invoked bool hcd_edpt_xfer(uint8_t rhport, uint8_t daddr, uint8_t ep_addr, uint8_t * buffer, uint16_t buflen); diff --git a/src/host/usbh.c b/src/host/usbh.c index 7a09f5b6e2..12a7f58393 100644 --- a/src/host/usbh.c +++ b/src/host/usbh.c @@ -919,6 +919,7 @@ TU_ATTR_FAST_FUNC void hcd_event_handler(hcd_event_t const* event, bool in_isr) switch (event->event_id) { // case HCD_EVENT_DEVICE_REMOVE: +// // FIXME device remove from a hub need an HCD API for hcd to free up endpoint // // mark device as removing to prevent further xfer before the event is processed in usbh task // break; diff --git a/src/portable/analog/max3421/hcd_max3421.c b/src/portable/analog/max3421/hcd_max3421.c index e546f99cef..574cca788f 100644 --- a/src/portable/analog/max3421/hcd_max3421.c +++ b/src/portable/analog/max3421/hcd_max3421.c @@ -582,6 +582,7 @@ void xact_out(uint8_t rhport, max3421_ep_t *ep, bool switch_ep, bool in_isr) { } uint8_t const xact_len = (uint8_t) tu_min16(ep->total_len - ep->xferred_len, ep->packet_size); + TU_ASSERT(_hcd_data.hirq & HIRQ_SNDBAV_IRQ, ); fifo_write(rhport, SNDFIFO_ADDR, ep->buf, xact_len, in_isr); sndbc_write(rhport, xact_len, in_isr); @@ -602,6 +603,28 @@ void xact_in(uint8_t rhport, max3421_ep_t *ep, bool switch_ep, bool in_isr) { hxfr_write(rhport, hxfr, in_isr); } +TU_ATTR_ALWAYS_INLINE static inline void xact_inout(uint8_t rhport, max3421_ep_t *ep, bool switch_ep, bool in_isr) { + if (ep->ep_dir) { + xact_in(rhport, ep, switch_ep, in_isr); + }else { + xact_out(rhport, ep, switch_ep, in_isr); + } +} + +void xfer_complete_isr(uint8_t rhport, max3421_ep_t *ep, xfer_result_t result, uint8_t data_toggle) { + (void) rhport; + (void) result; + ep->xfer_pending = 0; + ep->data_toggle = data_toggle; + //uint8_t const ep_addr = tu_edpt_addr(ep->ep_num, ep->ep_dir); + //hcd_event_xfer_complete(rhport, ep_addr, ep->xferred_len, result, true); + +// max3421_ep_t *next_ep = find_next_pending_ep(ep); +// if (next_ep) { +// xact_inout(rhport, next_ep, true, true); +// } +} + // Submit a transfer, when complete hcd_event_xfer_complete() must be invoked bool hcd_edpt_xfer(uint8_t rhport, uint8_t daddr, uint8_t ep_addr, uint8_t * buffer, uint16_t buflen) { (void) rhport; @@ -612,6 +635,9 @@ bool hcd_edpt_xfer(uint8_t rhport, uint8_t daddr, uint8_t ep_addr, uint8_t * buf max3421_ep_t* ep = find_opened_ep(daddr, ep_num, ep_dir); TU_ASSERT(ep); + // control transfer can switch direction + ep->ep_dir = ep_dir; + ep->buf = buffer; ep->total_len = buflen; ep->xferred_len = 0; @@ -636,12 +662,7 @@ bool hcd_edpt_xfer(uint8_t rhport, uint8_t daddr, uint8_t ep_addr, uint8_t * buf } } - if ( 0 == ep_dir ) { - TU_ASSERT(_hcd_data.hirq & HIRQ_SNDBAV_IRQ); - xact_out(rhport, ep, true, false); - } else { - xact_in(rhport, ep, true, false); - } + xact_inout(rhport, ep, true, false); } return true; @@ -662,6 +683,7 @@ bool hcd_setup_send(uint8_t rhport, uint8_t daddr, uint8_t const setup_packet[8] (void) rhport; max3421_ep_t* ep = find_opened_ep(daddr, 0, 0); + ep->ep_dir = 0; ep->total_len = 8; ep->xferred_len = 0; @@ -715,18 +737,13 @@ static void handle_xfer_done(uint8_t rhport) { }else { // NAK on non-control, find next pending to switch max3421_ep_t *next_ep = find_next_pending_ep(ep); - TU_ASSERT(next_ep, ); if (ep == next_ep) { // only one pending, retry immediately hxfr_write(rhport, _hcd_data.hxfr, true); - }else { + }else if (next_ep) { // switch to next pending TODO could have issue with double buffered if not clear previously out data - if ( ep_dir ) { - xact_in(rhport, next_ep, true, true); - } else { - xact_out(rhport, next_ep, true, true); - } + xact_inout(rhport, next_ep, true, true); } } return; @@ -744,8 +761,8 @@ static void handle_xfer_done(uint8_t rhport) { // short packet or all bytes transferred if ( ep->xfer_complete ) { - // save data toggle - ep->data_toggle = (hrsl & HRSL_RCVTOGRD) ? 1 : 0; + uint8_t const dt = (hrsl & HRSL_RCVTOGRD) ? 1 : 0; // save data toggle + xfer_complete_isr(rhport, ep, xfer_result, dt); hcd_event_xfer_complete(_hcd_data.peraddr, TUSB_DIR_IN_MASK | ep_num, ep->xferred_len, xfer_result, true); }else { // more to transfer @@ -767,8 +784,8 @@ static void handle_xfer_done(uint8_t rhport) { ep->buf += xact_len; if (xact_len < ep->packet_size || ep->xferred_len >= ep->total_len) { - // save data toggle - ep->data_toggle = (hrsl & HRSL_SNDTOGRD) ? 1 : 0; + uint8_t const dt = (hrsl & HRSL_SNDTOGRD) ? 1 : 0; // save data toggle + xfer_complete_isr(rhport, ep, xfer_result, dt); hcd_event_xfer_complete(_hcd_data.peraddr, ep_num, ep->xferred_len, xfer_result, true); } else { xact_out(rhport, ep, false, true); From 84df3b04db47d34b53ef002b056b6b324394de52 Mon Sep 17 00:00:00 2001 From: hathach Date: Sun, 27 Aug 2023 23:54:24 +0700 Subject: [PATCH 17/34] minor update --- .idea/cmake.xml | 5 +++-- .idea/runConfigurations/nrf52840.xml | 2 +- examples/host/cdc_msc_hid/src/tusb_config.h | 6 +++--- examples/host/msc_file_explorer/src/tusb_config.h | 6 +++--- 4 files changed, 10 insertions(+), 9 deletions(-) diff --git a/.idea/cmake.xml b/.idea/cmake.xml index 8ee7f09a0a..86e7c66066 100644 --- a/.idea/cmake.xml +++ b/.idea/cmake.xml @@ -30,9 +30,10 @@ - - + + + diff --git a/.idea/runConfigurations/nrf52840.xml b/.idea/runConfigurations/nrf52840.xml index 084669c396..2f3f1876a1 100644 --- a/.idea/runConfigurations/nrf52840.xml +++ b/.idea/runConfigurations/nrf52840.xml @@ -1,5 +1,5 @@ - + diff --git a/examples/host/cdc_msc_hid/src/tusb_config.h b/examples/host/cdc_msc_hid/src/tusb_config.h index 7d621d466c..8d3ef88919 100644 --- a/examples/host/cdc_msc_hid/src/tusb_config.h +++ b/examples/host/cdc_msc_hid/src/tusb_config.h @@ -38,9 +38,9 @@ // change to 1 if using pico-pio-usb as host controller for raspberry rp2040 #define CFG_TUH_RPI_PIO_USB 0 #define BOARD_TUH_RHPORT CFG_TUH_RPI_PIO_USB -#elif CFG_TUSB_MCU == OPT_MCU_NRF5X - // Use external USB controller (via SPI) MAX3421E (aka usb host shield) - #define CFG_TUH_MAX3421 1 +//#elif CFG_TUSB_MCU == OPT_MCU_NRF5X +// // Use external USB controller (via SPI) MAX3421E (aka usb host shield) +// #define CFG_TUH_MAX3421 1 #endif // RHPort number used for host can be defined by board.mk, default to port 0 diff --git a/examples/host/msc_file_explorer/src/tusb_config.h b/examples/host/msc_file_explorer/src/tusb_config.h index bb2fd4cf56..28e130c0e5 100644 --- a/examples/host/msc_file_explorer/src/tusb_config.h +++ b/examples/host/msc_file_explorer/src/tusb_config.h @@ -38,9 +38,9 @@ // change to 1 if using pico-pio-usb as host controller for raspberry rp2040 #define CFG_TUH_RPI_PIO_USB 0 #define BOARD_TUH_RHPORT CFG_TUH_RPI_PIO_US -#elif CFG_TUSB_MCU == OPT_MCU_NRF5X - // Use external USB controller (via SPI) MAX3421E (aka usb host shield) - #define CFG_TUH_MAX3421 1 +//#elif CFG_TUSB_MCU == OPT_MCU_NRF5X +// // Use external USB controller (via SPI) MAX3421E (aka usb host shield) +// #define CFG_TUH_MAX3421 1 #endif From b31924e13edff0f29829056152348a9255e72169 Mon Sep 17 00:00:00 2001 From: hathach Date: Mon, 28 Aug 2023 12:41:44 +0700 Subject: [PATCH 18/34] - add xfer_complete_isr() - merge addr0 ep to pool - add control status to xact in/out - use atomic flag busy to ensure only 1 transfer is active at any time - execute pending transfer after one is complete (or clear busy flag) - change rtt mode to block if full --- hw/bsp/family_support.cmake | 1 + src/portable/analog/max3421/hcd_max3421.c | 118 +++++++++++----------- 2 files changed, 62 insertions(+), 57 deletions(-) diff --git a/hw/bsp/family_support.cmake b/hw/bsp/family_support.cmake index 7c89427c0d..1cbcfb2a74 100644 --- a/hw/bsp/family_support.cmake +++ b/hw/bsp/family_support.cmake @@ -216,6 +216,7 @@ function(family_configure_common TARGET RTOS) if (NOT TARGET segger_rtt) add_library(segger_rtt STATIC ${TOP}/lib/SEGGER_RTT/RTT/SEGGER_RTT.c) target_include_directories(segger_rtt PUBLIC ${TOP}/lib/SEGGER_RTT/RTT) + target_compile_definitions(segger_rtt PUBLIC SEGGER_RTT_MODE_DEFAULT=SEGGER_RTT_MODE_BLOCK_IF_FIFO_FULL) endif() target_link_libraries(${TARGET} PUBLIC segger_rtt) endif () diff --git a/src/portable/analog/max3421/hcd_max3421.c b/src/portable/analog/max3421/hcd_max3421.c index 574cca788f..262dbca0fc 100644 --- a/src/portable/analog/max3421/hcd_max3421.c +++ b/src/portable/analog/max3421/hcd_max3421.c @@ -195,9 +195,7 @@ typedef struct { uint8_t hxfr; volatile uint16_t frame_count; - - max3421_ep_t ep0_addr0; // control endpoint for addr0 - max3421_ep_t ep[CFG_TUH_MAX3421_ENDPOINT_TOTAL]; + max3421_ep_t ep[CFG_TUH_MAX3421_ENDPOINT_TOTAL]; // [0] is reserved for addr0 OSAL_MUTEX_DEF(spi_mutexdef); #if OSAL_MUTEX_REQUIRED @@ -328,7 +326,7 @@ static inline void sndbc_write(uint8_t rhport, uint8_t data, bool in_isr) { //--------------------------------------------------------------------+ static max3421_ep_t* find_ep_not_addr0(uint8_t daddr, uint8_t ep_num, uint8_t ep_dir) { - for(size_t i=0; idaddr && ep_num == ep->ep_num && (ep_dir == ep->ep_dir || ep_num == 0)) { @@ -344,9 +342,17 @@ TU_ATTR_ALWAYS_INLINE static inline max3421_ep_t * allocate_ep(void) { return find_ep_not_addr0(0, 0, 0); } +TU_ATTR_ALWAYS_INLINE static inline max3421_ep_t * find_opened_ep(uint8_t daddr, uint8_t ep_num, uint8_t ep_dir) { + if (daddr == 0 && ep_num == 0) { + return &_hcd_data.ep[0]; + }else{ + return find_ep_not_addr0(daddr, ep_num, ep_dir); + } +} + // free all endpoints belong to device address static void free_ep(uint8_t daddr) { - for (size_t i=0; idaddr == daddr) { tu_memclr(ep, sizeof(max3421_ep_t)); @@ -354,16 +360,8 @@ static void free_ep(uint8_t daddr) { } } -TU_ATTR_ALWAYS_INLINE static inline max3421_ep_t * find_opened_ep(uint8_t daddr, uint8_t ep_num, uint8_t ep_dir) { - if (daddr == 0 && ep_num == 0) { - return &_hcd_data.ep0_addr0; - }else{ - return find_ep_not_addr0(daddr, ep_num, ep_dir); - } -} - static max3421_ep_t * find_next_pending_ep(max3421_ep_t * cur_ep) { - size_t idx = cur_ep - _hcd_data.ep; + size_t const idx = cur_ep - _hcd_data.ep; // starting from next endpoint for (size_t i = idx + 1; i < CFG_TUH_MAX3421_ENDPOINT_TOTAL; i++) { @@ -553,7 +551,7 @@ bool hcd_edpt_open(uint8_t rhport, uint8_t daddr, tusb_desc_endpoint_t const * e max3421_ep_t * ep; if (daddr == 0 && ep_num == 0) { - ep = &_hcd_data.ep0_addr0; + ep = &_hcd_data.ep[0]; }else { ep = allocate_ep(); TU_ASSERT(ep); @@ -581,12 +579,20 @@ void xact_out(uint8_t rhport, max3421_ep_t *ep, bool switch_ep, bool in_isr) { reg_write(rhport, HCTL_ADDR, hctl, in_isr); } - uint8_t const xact_len = (uint8_t) tu_min16(ep->total_len - ep->xferred_len, ep->packet_size); - TU_ASSERT(_hcd_data.hirq & HIRQ_SNDBAV_IRQ, ); - fifo_write(rhport, SNDFIFO_ADDR, ep->buf, xact_len, in_isr); - sndbc_write(rhport, xact_len, in_isr); + uint8_t hxfr = ep->ep_num | HXFR_OUT_NIN | (ep->is_iso ? HXFR_ISO : 0); + + if (ep->ep_num == 0 && (ep->buf == NULL || ep->total_len == 0)) { + // Control ZLP status use HS + hxfr |= HXFR_HS; + } else { + uint8_t const xact_len = (uint8_t) tu_min16(ep->total_len - ep->xferred_len, ep->packet_size); + TU_ASSERT(_hcd_data.hirq & HIRQ_SNDBAV_IRQ,); + if (xact_len) { + fifo_write(rhport, SNDFIFO_ADDR, ep->buf, xact_len, in_isr); + } + sndbc_write(rhport, xact_len, in_isr); + } - uint8_t const hxfr = ep->ep_num | HXFR_OUT_NIN | (ep->is_iso ? HXFR_ISO : 0); hxfr_write(rhport, hxfr, in_isr); } @@ -599,7 +605,12 @@ void xact_in(uint8_t rhport, max3421_ep_t *ep, bool switch_ep, bool in_isr) { reg_write(rhport, HCTL_ADDR, hctl, in_isr); } - uint8_t const hxfr = ep->ep_num | (ep->is_iso ? HXFR_ISO : 0); + uint8_t hxfr = ep->ep_num | (ep->is_iso ? HXFR_ISO : 0); + if (ep->ep_num == 0 && (ep->buf == NULL || ep->total_len == 0)) { + // Control ZLP status use HS + hxfr |= HXFR_HS; + } + hxfr_write(rhport, hxfr, in_isr); } @@ -611,24 +622,8 @@ TU_ATTR_ALWAYS_INLINE static inline void xact_inout(uint8_t rhport, max3421_ep_t } } -void xfer_complete_isr(uint8_t rhport, max3421_ep_t *ep, xfer_result_t result, uint8_t data_toggle) { - (void) rhport; - (void) result; - ep->xfer_pending = 0; - ep->data_toggle = data_toggle; - //uint8_t const ep_addr = tu_edpt_addr(ep->ep_num, ep->ep_dir); - //hcd_event_xfer_complete(rhport, ep_addr, ep->xferred_len, result, true); - -// max3421_ep_t *next_ep = find_next_pending_ep(ep); -// if (next_ep) { -// xact_inout(rhport, next_ep, true, true); -// } -} - // Submit a transfer, when complete hcd_event_xfer_complete() must be invoked bool hcd_edpt_xfer(uint8_t rhport, uint8_t daddr, uint8_t ep_addr, uint8_t * buffer, uint16_t buflen) { - (void) rhport; - uint8_t const ep_num = tu_edpt_number(ep_addr); uint8_t const ep_dir = tu_edpt_dir(ep_addr); @@ -644,24 +639,12 @@ bool hcd_edpt_xfer(uint8_t rhport, uint8_t daddr, uint8_t ep_addr, uint8_t * buf ep->xfer_complete = 0; ep->xfer_pending = 1; - // carry out transfer if not busy -// if ( atomic_flag_test_and_set(&_hcd_data.busy) ) - { - uint8_t hxfr = ep_num; - - if ( ep_num == 0 ) { - ep->data_toggle = 1; - if ( buffer == NULL || buflen == 0 ) { - // ZLP for ACK stage, use HS - peraddr_write(rhport, daddr, false); - - hxfr |= HXFR_HS; - hxfr |= (ep_dir ? 0 : HXFR_OUT_NIN); - hxfr_write(rhport, hxfr, false); - return true; - } - } + if ( ep_num == 0 ) { + ep->data_toggle = 1; + } + // carry out transfer if not busy + if ( !atomic_flag_test_and_set(&_hcd_data.busy) ) { xact_inout(rhport, ep, true, false); } @@ -683,6 +666,8 @@ bool hcd_setup_send(uint8_t rhport, uint8_t daddr, uint8_t const setup_packet[8] (void) rhport; max3421_ep_t* ep = find_opened_ep(daddr, 0, 0); + TU_ASSERT(ep); + ep->ep_dir = 0; ep->total_len = 8; ep->xferred_len = 0; @@ -703,6 +688,26 @@ bool hcd_edpt_clear_stall(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr) { return false; } +//--------------------------------------------------------------------+ +// Interrupt Handler +//--------------------------------------------------------------------+ + +static void xfer_complete_isr(uint8_t rhport, max3421_ep_t *ep, xfer_result_t result, uint8_t data_toggle) { + uint8_t const ep_addr = tu_edpt_addr(ep->ep_num, ep->ep_dir); + ep->data_toggle = data_toggle; + ep->xfer_pending = 0; + hcd_event_xfer_complete(ep->daddr, ep_addr, ep->xferred_len, result, true); + + // Find next pending endpoint + max3421_ep_t *next_ep = find_next_pending_ep(ep); + if (next_ep) { + xact_inout(rhport, next_ep, true, true); + }else { + // no more pending + atomic_flag_clear(&_hcd_data.busy); + } +} + static void handle_xfer_done(uint8_t rhport) { uint8_t const hrsl = reg_read(rhport, HRSL_ADDR, true); uint8_t const hresult = hrsl & HRSL_RESULT_MASK; @@ -739,7 +744,7 @@ static void handle_xfer_done(uint8_t rhport) { max3421_ep_t *next_ep = find_next_pending_ep(ep); if (ep == next_ep) { - // only one pending, retry immediately + // this endpoint is only one pending, retry immediately hxfr_write(rhport, _hcd_data.hxfr, true); }else if (next_ep) { // switch to next pending TODO could have issue with double buffered if not clear previously out data @@ -763,7 +768,6 @@ static void handle_xfer_done(uint8_t rhport) { if ( ep->xfer_complete ) { uint8_t const dt = (hrsl & HRSL_RCVTOGRD) ? 1 : 0; // save data toggle xfer_complete_isr(rhport, ep, xfer_result, dt); - hcd_event_xfer_complete(_hcd_data.peraddr, TUSB_DIR_IN_MASK | ep_num, ep->xferred_len, xfer_result, true); }else { // more to transfer hxfr_write(rhport, _hcd_data.hxfr, true); @@ -786,8 +790,8 @@ static void handle_xfer_done(uint8_t rhport) { if (xact_len < ep->packet_size || ep->xferred_len >= ep->total_len) { uint8_t const dt = (hrsl & HRSL_SNDTOGRD) ? 1 : 0; // save data toggle xfer_complete_isr(rhport, ep, xfer_result, dt); - hcd_event_xfer_complete(_hcd_data.peraddr, ep_num, ep->xferred_len, xfer_result, true); } else { + // more to transfer xact_out(rhport, ep, false, true); } } From 3740a3287ad5965df34639e90bfa890b36c0fd60 Mon Sep 17 00:00:00 2001 From: hathach Date: Tue, 29 Aug 2023 18:22:21 +0700 Subject: [PATCH 19/34] - correct tuh_max3421e_int_api() for nrf52 - hcd_int_disable/enable is software only to reduce interrupt lag --- hw/bsp/nrf/boards/pca10056/board.h | 9 +++ hw/bsp/nrf/family.c | 20 +++++- src/portable/analog/max3421/hcd_max3421.c | 86 ++++++++++++++++------- 3 files changed, 87 insertions(+), 28 deletions(-) diff --git a/hw/bsp/nrf/boards/pca10056/board.h b/hw/bsp/nrf/boards/pca10056/board.h index f4368f8309..16d31addb8 100644 --- a/hw/bsp/nrf/boards/pca10056/board.h +++ b/hw/bsp/nrf/boards/pca10056/board.h @@ -31,6 +31,8 @@ extern "C" { #endif +#define _PINNUM(port, pin) ((port)*32 + (pin)) + // LED #define LED_PIN 13 #define LED_STATE_ON 0 @@ -43,6 +45,13 @@ #define UART_RX_PIN 8 #define UART_TX_PIN 6 +// SPI for USB host shield +#define MAX3421E_SCK_PIN _PINNUM(1, 15) +#define MAX3421E_MOSI_PIN _PINNUM(1, 13) +#define MAX3421E_MISO_PIN _PINNUM(1, 14) +#define MAX3421E_CS_PIN _PINNUM(1, 12) +#define MAX3241E_INTR_PIN _PINNUM(1, 11) + #ifdef __cplusplus } #endif diff --git a/hw/bsp/nrf/family.c b/hw/bsp/nrf/family.c index 368763b841..083efc235c 100644 --- a/hw/bsp/nrf/family.c +++ b/hw/bsp/nrf/family.c @@ -107,7 +107,12 @@ void max3421e_int_handler(nrfx_gpiote_pin_t pin, nrf_gpiote_polarity_t action) { //--------------------------------------------------------------------+ void tuh_max3421e_int_api(uint8_t rhport, bool enabled) { (void) rhport; - nrfx_gpiote_trigger_enable(MAX3241E_INTR_PIN, enabled); + + if (enabled) { + nrfx_gpiote_trigger_enable(MAX3241E_INTR_PIN, true); + }else { + nrfx_gpiote_trigger_disable(MAX3241E_INTR_PIN); + } } void tuh_max3421_spi_cs_api(uint8_t rhport, bool active) { @@ -217,6 +222,19 @@ void board_init(void) { #endif #if CFG_TUH_ENABLED && defined(CFG_TUH_MAX3421) && CFG_TUH_MAX3421 + // MAX3421 need 3.3v signal + if ((NRF_UICR->REGOUT0 & UICR_REGOUT0_VOUT_Msk) != UICR_REGOUT0_VOUT_3V3) { + NRF_NVMC->CONFIG = NVMC_CONFIG_WEN_Wen << NVMC_CONFIG_WEN_Pos; + while (NRF_NVMC->READY == NVMC_READY_READY_Busy){} + + NRF_UICR->REGOUT0 = (NRF_UICR->REGOUT0 & ~UICR_REGOUT0_VOUT_Msk) | UICR_REGOUT0_VOUT_3V3; + + NRF_NVMC->CONFIG = NVMC_CONFIG_WEN_Ren << NVMC_CONFIG_WEN_Pos; + while (NRF_NVMC->READY == NVMC_READY_READY_Busy){} + + NVIC_SystemReset(); + } + // manually manage CS nrf_gpio_cfg_output(MAX3421E_CS_PIN); tuh_max3421_spi_cs_api(0, false); diff --git a/src/portable/analog/max3421/hcd_max3421.c b/src/portable/analog/max3421/hcd_max3421.c index 262dbca0fc..cb79119925 100644 --- a/src/portable/analog/max3421/hcd_max3421.c +++ b/src/portable/analog/max3421/hcd_max3421.c @@ -184,8 +184,6 @@ typedef struct { } max3421_ep_t; typedef struct { - atomic_flag busy; // busy transferring - // cached register uint8_t sndbc; uint8_t hirq; @@ -194,7 +192,10 @@ typedef struct { uint8_t peraddr; uint8_t hxfr; + atomic_flag busy; // busy transferring + volatile uint8_t intr_disable_count; volatile uint16_t frame_count; + max3421_ep_t ep[CFG_TUH_MAX3421_ENDPOINT_TOTAL]; // [0] is reserved for addr0 OSAL_MUTEX_DEF(spi_mutexdef); @@ -220,8 +221,8 @@ void tuh_max3421e_int_api(uint8_t rhport, bool enabled); static void max3421_spi_lock(uint8_t rhport, bool in_isr) { // disable interrupt and mutex lock (for pre-emptive RTOS) if not in_isr if (!in_isr) { - tuh_max3421e_int_api(rhport, false); (void) osal_mutex_lock(_hcd_data.spi_mutex, OSAL_TIMEOUT_WAIT_FOREVER); + tuh_max3421e_int_api(rhport, false); } // assert CS @@ -294,6 +295,12 @@ static uint8_t reg_read(uint8_t rhport, uint8_t reg, bool in_isr) { return ret ? rx_buf[1] : 0; } +static inline void hirq_write(uint8_t rhport, uint8_t data, bool in_isr) { + reg_write(rhport, HIRQ_ADDR, data, in_isr); + // HIRQ write 1 is clear + _hcd_data.hirq &= ~data; +} + static inline void hien_write(uint8_t rhport, uint8_t data, bool in_isr) { _hcd_data.hien = data; reg_write(rhport, HIEN_ADDR, data, in_isr); @@ -440,13 +447,14 @@ tusb_speed_t handle_connect_irq(uint8_t rhport) { bool hcd_init(uint8_t rhport) { (void) rhport; - hcd_int_disable(rhport); + tuh_max3421e_int_api(rhport, false); tuh_max3421_spi_cs_api(rhport, false); TU_LOG2_INT(sizeof(max3421_ep_t)); TU_LOG2_INT(sizeof(max3421_data_t)); tu_memclr(&_hcd_data, sizeof(_hcd_data)); + _hcd_data.peraddr = 0xff; // invalid #if OSAL_MUTEX_REQUIRED _hcd_data.spi_mutex = osal_mutex_create(&_hcd_data.spi_mutexdef); @@ -469,11 +477,13 @@ bool hcd_init(uint8_t rhport) { reg_write(rhport, HCTL_ADDR, HCTL_BUSRST | HCTL_FRMRST, false); // clear all previously pending IRQ - reg_write(rhport, HIRQ_ADDR, 0xff, false); + hirq_write(rhport, 0xff, false); // Enable IRQ hien_write(rhport, DEFAULT_HIEN, false); + tuh_max3421e_int_api(rhport, true); + // Enable Interrupt pin reg_write(rhport, CPUCTL_ADDR, CPUCTL_IE, false); @@ -481,13 +491,21 @@ bool hcd_init(uint8_t rhport) { } // Enable USB interrupt +// Not actually enable GPIO interrupt, just set variable to prevent handler to process void hcd_int_enable (uint8_t rhport) { - tuh_max3421e_int_api(rhport, true); + (void) rhport; + // tuh_max3421e_int_api(rhport, true); + if (_hcd_data.intr_disable_count) { + _hcd_data.intr_disable_count--; + } } // Disable USB interrupt +// Not actually disable GPIO interrupt, just set variable to prevent handler to process void hcd_int_disable(uint8_t rhport) { - tuh_max3421e_int_api(rhport, false); + (void) rhport; + //tuh_max3421e_int_api(rhport, false); + _hcd_data.intr_disable_count++; } // Get frame number (1ms) @@ -521,7 +539,7 @@ void hcd_port_reset_end(uint8_t rhport) { reg_write(rhport, HCTL_ADDR, 0, false); // Bus reset will also trigger CONDET IRQ, clear and re-enable it after reset - reg_write(rhport, HIRQ_ADDR, HIRQ_CONDET_IRQ, false); + hirq_write(rhport, HIRQ_CONDET_IRQ, false); hien_write(rhport, DEFAULT_HIEN, false); } @@ -572,19 +590,23 @@ bool hcd_edpt_open(uint8_t rhport, uint8_t daddr, tusb_desc_endpoint_t const * e void xact_out(uint8_t rhport, max3421_ep_t *ep, bool switch_ep, bool in_isr) { // Page 12: Programming BULK-OUT Transfers // TODO double buffered - if (switch_ep) { - peraddr_write(rhport, ep->daddr, in_isr); - - uint8_t const hctl = (ep->data_toggle ? HCTL_SNDTOG1 : HCTL_SNDTOG0); - reg_write(rhport, HCTL_ADDR, hctl, in_isr); - } uint8_t hxfr = ep->ep_num | HXFR_OUT_NIN | (ep->is_iso ? HXFR_ISO : 0); - if (ep->ep_num == 0 && (ep->buf == NULL || ep->total_len == 0)) { // Control ZLP status use HS hxfr |= HXFR_HS; - } else { + } + + if (switch_ep) { + peraddr_write(rhport, ep->daddr, in_isr); + + if ( 0 == (hxfr & HXFR_HS) ) { + uint8_t const hctl = (ep->data_toggle ? HCTL_SNDTOG1 : HCTL_SNDTOG0); + reg_write(rhport, HCTL_ADDR, hctl, in_isr); + } + } + + if ( 0 == (hxfr & HXFR_HS) ) { uint8_t const xact_len = (uint8_t) tu_min16(ep->total_len - ep->xferred_len, ep->packet_size); TU_ASSERT(_hcd_data.hirq & HIRQ_SNDBAV_IRQ,); if (xact_len) { @@ -598,12 +620,6 @@ void xact_out(uint8_t rhport, max3421_ep_t *ep, bool switch_ep, bool in_isr) { void xact_in(uint8_t rhport, max3421_ep_t *ep, bool switch_ep, bool in_isr) { // Page 13: Programming BULK-IN Transfers - if (switch_ep) { - peraddr_write(rhport, ep->daddr, in_isr); - - uint8_t const hctl = (ep->data_toggle ? HCTL_RCVTOG1 : HCTL_RCVTOG0); - reg_write(rhport, HCTL_ADDR, hctl, in_isr); - } uint8_t hxfr = ep->ep_num | (ep->is_iso ? HXFR_ISO : 0); if (ep->ep_num == 0 && (ep->buf == NULL || ep->total_len == 0)) { @@ -611,6 +627,15 @@ void xact_in(uint8_t rhport, max3421_ep_t *ep, bool switch_ep, bool in_isr) { hxfr |= HXFR_HS; } + if (switch_ep) { + peraddr_write(rhport, ep->daddr, in_isr); + + if ( 0 == (hxfr & HXFR_HS) ) { + uint8_t const hctl = (ep->data_toggle ? HCTL_RCVTOG1 : HCTL_RCVTOG0); + reg_write(rhport, HCTL_ADDR, hctl, in_isr); + } + } + hxfr_write(rhport, hxfr, in_isr); } @@ -721,7 +746,7 @@ static void handle_xfer_done(uint8_t rhport) { xfer_result_t xfer_result; - //TU_LOG3("HRSL: %02X\r\n", hrsl); +// TU_LOG3("HRSL: %02X\r\n", hrsl); switch(hresult) { case HRSL_SUCCESS: xfer_result = XFER_RESULT_SUCCESS; @@ -821,13 +846,20 @@ void print_hirq(uint8_t hirq) { void hcd_int_handler(uint8_t rhport) { uint8_t hirq = reg_read(rhport, HIRQ_ADDR, true) & _hcd_data.hien; if (!hirq) return; - // print_hirq(hirq); if (hirq & HIRQ_FRAME_IRQ) { _hcd_data.frame_count++; } + // interrupt is disabled, only ack FRAME IRQ and skip the rest + if (_hcd_data.intr_disable_count) { + if (hirq & HIRQ_FRAME_IRQ) { + hirq_write(rhport, HIRQ_FRAME_IRQ, true); + } + return; + } + if (hirq & HIRQ_CONDET_IRQ) { tusb_speed_t speed = handle_connect_irq(rhport); @@ -861,7 +893,7 @@ void hcd_int_handler(uint8_t rhport) { } // ack RCVDVAV IRQ - reg_write(rhport, HIRQ_ADDR, HIRQ_RCVDAV_IRQ, true); + hirq_write(rhport, HIRQ_RCVDAV_IRQ, true); hirq = reg_read(rhport, HIRQ_ADDR, true); } @@ -871,7 +903,7 @@ void hcd_int_handler(uint8_t rhport) { } if ( hirq & HIRQ_HXFRDN_IRQ ) { - reg_write(rhport, HIRQ_ADDR, HIRQ_HXFRDN_IRQ, true); + hirq_write(rhport, HIRQ_HXFRDN_IRQ, true); handle_xfer_done(rhport); } @@ -881,7 +913,7 @@ void hcd_int_handler(uint8_t rhport) { // clear all interrupt except SNDBAV_IRQ (never clear by us). Note RCVDAV_IRQ, HXFRDN_IRQ already clear while processing hirq &= ~HIRQ_SNDBAV_IRQ; if ( hirq ) { - reg_write(rhport, HIRQ_ADDR, hirq, true); + hirq_write(rhport, hirq, true); } } From 2a814a99af32bf084cbb730d97e3c9cb31a3fa85 Mon Sep 17 00:00:00 2001 From: hathach Date: Tue, 29 Aug 2023 20:27:37 +0700 Subject: [PATCH 20/34] - hcd_setup_send() also check for busy flag - xact_inout() to support send setup --- src/portable/analog/max3421/hcd_max3421.c | 71 +++++++++++++---------- 1 file changed, 39 insertions(+), 32 deletions(-) diff --git a/src/portable/analog/max3421/hcd_max3421.c b/src/portable/analog/max3421/hcd_max3421.c index cb79119925..461e02593f 100644 --- a/src/portable/analog/max3421/hcd_max3421.c +++ b/src/portable/analog/max3421/hcd_max3421.c @@ -168,6 +168,7 @@ typedef struct { struct TU_ATTR_PACKED { uint8_t ep_dir : 1; uint8_t is_iso : 1; + uint8_t is_setup : 1; uint8_t data_toggle : 1; uint8_t xfer_pending : 1; uint8_t xfer_complete : 1; @@ -590,56 +591,55 @@ bool hcd_edpt_open(uint8_t rhport, uint8_t daddr, tusb_desc_endpoint_t const * e void xact_out(uint8_t rhport, max3421_ep_t *ep, bool switch_ep, bool in_isr) { // Page 12: Programming BULK-OUT Transfers // TODO double buffered - - uint8_t hxfr = ep->ep_num | HXFR_OUT_NIN | (ep->is_iso ? HXFR_ISO : 0); - if (ep->ep_num == 0 && (ep->buf == NULL || ep->total_len == 0)) { - // Control ZLP status use HS - hxfr |= HXFR_HS; - } - if (switch_ep) { peraddr_write(rhport, ep->daddr, in_isr); - if ( 0 == (hxfr & HXFR_HS) ) { - uint8_t const hctl = (ep->data_toggle ? HCTL_SNDTOG1 : HCTL_SNDTOG0); - reg_write(rhport, HCTL_ADDR, hctl, in_isr); - } + uint8_t const hctl = (ep->data_toggle ? HCTL_SNDTOG1 : HCTL_SNDTOG0); + reg_write(rhport, HCTL_ADDR, hctl, in_isr); } - if ( 0 == (hxfr & HXFR_HS) ) { - uint8_t const xact_len = (uint8_t) tu_min16(ep->total_len - ep->xferred_len, ep->packet_size); - TU_ASSERT(_hcd_data.hirq & HIRQ_SNDBAV_IRQ,); - if (xact_len) { - fifo_write(rhport, SNDFIFO_ADDR, ep->buf, xact_len, in_isr); - } - sndbc_write(rhport, xact_len, in_isr); + uint8_t const xact_len = (uint8_t) tu_min16(ep->total_len - ep->xferred_len, ep->packet_size); + TU_ASSERT(_hcd_data.hirq & HIRQ_SNDBAV_IRQ,); + if (xact_len) { + fifo_write(rhport, SNDFIFO_ADDR, ep->buf, xact_len, in_isr); } + sndbc_write(rhport, xact_len, in_isr); + uint8_t hxfr = ep->ep_num | HXFR_OUT_NIN | (ep->is_iso ? HXFR_ISO : 0); hxfr_write(rhport, hxfr, in_isr); } void xact_in(uint8_t rhport, max3421_ep_t *ep, bool switch_ep, bool in_isr) { // Page 13: Programming BULK-IN Transfers - - uint8_t hxfr = ep->ep_num | (ep->is_iso ? HXFR_ISO : 0); - if (ep->ep_num == 0 && (ep->buf == NULL || ep->total_len == 0)) { - // Control ZLP status use HS - hxfr |= HXFR_HS; - } - if (switch_ep) { peraddr_write(rhport, ep->daddr, in_isr); - if ( 0 == (hxfr & HXFR_HS) ) { - uint8_t const hctl = (ep->data_toggle ? HCTL_RCVTOG1 : HCTL_RCVTOG0); - reg_write(rhport, HCTL_ADDR, hctl, in_isr); - } + uint8_t const hctl = (ep->data_toggle ? HCTL_RCVTOG1 : HCTL_RCVTOG0); + reg_write(rhport, HCTL_ADDR, hctl, in_isr); } + uint8_t hxfr = ep->ep_num | (ep->is_iso ? HXFR_ISO : 0); hxfr_write(rhport, hxfr, in_isr); } TU_ATTR_ALWAYS_INLINE static inline void xact_inout(uint8_t rhport, max3421_ep_t *ep, bool switch_ep, bool in_isr) { + if (ep->ep_num == 0 ) { + // setup + if (ep->is_setup) { + peraddr_write(rhport, ep->daddr, in_isr); + hxfr_write(rhport, HXFR_SETUP, in_isr); + return; + } + + // status + if (ep->buf == NULL || ep->total_len == 0) { + uint8_t const hxfr = HXFR_HS | (ep->ep_dir ? 0 : HXFR_OUT_NIN); + peraddr_write(rhport, ep->daddr, in_isr); + hxfr_write(rhport, hxfr, in_isr); + return; + } + } + if (ep->ep_dir) { xact_in(rhport, ep, switch_ep, in_isr); }else { @@ -665,12 +665,15 @@ bool hcd_edpt_xfer(uint8_t rhport, uint8_t daddr, uint8_t ep_addr, uint8_t * buf ep->xfer_pending = 1; if ( ep_num == 0 ) { + ep->is_setup = 0; ep->data_toggle = 1; } // carry out transfer if not busy if ( !atomic_flag_test_and_set(&_hcd_data.busy) ) { xact_inout(rhport, ep, true, false); + } else { + return true; } return true; @@ -694,12 +697,16 @@ bool hcd_setup_send(uint8_t rhport, uint8_t daddr, uint8_t const setup_packet[8] TU_ASSERT(ep); ep->ep_dir = 0; - ep->total_len = 8; + ep->total_len = 8; ep->xferred_len = 0; + ep->is_setup = 1; - peraddr_write(rhport, daddr, false); fifo_write(rhport, SUDFIFO_ADDR, setup_packet, 8, false); - hxfr_write(rhport, HXFR_SETUP, false); + + // carry out transfer if not busy + if ( !atomic_flag_test_and_set(&_hcd_data.busy) ) { + xact_inout(rhport, ep, true, false); + } return true; } From 1ab488eb06ef4cb8ad9c0cff91e6b0caf76f73c4 Mon Sep 17 00:00:00 2001 From: hathach Date: Wed, 30 Aug 2023 16:04:18 +0700 Subject: [PATCH 21/34] call xfer_complete_isr() when result is not successful (stalled or failed) --- hw/bsp/nrf/boards/pca10095/board.h | 9 +++++ hw/bsp/nrf/family.c | 7 ++-- hw/bsp/nrf/nrfx_config.h | 2 +- src/common/tusb_mcu.h | 2 +- src/portable/analog/max3421/hcd_max3421.c | 43 ++++++++++++++++------- 5 files changed, 47 insertions(+), 16 deletions(-) diff --git a/hw/bsp/nrf/boards/pca10095/board.h b/hw/bsp/nrf/boards/pca10095/board.h index fd3c63d6aa..b9d3a19dc8 100644 --- a/hw/bsp/nrf/boards/pca10095/board.h +++ b/hw/bsp/nrf/boards/pca10095/board.h @@ -31,6 +31,8 @@ extern "C" { #endif +#define _PINNUM(port, pin) ((port)*32 + (pin)) + // LED #define LED_PIN 28 #define LED_STATE_ON 0 @@ -43,6 +45,13 @@ #define UART_RX_PIN 32 #define UART_TX_PIN 33 +// SPI for USB host shield +#define MAX3421E_SCK_PIN _PINNUM(1, 15) +#define MAX3421E_MOSI_PIN _PINNUM(1, 13) +#define MAX3421E_MISO_PIN _PINNUM(1, 14) +#define MAX3421E_CS_PIN _PINNUM(1, 12) +#define MAX3241E_INTR_PIN _PINNUM(1, 11) + #ifdef __cplusplus } #endif diff --git a/hw/bsp/nrf/family.c b/hw/bsp/nrf/family.c index 083efc235c..2b4260083a 100644 --- a/hw/bsp/nrf/family.c +++ b/hw/bsp/nrf/family.c @@ -34,6 +34,7 @@ #pragma GCC diagnostic ignored "-Wcast-align" #pragma GCC diagnostic ignored "-Wunused-parameter" #pragma GCC diagnostic ignored "-Wundef" +#pragma GCC diagnostic ignored "-Wredundant-decls" #endif #include "nrfx.h" @@ -94,7 +95,7 @@ TU_ATTR_UNUSED static void power_event_handler(nrfx_power_usb_evt_t event) { //------------- Host using MAX2341E -------------// #if CFG_TUH_ENABLED && defined(CFG_TUH_MAX3421) && CFG_TUH_MAX3421 -static nrfx_spim_t _spi = NRFX_SPIM_INSTANCE(0); +static nrfx_spim_t _spi = NRFX_SPIM_INSTANCE(1); void max3421e_int_handler(nrfx_gpiote_pin_t pin, nrf_gpiote_polarity_t action) { if ( !(pin == MAX3241E_INTR_PIN && action == NRF_GPIOTE_POLARITY_HITOLO) ) return; @@ -222,7 +223,8 @@ void board_init(void) { #endif #if CFG_TUH_ENABLED && defined(CFG_TUH_MAX3421) && CFG_TUH_MAX3421 - // MAX3421 need 3.3v signal + // MAX3421 need 3.3v signal (may not be needed) + #if defined(UICR_REGOUT0_VOUT_Msk) && 0 if ((NRF_UICR->REGOUT0 & UICR_REGOUT0_VOUT_Msk) != UICR_REGOUT0_VOUT_3V3) { NRF_NVMC->CONFIG = NVMC_CONFIG_WEN_Wen << NVMC_CONFIG_WEN_Pos; while (NRF_NVMC->READY == NVMC_READY_READY_Busy){} @@ -234,6 +236,7 @@ void board_init(void) { NVIC_SystemReset(); } + #endif // manually manage CS nrf_gpio_cfg_output(MAX3421E_CS_PIN); diff --git a/hw/bsp/nrf/nrfx_config.h b/hw/bsp/nrf/nrfx_config.h index e3d0ea91b0..95ef33ce42 100644 --- a/hw/bsp/nrf/nrfx_config.h +++ b/hw/bsp/nrf/nrfx_config.h @@ -11,7 +11,7 @@ #define NRFX_UARTE0_ENABLED 1 #define NRFX_SPIM_ENABLED 1 -#define NRFX_SPIM0_ENABLED 1 +#define NRFX_SPIM1_ENABLED 1 // use SPI1 since nrf5340 share uart with spi #define NRFX_PRS_ENABLED 0 #define NRFX_USBREG_ENABLED 1 diff --git a/src/common/tusb_mcu.h b/src/common/tusb_mcu.h index 21939df7c6..8807ff8aa0 100644 --- a/src/common/tusb_mcu.h +++ b/src/common/tusb_mcu.h @@ -390,7 +390,7 @@ // External USB controller //--------------------------------------------------------------------+ -#if defined(CFG_TUH_MAX3421) & CFG_TUH_MAX3421 +#if defined(CFG_TUH_MAX3421) && CFG_TUH_MAX3421 #ifndef CFG_TUH_MAX3421_ENDPOINT_TOTAL #define CFG_TUH_MAX3421_ENDPOINT_TOTAL (8 + 4*(CFG_TUH_DEVICE_MAX-1)) #endif diff --git a/src/portable/analog/max3421/hcd_max3421.c b/src/portable/analog/max3421/hcd_max3421.c index 461e02593f..705bb5bfd3 100644 --- a/src/portable/analog/max3421/hcd_max3421.c +++ b/src/portable/analog/max3421/hcd_max3421.c @@ -374,7 +374,8 @@ static max3421_ep_t * find_next_pending_ep(max3421_ep_t * cur_ep) { // starting from next endpoint for (size_t i = idx + 1; i < CFG_TUH_MAX3421_ENDPOINT_TOTAL; i++) { max3421_ep_t* ep = &_hcd_data.ep[i]; - if (ep->xfer_pending) { + if (ep->xfer_pending && ep->packet_size) { +// TU_LOG3("next pending i = %u\n", i); return ep; } } @@ -382,7 +383,8 @@ static max3421_ep_t * find_next_pending_ep(max3421_ep_t * cur_ep) { // wrap around including current endpoint for (size_t i = 0; i <= idx; i++) { max3421_ep_t* ep = &_hcd_data.ep[i]; - if (ep->xfer_pending) { + if (ep->xfer_pending && ep->packet_size) { +// TU_LOG3("next pending i = %u\n", i); return ep; } } @@ -464,6 +466,10 @@ bool hcd_init(uint8_t rhport) { // full duplex, interrupt negative edge reg_write(rhport, PINCTL_ADDR, PINCTL_FDUPSPI, false); + // V1 is 0x01, V2 is 0x12, V3 is 0x13 + // uint8_t const revision = reg_read(rhport, REVISION_ADDR, false); + // TU_LOG2_HEX(revision); + // reset reg_write(rhport, USBCTL_ADDR, USBCTL_CHIPRES, false); reg_write(rhport, USBCTL_ADDR, 0, false); @@ -699,6 +705,7 @@ bool hcd_setup_send(uint8_t rhport, uint8_t daddr, uint8_t const setup_packet[8] ep->ep_dir = 0; ep->total_len = 8; ep->xferred_len = 0; + ep->xfer_pending = 1; ep->is_setup = 1; fifo_write(rhport, SUDFIFO_ADDR, setup_packet, 8, false); @@ -724,9 +731,16 @@ bool hcd_edpt_clear_stall(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr) { // Interrupt Handler //--------------------------------------------------------------------+ -static void xfer_complete_isr(uint8_t rhport, max3421_ep_t *ep, xfer_result_t result, uint8_t data_toggle) { +static void xfer_complete_isr(uint8_t rhport, max3421_ep_t *ep, xfer_result_t result, uint8_t hrsl) { uint8_t const ep_addr = tu_edpt_addr(ep->ep_num, ep->ep_dir); - ep->data_toggle = data_toggle; + + // save data toggle + if (ep->ep_dir) { + ep->data_toggle = (hrsl & HRSL_RCVTOGRD) ? 1 : 0; + }else { + ep->data_toggle = (hrsl & HRSL_SNDTOGRD) ? 1 : 0; + } + ep->xfer_pending = 0; hcd_event_xfer_complete(ep->daddr, ep_addr, ep->xferred_len, result, true); @@ -763,10 +777,6 @@ static void handle_xfer_done(uint8_t rhport) { xfer_result = XFER_RESULT_STALLED; break; - case HRSL_BAD_REQ: - // occurred when initialized without any pending transfer. Skip for now - return; - case HRSL_NAK: if (ep_num == 0) { // NAK on control, retry immediately @@ -781,15 +791,26 @@ static void handle_xfer_done(uint8_t rhport) { }else if (next_ep) { // switch to next pending TODO could have issue with double buffered if not clear previously out data xact_inout(rhport, next_ep, true, true); + }else { + TU_ASSERT(false,); } } return; + case HRSL_BAD_REQ: + // occurred when initialized without any pending transfer. Skip for now + return; + default: xfer_result = XFER_RESULT_FAILED; break; } + if (xfer_result != XFER_RESULT_SUCCESS) { + xfer_complete_isr(rhport, ep, xfer_result, hrsl); + return; + } + if (ep_dir) { // IN transfer: fifo data is already received in RCVDAV IRQ if ( hxfr_type & HXFR_HS ) { @@ -798,8 +819,7 @@ static void handle_xfer_done(uint8_t rhport) { // short packet or all bytes transferred if ( ep->xfer_complete ) { - uint8_t const dt = (hrsl & HRSL_RCVTOGRD) ? 1 : 0; // save data toggle - xfer_complete_isr(rhport, ep, xfer_result, dt); + xfer_complete_isr(rhport, ep, xfer_result, hrsl); }else { // more to transfer hxfr_write(rhport, _hcd_data.hxfr, true); @@ -820,8 +840,7 @@ static void handle_xfer_done(uint8_t rhport) { ep->buf += xact_len; if (xact_len < ep->packet_size || ep->xferred_len >= ep->total_len) { - uint8_t const dt = (hrsl & HRSL_SNDTOGRD) ? 1 : 0; // save data toggle - xfer_complete_isr(rhport, ep, xfer_result, dt); + xfer_complete_isr(rhport, ep, xfer_result, hrsl); } else { // more to transfer xact_out(rhport, ep, false, true); From 41493426b38c8ce44b1f7720b907538bc5402f98 Mon Sep 17 00:00:00 2001 From: hathach Date: Wed, 30 Aug 2023 16:21:43 +0700 Subject: [PATCH 22/34] use ep buf to keep setup packet, work well with hid device --- examples/host/msc_file_explorer/src/tusb_config.h | 2 +- src/portable/analog/max3421/hcd_max3421.c | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/examples/host/msc_file_explorer/src/tusb_config.h b/examples/host/msc_file_explorer/src/tusb_config.h index 28e130c0e5..e6186ba46f 100644 --- a/examples/host/msc_file_explorer/src/tusb_config.h +++ b/examples/host/msc_file_explorer/src/tusb_config.h @@ -37,7 +37,7 @@ #if CFG_TUSB_MCU == OPT_MCU_RP2040 // change to 1 if using pico-pio-usb as host controller for raspberry rp2040 #define CFG_TUH_RPI_PIO_USB 0 - #define BOARD_TUH_RHPORT CFG_TUH_RPI_PIO_US + #define BOARD_TUH_RHPORT CFG_TUH_RPI_PIO_USB //#elif CFG_TUSB_MCU == OPT_MCU_NRF5X // // Use external USB controller (via SPI) MAX3421E (aka usb host shield) // #define CFG_TUH_MAX3421 1 diff --git a/src/portable/analog/max3421/hcd_max3421.c b/src/portable/analog/max3421/hcd_max3421.c index 705bb5bfd3..d644390da8 100644 --- a/src/portable/analog/max3421/hcd_max3421.c +++ b/src/portable/analog/max3421/hcd_max3421.c @@ -633,6 +633,7 @@ TU_ATTR_ALWAYS_INLINE static inline void xact_inout(uint8_t rhport, max3421_ep_t // setup if (ep->is_setup) { peraddr_write(rhport, ep->daddr, in_isr); + fifo_write(rhport, SUDFIFO_ADDR, ep->buf, 8, in_isr); hxfr_write(rhport, HXFR_SETUP, in_isr); return; } @@ -703,12 +704,12 @@ bool hcd_setup_send(uint8_t rhport, uint8_t daddr, uint8_t const setup_packet[8] TU_ASSERT(ep); ep->ep_dir = 0; + ep->is_setup = 1; + ep->buf = (uint8_t*)(uintptr_t) setup_packet; ep->total_len = 8; ep->xferred_len = 0; + ep->xfer_complete = 0; ep->xfer_pending = 1; - ep->is_setup = 1; - - fifo_write(rhport, SUDFIFO_ADDR, setup_packet, 8, false); // carry out transfer if not busy if ( !atomic_flag_test_and_set(&_hcd_data.busy) ) { From 3b7d5aa0421f3d3a7ac199de0138dc40141fbddd Mon Sep 17 00:00:00 2001 From: hathach Date: Thu, 31 Aug 2023 16:52:09 +0700 Subject: [PATCH 23/34] improve connection & disconnection detection. But there is still issue when CONDETIRQ occurs but we are disabled interrupt (for osal queue access). --- hw/bsp/board.c | 26 +++---- hw/bsp/nrf/family.c | 49 ++++++------- src/host/usbh.c | 2 +- src/portable/analog/max3421/hcd_max3421.c | 85 +++++++++++------------ 4 files changed, 72 insertions(+), 90 deletions(-) diff --git a/hw/bsp/board.c b/hw/bsp/board.c index 417630a03e..5627926257 100644 --- a/hw/bsp/board.c +++ b/hw/bsp/board.c @@ -44,17 +44,16 @@ // If using SES IDE, use the Syscalls/SEGGER_RTT_Syscalls_SES.c instead #if !(defined __SES_ARM) && !(defined __SES_RISCV) && !(defined __CROSSWORKS_ARM) + #include "SEGGER_RTT.h" -TU_ATTR_USED int sys_write (int fhdl, const void *buf, size_t count) -{ +TU_ATTR_USED int sys_write(int fhdl, const void *buf, size_t count) { (void) fhdl; - SEGGER_RTT_Write(0, (const char*) buf, (int) count); + SEGGER_RTT_Write(0, (const char *) buf, (int) count); return count; } -TU_ATTR_USED int sys_read (int fhdl, char *buf, size_t count) -{ +TU_ATTR_USED int sys_read(int fhdl, char *buf, size_t count) { (void) fhdl; int rd = (int) SEGGER_RTT_Read(0, buf, count); return (rd > 0) ? rd : -1; @@ -67,8 +66,7 @@ TU_ATTR_USED int sys_read (int fhdl, char *buf, size_t count) #include "board_mcu.h" -TU_ATTR_USED int sys_write (int fhdl, const void *buf, size_t count) -{ +TU_ATTR_USED int sys_write (int fhdl, const void *buf, size_t count) { (void) fhdl; uint8_t const* buf8 = (uint8_t const*) buf; @@ -79,8 +77,7 @@ TU_ATTR_USED int sys_write (int fhdl, const void *buf, size_t count) return (int) count; } -TU_ATTR_USED int sys_read (int fhdl, char *buf, size_t count) -{ +TU_ATTR_USED int sys_read (int fhdl, char *buf, size_t count) { (void) fhdl; (void) buf; (void) count; @@ -90,14 +87,12 @@ TU_ATTR_USED int sys_read (int fhdl, char *buf, size_t count) #else // Default logging with on-board UART -TU_ATTR_USED int sys_write (int fhdl, const void *buf, size_t count) -{ +TU_ATTR_USED int sys_write (int fhdl, const void *buf, size_t count) { (void) fhdl; return board_uart_write(buf, (int) count); } -TU_ATTR_USED int sys_read (int fhdl, char *buf, size_t count) -{ +TU_ATTR_USED int sys_read (int fhdl, char *buf, size_t count) { (void) fhdl; int rd = board_uart_read((uint8_t*) buf, (int) count); return (rd > 0) ? rd : -1; @@ -105,8 +100,7 @@ TU_ATTR_USED int sys_read (int fhdl, char *buf, size_t count) #endif -int board_getchar(void) -{ +int board_getchar(void) { char c; - return ( sys_read(0, &c, 1) > 0 ) ? (int) c : (-1); + return (sys_read(0, &c, 1) > 0) ? (int) c : (-1); } diff --git a/hw/bsp/nrf/family.c b/hw/bsp/nrf/family.c index 2b4260083a..7358458ce7 100644 --- a/hw/bsp/nrf/family.c +++ b/hw/bsp/nrf/family.c @@ -98,7 +98,7 @@ TU_ATTR_UNUSED static void power_event_handler(nrfx_power_usb_evt_t event) { static nrfx_spim_t _spi = NRFX_SPIM_INSTANCE(1); void max3421e_int_handler(nrfx_gpiote_pin_t pin, nrf_gpiote_polarity_t action) { - if ( !(pin == MAX3241E_INTR_PIN && action == NRF_GPIOTE_POLARITY_HITOLO) ) return; + if (!(pin == MAX3241E_INTR_PIN && action == NRF_GPIOTE_POLARITY_HITOLO)) return; tuh_int_handler(1); } @@ -111,7 +111,7 @@ void tuh_max3421e_int_api(uint8_t rhport, bool enabled) { if (enabled) { nrfx_gpiote_trigger_enable(MAX3241E_INTR_PIN, true); - }else { + } else { nrfx_gpiote_trigger_disable(MAX3241E_INTR_PIN); } } @@ -121,7 +121,7 @@ void tuh_max3421_spi_cs_api(uint8_t rhport, bool active) { nrf_gpio_pin_write(MAX3421E_CS_PIN, active ? 0 : 1); } -bool tuh_max3421_spi_xfer_api(uint8_t rhport, uint8_t const * tx_buf, size_t tx_len, uint8_t * rx_buf, size_t rx_len) { +bool tuh_max3421_spi_xfer_api(uint8_t rhport, uint8_t const *tx_buf, size_t tx_len, uint8_t *rx_buf, size_t rx_len) { (void) rhport; nrfx_spim_xfer_desc_t xfer = { @@ -157,21 +157,21 @@ void board_init(void) { nrf_gpio_cfg_input(BUTTON_PIN, NRF_GPIO_PIN_PULLUP); // 1ms tick timer - SysTick_Config(SystemCoreClock/1000); + SysTick_Config(SystemCoreClock / 1000); // UART nrfx_uarte_config_t uart_cfg = { - .pseltxd = UART_TX_PIN, - .pselrxd = UART_RX_PIN, - .pselcts = NRF_UARTE_PSEL_DISCONNECTED, - .pselrts = NRF_UARTE_PSEL_DISCONNECTED, - .p_context = NULL, - .baudrate = NRF_UARTE_BAUDRATE_115200, // CFG_BOARD_UART_BAUDRATE - .interrupt_priority = 7, - .hal_cfg = { - .hwfc = NRF_UARTE_HWFC_DISABLED, - .parity = NRF_UARTE_PARITY_EXCLUDED, - } + .pseltxd = UART_TX_PIN, + .pselrxd = UART_RX_PIN, + .pselcts = NRF_UARTE_PSEL_DISCONNECTED, + .pselrts = NRF_UARTE_PSEL_DISCONNECTED, + .p_context = NULL, + .baudrate = NRF_UARTE_BAUDRATE_115200, // CFG_BOARD_UART_BAUDRATE + .interrupt_priority = 7, + .hal_cfg = { + .hwfc = NRF_UARTE_HWFC_DISABLED, + .parity = NRF_UARTE_PARITY_EXCLUDED, + } }; nrfx_uarte_init(&_uart_id, &uart_cfg, NULL); //uart_handler); @@ -211,11 +211,11 @@ void board_init(void) { // USB power may already be ready at this time -> no event generated // We need to invoke the handler based on the status initially - #ifdef NRF5340_XXAA +#ifdef NRF5340_XXAA usb_reg = NRF_USBREGULATOR->USBREGSTATUS; - #else +#else usb_reg = NRF_POWER->USBREGSTATUS; - #endif +#endif } if ( usb_reg & VBUSDETECT_Msk ) tusb_hal_nrf_power_event(USB_EVT_DETECTED); @@ -308,8 +308,7 @@ uint32_t board_millis(void) { #ifdef SOFTDEVICE_PRESENT // process SOC event from SD -uint32_t proc_soc(void) -{ +uint32_t proc_soc(void) { uint32_t soc_evt; uint32_t err = sd_evt_get(&soc_evt); @@ -326,18 +325,14 @@ uint32_t proc_soc(void) return err; } -uint32_t proc_ble(void) -{ +uint32_t proc_ble(void) { // do nothing with ble return NRF_ERROR_NOT_FOUND; } -void SD_EVT_IRQHandler(void) -{ +void SD_EVT_IRQHandler(void) { // process BLE and SOC until there is no more events - while( (NRF_ERROR_NOT_FOUND != proc_ble()) || (NRF_ERROR_NOT_FOUND != proc_soc()) ) - { - + while( (NRF_ERROR_NOT_FOUND != proc_ble()) || (NRF_ERROR_NOT_FOUND != proc_soc()) ) { } } diff --git a/src/host/usbh.c b/src/host/usbh.c index 12a7f58393..bacb3a7192 100644 --- a/src/host/usbh.c +++ b/src/host/usbh.c @@ -852,7 +852,7 @@ bool usbh_edpt_xfer_with_callback(uint8_t dev_addr, uint8_t ep_addr, uint8_t * b ep_state->busy = 0; ep_state->claimed = 0; TU_LOG1("Failed\r\n"); - TU_BREAKPOINT(); +// TU_BREAKPOINT(); return false; } } diff --git a/src/portable/analog/max3421/hcd_max3421.c b/src/portable/analog/max3421/hcd_max3421.c index d644390da8..56d3aea45a 100644 --- a/src/portable/analog/max3421/hcd_max3421.c +++ b/src/portable/analog/max3421/hcd_max3421.c @@ -405,45 +405,46 @@ bool hcd_configure(uint8_t rhport, uint32_t cfg_id, const void* cfg_param) { return false; } -tusb_speed_t handle_connect_irq(uint8_t rhport) { +static void handle_connect_irq(uint8_t rhport) { uint8_t const hrsl = reg_read(rhport, HRSL_ADDR, true); uint8_t const jk = hrsl & (HRSL_JSTATUS | HRSL_KSTATUS); - tusb_speed_t speed; uint8_t new_mode = MODE_DPPULLDN | MODE_DMPULLDN | MODE_HOST; + TU_LOG2_HEX(jk); switch(jk) { - case 0x00: - // SEO is disconnected - speed = TUSB_SPEED_INVALID; - break; - - case (HRSL_JSTATUS | HRSL_KSTATUS): - // SE1 is illegal - speed = TUSB_SPEED_INVALID; + case 0x00: // SEO is disconnected + case (HRSL_JSTATUS | HRSL_KSTATUS): // SE1 is illegal + mode_write(rhport, new_mode, true); + hcd_event_device_remove(rhport, true); break; default: { - // Low speed if (LS = 1 and J-state) or (LS = 0 and K-State) - uint8_t const mode = reg_read(rhport, MODE_ADDR, true); - uint8_t const ls_bit = mode & MODE_LOWSPEED; + // Bus Reset also cause CONDET IRQ, skip if we are already connected and doing bus reset + if ((_hcd_data.hirq & HIRQ_BUSEVENT_IRQ) && (_hcd_data.mode & MODE_SOFKAENAB)) { + break; + } - if ( (ls_bit && (jk == HRSL_JSTATUS)) || (!ls_bit && (jk == HRSL_KSTATUS)) ) { - speed = TUSB_SPEED_LOW; + // Low speed if (LS = 1 and J-state) or (LS = 0 and K-State) + // However, since we are always in full speed mode, we can just check J-state + if (jk == HRSL_KSTATUS) { new_mode |= MODE_LOWSPEED; - } else { - speed = TUSB_SPEED_FULL; + TU_LOG3("Low speed\n"); + }else { + TU_LOG3("Full speed\n"); } + new_mode |= MODE_SOFKAENAB; + mode_write(rhport, new_mode, true); - new_mode |= MODE_SOFKAENAB; // enable SOF since there is new device + // FIXME multiple MAX3421 rootdevice address is not 1 + uint8_t const daddr = 1; + free_ep(daddr); + + hcd_event_device_attach(rhport, true); break; } } - - mode_write(rhport, new_mode, true); - TU_LOG2_INT(speed); - return speed; } // Initialize controller to host mode @@ -500,8 +501,9 @@ bool hcd_init(uint8_t rhport) { // Enable USB interrupt // Not actually enable GPIO interrupt, just set variable to prevent handler to process void hcd_int_enable (uint8_t rhport) { +// tuh_max3421e_int_api(rhport, true); + (void) rhport; - // tuh_max3421e_int_api(rhport, true); if (_hcd_data.intr_disable_count) { _hcd_data.intr_disable_count--; } @@ -510,8 +512,8 @@ void hcd_int_enable (uint8_t rhport) { // Disable USB interrupt // Not actually disable GPIO interrupt, just set variable to prevent handler to process void hcd_int_disable(uint8_t rhport) { - (void) rhport; //tuh_max3421e_int_api(rhport, false); + (void) rhport; _hcd_data.intr_disable_count++; } @@ -534,20 +536,12 @@ bool hcd_port_connect_status(uint8_t rhport) { // Reset USB bus on the port. Return immediately, bus reset sequence may not be complete. // Some port would require hcd_port_reset_end() to be invoked after 10ms to complete the reset sequence. void hcd_port_reset(uint8_t rhport) { - // Bus reset will also trigger CONDET IRQ, disable it - uint8_t const hien = DEFAULT_HIEN & ~HIRQ_CONDET_IRQ; - hien_write(rhport, hien, false); - reg_write(rhport, HCTL_ADDR, HCTL_BUSRST, false); } // Complete bus reset sequence, may be required by some controllers void hcd_port_reset_end(uint8_t rhport) { reg_write(rhport, HCTL_ADDR, 0, false); - - // Bus reset will also trigger CONDET IRQ, clear and re-enable it after reset - hirq_write(rhport, HIRQ_CONDET_IRQ, false); - hien_write(rhport, DEFAULT_HIEN, false); } // Get port link speed @@ -660,7 +654,7 @@ bool hcd_edpt_xfer(uint8_t rhport, uint8_t daddr, uint8_t ep_addr, uint8_t * buf uint8_t const ep_dir = tu_edpt_dir(ep_addr); max3421_ep_t* ep = find_opened_ep(daddr, ep_num, ep_dir); - TU_ASSERT(ep); + TU_VERIFY(ep); // control transfer can switch direction ep->ep_dir = ep_dir; @@ -767,8 +761,6 @@ static void handle_xfer_done(uint8_t rhport) { TU_ASSERT(ep, ); xfer_result_t xfer_result; - -// TU_LOG3("HRSL: %02X\r\n", hrsl); switch(hresult) { case HRSL_SUCCESS: xfer_result = XFER_RESULT_SUCCESS; @@ -803,6 +795,7 @@ static void handle_xfer_done(uint8_t rhport) { return; default: + TU_LOG3("HRSL: %02X\r\n", hrsl); xfer_result = XFER_RESULT_FAILED; break; } @@ -875,30 +868,30 @@ void hcd_int_handler(uint8_t rhport) { if (!hirq) return; // print_hirq(hirq); +// uint8_t hirq = reg_read(rhport, HIRQ_ADDR, true); + if (hirq & HIRQ_FRAME_IRQ) { _hcd_data.frame_count++; } + #if 1 // interrupt is disabled, only ack FRAME IRQ and skip the rest if (_hcd_data.intr_disable_count) { if (hirq & HIRQ_FRAME_IRQ) { hirq_write(rhport, HIRQ_FRAME_IRQ, true); } + + if ((hirq & HIRQ_CONDET_IRQ) && !(_hcd_data.mode & MODE_SOFKAENAB)) { + // connection when interrupt is disabled + TU_LOG3_INT(_hcd_data.intr_disable_count); + return; + } return; } + #endif if (hirq & HIRQ_CONDET_IRQ) { - tusb_speed_t speed = handle_connect_irq(rhport); - - if (speed == TUSB_SPEED_INVALID) { - hcd_event_device_remove(rhport, true); - }else { - // FIXME multiple MAX3421 rootdevice address is not 1 - uint8_t const daddr = 1; - free_ep(daddr); - - hcd_event_device_attach(rhport, true); - } + handle_connect_irq(rhport); } // queue more transfer in handle_xfer_done() can cause hirq to be set again while external IRQ may not catch and/or From ed0a233d4830baa8a767fcc20dcbfedbb09b7b41 Mon Sep 17 00:00:00 2001 From: hathach Date: Thu, 31 Aug 2023 21:28:27 +0700 Subject: [PATCH 24/34] vastly improve attach/detach device, still have issue where thing is still hanged occasionally. --- src/portable/analog/max3421/hcd_max3421.c | 126 ++++++++++++---------- 1 file changed, 70 insertions(+), 56 deletions(-) diff --git a/src/portable/analog/max3421/hcd_max3421.c b/src/portable/analog/max3421/hcd_max3421.c index 56d3aea45a..c61389cb9f 100644 --- a/src/portable/analog/max3421/hcd_max3421.c +++ b/src/portable/analog/max3421/hcd_max3421.c @@ -215,6 +215,9 @@ void tuh_max3421_spi_cs_api(uint8_t rhport, bool active); bool tuh_max3421_spi_xfer_api(uint8_t rhport, uint8_t const * tx_buf, size_t tx_len, uint8_t * rx_buf, size_t rx_len); void tuh_max3421e_int_api(uint8_t rhport, bool enabled); +static void handle_connect_irq(uint8_t rhport, bool in_isr); +static inline void hirq_write(uint8_t rhport, uint8_t data, bool in_isr); + //--------------------------------------------------------------------+ // SPI Helper //--------------------------------------------------------------------+ @@ -238,6 +241,14 @@ static void max3421_spi_unlock(uint8_t rhport, bool in_isr) { if (!in_isr) { tuh_max3421e_int_api(rhport, true); (void) osal_mutex_unlock(_hcd_data.spi_mutex); + + // when re-enable interrupt, we may miss INTR edge (usually via GPIO detection interrupt). + // It would be ok if we are operating since SOF will re-trigger interrupt. + // However, for CONDET_IRQ i.e host not operating therefore we need to manually handle it here. + if (_hcd_data.hirq & HIRQ_CONDET_IRQ) { + handle_connect_irq(rhport, false); + hirq_write(rhport, HIRQ_CONDET_IRQ, false); + } } } @@ -405,48 +416,6 @@ bool hcd_configure(uint8_t rhport, uint32_t cfg_id, const void* cfg_param) { return false; } -static void handle_connect_irq(uint8_t rhport) { - uint8_t const hrsl = reg_read(rhport, HRSL_ADDR, true); - uint8_t const jk = hrsl & (HRSL_JSTATUS | HRSL_KSTATUS); - - uint8_t new_mode = MODE_DPPULLDN | MODE_DMPULLDN | MODE_HOST; - TU_LOG2_HEX(jk); - - switch(jk) { - case 0x00: // SEO is disconnected - case (HRSL_JSTATUS | HRSL_KSTATUS): // SE1 is illegal - mode_write(rhport, new_mode, true); - hcd_event_device_remove(rhport, true); - break; - - default: { - // Bus Reset also cause CONDET IRQ, skip if we are already connected and doing bus reset - if ((_hcd_data.hirq & HIRQ_BUSEVENT_IRQ) && (_hcd_data.mode & MODE_SOFKAENAB)) { - break; - } - - // Low speed if (LS = 1 and J-state) or (LS = 0 and K-State) - // However, since we are always in full speed mode, we can just check J-state - if (jk == HRSL_KSTATUS) { - new_mode |= MODE_LOWSPEED; - TU_LOG3("Low speed\n"); - }else { - TU_LOG3("Full speed\n"); - } - new_mode |= MODE_SOFKAENAB; - mode_write(rhport, new_mode, true); - - // FIXME multiple MAX3421 rootdevice address is not 1 - uint8_t const daddr = 1; - free_ep(daddr); - - hcd_event_device_attach(rhport, true); - - break; - } - } -} - // Initialize controller to host mode bool hcd_init(uint8_t rhport) { (void) rhport; @@ -507,6 +476,14 @@ void hcd_int_enable (uint8_t rhport) { if (_hcd_data.intr_disable_count) { _hcd_data.intr_disable_count--; } + + // when re-enable interrupt, we may miss INTR edge (usually via GPIO detection interrupt). + // It would be ok if we are operating since SOF will re-trigger interrupt. + // However, for CONDET_IRQ i.e host not operating therefore we need to manually handle it here. +// if (_hcd_data.hirq & HIRQ_CONDET_IRQ) { +// handle_connect_irq(rhport, false); +// hirq_write(rhport, HIRQ_CONDET_IRQ, false); +// } } // Disable USB interrupt @@ -726,6 +703,54 @@ bool hcd_edpt_clear_stall(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr) { // Interrupt Handler //--------------------------------------------------------------------+ +static void handle_connect_irq(uint8_t rhport, bool in_isr) { + uint8_t const hrsl = reg_read(rhport, HRSL_ADDR, in_isr); + uint8_t const jk = hrsl & (HRSL_JSTATUS | HRSL_KSTATUS); + + uint8_t new_mode = MODE_DPPULLDN | MODE_DMPULLDN | MODE_HOST; + TU_LOG2_HEX(jk); + + switch(jk) { + case 0x00: // SEO is disconnected + case (HRSL_JSTATUS | HRSL_KSTATUS): // SE1 is illegal + mode_write(rhport, new_mode, in_isr); + + // port reset anyway, this will help to stable bus signal for next connection + reg_write(rhport, HCTL_ADDR, HCTL_BUSRST, in_isr); + + hcd_event_device_remove(rhport, in_isr); + + reg_write(rhport, HCTL_ADDR, 0, in_isr); + break; + + default: { + // Bus Reset also cause CONDET IRQ, skip if we are already connected and doing bus reset + if ((_hcd_data.hirq & HIRQ_BUSEVENT_IRQ) && (_hcd_data.mode & MODE_SOFKAENAB)) { + break; + } + + // Low speed if (LS = 1 and J-state) or (LS = 0 and K-State) + // However, since we are always in full speed mode, we can just check J-state + if (jk == HRSL_KSTATUS) { + new_mode |= MODE_LOWSPEED; + TU_LOG3("Low speed\n"); + }else { + TU_LOG3("Full speed\n"); + } + new_mode |= MODE_SOFKAENAB; + mode_write(rhport, new_mode, in_isr); + + // FIXME multiple MAX3421 rootdevice address is not 1 + uint8_t const daddr = 1; + free_ep(daddr); + + hcd_event_device_attach(rhport, in_isr); + + break; + } + } +} + static void xfer_complete_isr(uint8_t rhport, max3421_ep_t *ep, xfer_result_t result, uint8_t hrsl) { uint8_t const ep_addr = tu_edpt_addr(ep->ep_num, ep->ep_dir); @@ -758,7 +783,7 @@ static void handle_xfer_done(uint8_t rhport) { uint8_t const ep_dir = ((hxfr_type & HXFR_SETUP) || (hxfr_type & HXFR_OUT_NIN)) ? 0 : 1; max3421_ep_t *ep = find_opened_ep(_hcd_data.peraddr, ep_num, ep_dir); - TU_ASSERT(ep, ); + TU_VERIFY(ep, ); xfer_result_t xfer_result; switch(hresult) { @@ -857,7 +882,6 @@ void print_hirq(uint8_t hirq) { TU_LOG3("\r\n"); } - #else #define print_hirq(hirq) #endif @@ -868,30 +892,20 @@ void hcd_int_handler(uint8_t rhport) { if (!hirq) return; // print_hirq(hirq); -// uint8_t hirq = reg_read(rhport, HIRQ_ADDR, true); - if (hirq & HIRQ_FRAME_IRQ) { _hcd_data.frame_count++; } - #if 1 - // interrupt is disabled, only ack FRAME IRQ and skip the rest + // interrupt is disabled by usbh task: only ack FRAME IRQ and skip the rest if (_hcd_data.intr_disable_count) { if (hirq & HIRQ_FRAME_IRQ) { hirq_write(rhport, HIRQ_FRAME_IRQ, true); } - - if ((hirq & HIRQ_CONDET_IRQ) && !(_hcd_data.mode & MODE_SOFKAENAB)) { - // connection when interrupt is disabled - TU_LOG3_INT(_hcd_data.intr_disable_count); - return; - } return; } - #endif if (hirq & HIRQ_CONDET_IRQ) { - handle_connect_irq(rhport); + handle_connect_irq(rhport, true); } // queue more transfer in handle_xfer_done() can cause hirq to be set again while external IRQ may not catch and/or From 1b9108ea0dc237835e801d26cc7eef052acad987 Mon Sep 17 00:00:00 2001 From: hathach Date: Wed, 6 Sep 2023 17:11:35 +0700 Subject: [PATCH 25/34] minor debug clean up --- src/common/tusb_common.h | 6 ++---- src/common/tusb_debug.h | 37 ++++++++++++++----------------------- src/device/usbd.c | 2 +- src/device/usbd_pvt.h | 15 ++++++--------- src/host/usbh.c | 6 ++---- 5 files changed, 25 insertions(+), 41 deletions(-) diff --git a/src/common/tusb_common.h b/src/common/tusb_common.h index c303c6eafc..6fffed11c8 100644 --- a/src/common/tusb_common.h +++ b/src/common/tusb_common.h @@ -122,13 +122,11 @@ TU_ATTR_ALWAYS_INLINE static inline int tu_memcpy_s(void *dest, size_t destsz, c //------------- Bytes -------------// -TU_ATTR_ALWAYS_INLINE static inline uint32_t tu_u32(uint8_t b3, uint8_t b2, uint8_t b1, uint8_t b0) -{ +TU_ATTR_ALWAYS_INLINE static inline uint32_t tu_u32(uint8_t b3, uint8_t b2, uint8_t b1, uint8_t b0) { return ( ((uint32_t) b3) << 24) | ( ((uint32_t) b2) << 16) | ( ((uint32_t) b1) << 8) | b0; } -TU_ATTR_ALWAYS_INLINE static inline uint16_t tu_u16(uint8_t high, uint8_t low) -{ +TU_ATTR_ALWAYS_INLINE static inline uint16_t tu_u16(uint8_t high, uint8_t low) { return (uint16_t) ((((uint16_t) high) << 8) | low); } diff --git a/src/common/tusb_debug.h b/src/common/tusb_debug.h index 36507041fb..99176c02aa 100644 --- a/src/common/tusb_debug.h +++ b/src/common/tusb_debug.h @@ -58,16 +58,14 @@ void tu_print_mem(void const *buf, uint32_t count, uint8_t indent); #define tu_printf printf #endif -static inline void tu_print_arr(uint8_t const* buf, uint32_t bufsize) -{ +static inline void tu_print_buf(uint8_t const* buf, uint32_t bufsize) { for(uint32_t i=0; i= 2 #define TU_LOG2 TU_LOG1 #define TU_LOG2_MEM TU_LOG1_MEM - #define TU_LOG2_ARR TU_LOG1_ARR - #define TU_LOG2_PTR TU_LOG1_PTR + #define TU_LOG2_BUF TU_LOG1_BUF #define TU_LOG2_INT TU_LOG1_INT #define TU_LOG2_HEX TU_LOG1_HEX #endif @@ -95,30 +91,25 @@ static inline void tu_print_arr(uint8_t const* buf, uint32_t bufsize) #if CFG_TUSB_DEBUG >= 3 #define TU_LOG3 TU_LOG1 #define TU_LOG3_MEM TU_LOG1_MEM - #define TU_LOG3_ARR TU_LOG1_ARR - #define TU_LOG3_PTR TU_LOG1_PTR + #define TU_LOG3_BUF TU_LOG1_BUF #define TU_LOG3_INT TU_LOG1_INT #define TU_LOG3_HEX TU_LOG1_HEX #endif -typedef struct -{ +typedef struct { uint32_t key; const char* data; } tu_lookup_entry_t; -typedef struct -{ +typedef struct { uint16_t count; tu_lookup_entry_t const* items; } tu_lookup_table_t; -static inline const char* tu_lookup_find(tu_lookup_table_t const* p_table, uint32_t key) -{ +static inline const char* tu_lookup_find(tu_lookup_table_t const* p_table, uint32_t key) { tu_static char not_found[11]; - for(uint16_t i=0; icount; i++) - { + for(uint16_t i=0; icount; i++) { if (p_table->items[i].key == key) return p_table->items[i].data; } @@ -133,7 +124,7 @@ static inline const char* tu_lookup_find(tu_lookup_table_t const* p_table, uint3 #ifndef TU_LOG #define TU_LOG(n, ...) #define TU_LOG_MEM(n, ...) - #define TU_LOG_PTR(n, ...) + #define TU_LOG_BUF(n, ...) #define TU_LOG_INT(n, ...) #define TU_LOG_HEX(n, ...) #define TU_LOG_LOCATION() @@ -144,14 +135,14 @@ static inline const char* tu_lookup_find(tu_lookup_table_t const* p_table, uint3 #define TU_LOG0(...) #define TU_LOG0_MEM(...) -#define TU_LOG0_PTR(...) +#define TU_LOG0_BUF(...) #define TU_LOG0_INT(...) #define TU_LOG0_HEX(...) #ifndef TU_LOG1 #define TU_LOG1(...) #define TU_LOG1_MEM(...) - #define TU_LOG1_PTR(...) + #define TU_LOG1_BUF(...) #define TU_LOG1_INT(...) #define TU_LOG1_HEX(...) #endif @@ -159,7 +150,7 @@ static inline const char* tu_lookup_find(tu_lookup_table_t const* p_table, uint3 #ifndef TU_LOG2 #define TU_LOG2(...) #define TU_LOG2_MEM(...) - #define TU_LOG2_PTR(...) + #define TU_LOG2_BUF(...) #define TU_LOG2_INT(...) #define TU_LOG2_HEX(...) #endif @@ -167,7 +158,7 @@ static inline const char* tu_lookup_find(tu_lookup_table_t const* p_table, uint3 #ifndef TU_LOG3 #define TU_LOG3(...) #define TU_LOG3_MEM(...) - #define TU_LOG3_PTR(...) + #define TU_LOG3_BUF(...) #define TU_LOG3_INT(...) #define TU_LOG3_HEX(...) #endif diff --git a/src/device/usbd.c b/src/device/usbd.c index f0d9fba52f..50941c46f9 100644 --- a/src/device/usbd.c +++ b/src/device/usbd.c @@ -506,7 +506,7 @@ void tud_task_ext(uint32_t timeout_ms, bool in_isr) break; case DCD_EVENT_SETUP_RECEIVED: - TU_LOG_PTR(CFG_TUD_LOG_LEVEL, &event.setup_received); + TU_LOG_BUF(CFG_TUD_LOG_LEVEL, &event.setup_received, 8); TU_LOG_USBD("\r\n"); // Mark as connected after receiving 1st setup packet. diff --git a/src/device/usbd_pvt.h b/src/device/usbd_pvt.h index 16585167f1..153be7ceea 100644 --- a/src/device/usbd_pvt.h +++ b/src/device/usbd_pvt.h @@ -23,8 +23,8 @@ * * This file is part of the TinyUSB stack. */ -#ifndef USBD_PVT_H_ -#define USBD_PVT_H_ +#ifndef _TUSB_USBD_PVT_H_ +#define _TUSB_USBD_PVT_H_ #include "osal/osal.h" #include "common/tusb_fifo.h" @@ -44,8 +44,7 @@ // Class Driver API //--------------------------------------------------------------------+ -typedef struct -{ +typedef struct { #if CFG_TUSB_DEBUG >= CFG_TUD_LOG_LEVEL char const* name; #endif @@ -111,8 +110,7 @@ bool usbd_edpt_iso_activate(uint8_t rhport, tusb_desc_endpoint_t const * p_endp // Check if endpoint is ready (not busy and not stalled) TU_ATTR_ALWAYS_INLINE static inline -bool usbd_edpt_ready(uint8_t rhport, uint8_t ep_addr) -{ +bool usbd_edpt_ready(uint8_t rhport, uint8_t ep_addr) { return !usbd_edpt_busy(rhport, ep_addr) && !usbd_edpt_stalled(rhport, ep_addr); } @@ -124,11 +122,10 @@ void usbd_sof_enable(uint8_t rhport, bool en); *------------------------------------------------------------------*/ bool usbd_open_edpt_pair(uint8_t rhport, uint8_t const* p_desc, uint8_t ep_count, uint8_t xfer_type, uint8_t* ep_out, uint8_t* ep_in); -void usbd_defer_func( osal_task_func_t func, void* param, bool in_isr ); - +void usbd_defer_func(osal_task_func_t func, void *param, bool in_isr); #ifdef __cplusplus } #endif -#endif /* USBD_PVT_H_ */ +#endif diff --git a/src/host/usbh.c b/src/host/usbh.c index bacb3a7192..e60e680c2d 100644 --- a/src/host/usbh.c +++ b/src/host/usbh.c @@ -583,7 +583,7 @@ bool tuh_control_xfer (tuh_xfer_t* xfer) { TU_LOG_USBH("[%u:%u] %s: ", rhport, daddr, (xfer->setup->bmRequestType_bit.type == TUSB_REQ_TYPE_STANDARD && xfer->setup->bRequest <= TUSB_REQ_SYNCH_FRAME) ? tu_str_std_request[xfer->setup->bRequest] : "Class Request"); - TU_LOG_PTR(CFG_TUH_LOG_LEVEL, xfer->setup); + TU_LOG_BUF(CFG_TUH_LOG_LEVEL, xfer->setup, 8); TU_LOG_USBH("\r\n"); if (xfer->complete_cb) { @@ -660,10 +660,8 @@ static bool usbh_control_xfer_cb (uint8_t dev_addr, uint8_t ep_addr, xfer_result if (XFER_RESULT_SUCCESS != result) { TU_LOG1("[%u:%u] Control %s, xferred_bytes = %lu\r\n", rhport, dev_addr, result == XFER_RESULT_STALLED ? "STALLED" : "FAILED", xferred_bytes); - #if CFG_TUSB_DEBUG == 1 - TU_LOG1_PTR(request); + TU_LOG1_BUF(request, 8); TU_LOG1("\r\n"); - #endif // terminate transfer if any stage failed _xfer_complete(dev_addr, result); From 21ab40bab2e2fee28fa595f648a17944696c3d65 Mon Sep 17 00:00:00 2001 From: hathach Date: Thu, 7 Sep 2023 12:38:18 +0700 Subject: [PATCH 26/34] - wrap up hcd max3421, work well with nrf52840 - also add usbh_defer_func() --- hw/bsp/nrf/family.c | 7 +++-- src/host/usbh.c | 26 +++++++++------- src/host/usbh_pvt.h | 10 +++---- src/portable/analog/max3421/hcd_max3421.c | 36 ++--------------------- 4 files changed, 27 insertions(+), 52 deletions(-) diff --git a/hw/bsp/nrf/family.c b/hw/bsp/nrf/family.c index 7358458ce7..39ce179e81 100644 --- a/hw/bsp/nrf/family.c +++ b/hw/bsp/nrf/family.c @@ -109,10 +109,12 @@ void max3421e_int_handler(nrfx_gpiote_pin_t pin, nrf_gpiote_polarity_t action) { void tuh_max3421e_int_api(uint8_t rhport, bool enabled) { (void) rhport; + // use NVIC_Enable/Disable instead since nrfx_gpiote_trigger_enable/disable clear pending and can miss interrupt + // when disabled if (enabled) { - nrfx_gpiote_trigger_enable(MAX3241E_INTR_PIN, true); + NVIC_EnableIRQ(GPIOTE_IRQn); } else { - nrfx_gpiote_trigger_disable(MAX3241E_INTR_PIN); + NVIC_DisableIRQ(GPIOTE_IRQn); } } @@ -266,6 +268,7 @@ void board_init(void) { in_config.pull = NRF_GPIO_PIN_PULLUP; nrfx_gpiote_in_init(MAX3241E_INTR_PIN, &in_config, max3421e_int_handler); + nrfx_gpiote_trigger_enable(MAX3241E_INTR_PIN, true); #endif } diff --git a/src/host/usbh.c b/src/host/usbh.c index e60e680c2d..e332f35ccd 100644 --- a/src/host/usbh.c +++ b/src/host/usbh.c @@ -753,29 +753,33 @@ bool tuh_edpt_abort_xfer(uint8_t daddr, uint8_t ep_addr) { // USBH API For Class Driver //--------------------------------------------------------------------+ -uint8_t usbh_get_rhport(uint8_t dev_addr) -{ - usbh_device_t* dev = get_device(dev_addr); +uint8_t usbh_get_rhport(uint8_t dev_addr) { + usbh_device_t *dev = get_device(dev_addr); return dev ? dev->rhport : _dev0.rhport; } -uint8_t* usbh_get_enum_buf(void) -{ +uint8_t *usbh_get_enum_buf(void) { return _usbh_ctrl_buf; } -void usbh_int_set(bool enabled) -{ +void usbh_int_set(bool enabled) { // TODO all host controller if multiple are used since they shared the same event queue - if (enabled) - { + if (enabled) { hcd_int_enable(_usbh_controller); - }else - { + } else { hcd_int_disable(_usbh_controller); } } +void usbh_defer_func(osal_task_func_t func, void *param, bool in_isr) { + hcd_event_t event = { 0 }; + event.event_id = USBH_EVENT_FUNC_CALL; + event.func_call.func = func; + event.func_call.param = param; + + osal_queue_send(_usbh_q, &event, in_isr); +} + //--------------------------------------------------------------------+ // Endpoint API //--------------------------------------------------------------------+ diff --git a/src/host/usbh_pvt.h b/src/host/usbh_pvt.h index 0b58a91bc4..2b61a77db6 100644 --- a/src/host/usbh_pvt.h +++ b/src/host/usbh_pvt.h @@ -24,8 +24,8 @@ * This file is part of the TinyUSB stack. */ -#ifndef _TUSB_USBH_CLASSDRIVER_H_ -#define _TUSB_USBH_CLASSDRIVER_H_ +#ifndef _TUSB_USBH_PVT_H_ +#define _TUSB_USBH_PVT_H_ #include "osal/osal.h" #include "common/tusb_fifo.h" @@ -76,6 +76,8 @@ uint8_t* usbh_get_enum_buf(void); void usbh_int_set(bool enabled); +void usbh_defer_func(osal_task_func_t func, void *param, bool in_isr); + //--------------------------------------------------------------------+ // USBH Endpoint API //--------------------------------------------------------------------+ @@ -85,12 +87,10 @@ bool usbh_edpt_xfer_with_callback(uint8_t dev_addr, uint8_t ep_addr, uint8_t * b tuh_xfer_cb_t complete_cb, uintptr_t user_data); TU_ATTR_ALWAYS_INLINE -static inline bool usbh_edpt_xfer(uint8_t dev_addr, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes) -{ +static inline bool usbh_edpt_xfer(uint8_t dev_addr, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes) { return usbh_edpt_xfer_with_callback(dev_addr, ep_addr, buffer, total_bytes, NULL, 0); } - // Claim an endpoint before submitting a transfer. // If caller does not make any transfer, it must release endpoint for others. bool usbh_edpt_claim(uint8_t dev_addr, uint8_t ep_addr); diff --git a/src/portable/analog/max3421/hcd_max3421.c b/src/portable/analog/max3421/hcd_max3421.c index c61389cb9f..95cf5516e9 100644 --- a/src/portable/analog/max3421/hcd_max3421.c +++ b/src/portable/analog/max3421/hcd_max3421.c @@ -194,7 +194,6 @@ typedef struct { uint8_t hxfr; atomic_flag busy; // busy transferring - volatile uint8_t intr_disable_count; volatile uint16_t frame_count; max3421_ep_t ep[CFG_TUH_MAX3421_ENDPOINT_TOTAL]; // [0] is reserved for addr0 @@ -241,14 +240,6 @@ static void max3421_spi_unlock(uint8_t rhport, bool in_isr) { if (!in_isr) { tuh_max3421e_int_api(rhport, true); (void) osal_mutex_unlock(_hcd_data.spi_mutex); - - // when re-enable interrupt, we may miss INTR edge (usually via GPIO detection interrupt). - // It would be ok if we are operating since SOF will re-trigger interrupt. - // However, for CONDET_IRQ i.e host not operating therefore we need to manually handle it here. - if (_hcd_data.hirq & HIRQ_CONDET_IRQ) { - handle_connect_irq(rhport, false); - hirq_write(rhport, HIRQ_CONDET_IRQ, false); - } } } @@ -470,28 +461,13 @@ bool hcd_init(uint8_t rhport) { // Enable USB interrupt // Not actually enable GPIO interrupt, just set variable to prevent handler to process void hcd_int_enable (uint8_t rhport) { -// tuh_max3421e_int_api(rhport, true); - - (void) rhport; - if (_hcd_data.intr_disable_count) { - _hcd_data.intr_disable_count--; - } - - // when re-enable interrupt, we may miss INTR edge (usually via GPIO detection interrupt). - // It would be ok if we are operating since SOF will re-trigger interrupt. - // However, for CONDET_IRQ i.e host not operating therefore we need to manually handle it here. -// if (_hcd_data.hirq & HIRQ_CONDET_IRQ) { -// handle_connect_irq(rhport, false); -// hirq_write(rhport, HIRQ_CONDET_IRQ, false); -// } + tuh_max3421e_int_api(rhport, true); } // Disable USB interrupt // Not actually disable GPIO interrupt, just set variable to prevent handler to process void hcd_int_disable(uint8_t rhport) { - //tuh_max3421e_int_api(rhport, false); - (void) rhport; - _hcd_data.intr_disable_count++; + tuh_max3421e_int_api(rhport, false); } // Get frame number (1ms) @@ -896,14 +872,6 @@ void hcd_int_handler(uint8_t rhport) { _hcd_data.frame_count++; } - // interrupt is disabled by usbh task: only ack FRAME IRQ and skip the rest - if (_hcd_data.intr_disable_count) { - if (hirq & HIRQ_FRAME_IRQ) { - hirq_write(rhport, HIRQ_FRAME_IRQ, true); - } - return; - } - if (hirq & HIRQ_CONDET_IRQ) { handle_connect_irq(rhport, true); } From bcc77a60e047837a82b0719ffa95a4d6f688468d Mon Sep 17 00:00:00 2001 From: hathach Date: Fri, 8 Sep 2023 17:40:00 +0700 Subject: [PATCH 27/34] get spi working for metro m4 express --- hw/bsp/nrf/family.c | 73 +++--- hw/bsp/samd51/boards/metro_m4_express/board.h | 9 + hw/bsp/samd51/family.c | 211 +++++++++++++++--- hw/bsp/samd51/family.cmake | 1 + 4 files changed, 228 insertions(+), 66 deletions(-) diff --git a/hw/bsp/nrf/family.c b/hw/bsp/nrf/family.c index 39ce179e81..47c765a96d 100644 --- a/hw/bsp/nrf/family.c +++ b/hw/bsp/nrf/family.c @@ -102,40 +102,6 @@ void max3421e_int_handler(nrfx_gpiote_pin_t pin, nrf_gpiote_polarity_t action) { tuh_int_handler(1); } - -//--------------------------------------------------------------------+ -// API: SPI transfer with MAX3421E, must be implemented by application -//--------------------------------------------------------------------+ -void tuh_max3421e_int_api(uint8_t rhport, bool enabled) { - (void) rhport; - - // use NVIC_Enable/Disable instead since nrfx_gpiote_trigger_enable/disable clear pending and can miss interrupt - // when disabled - if (enabled) { - NVIC_EnableIRQ(GPIOTE_IRQn); - } else { - NVIC_DisableIRQ(GPIOTE_IRQn); - } -} - -void tuh_max3421_spi_cs_api(uint8_t rhport, bool active) { - (void) rhport; - nrf_gpio_pin_write(MAX3421E_CS_PIN, active ? 0 : 1); -} - -bool tuh_max3421_spi_xfer_api(uint8_t rhport, uint8_t const *tx_buf, size_t tx_len, uint8_t *rx_buf, size_t rx_len) { - (void) rhport; - - nrfx_spim_xfer_desc_t xfer = { - .p_tx_buffer = tx_buf, - .tx_length = tx_len, - .p_rx_buffer = rx_buf, - .rx_length = rx_len, - }; - - return (nrfx_spim_xfer(&_spi, &xfer, 0) == NRFX_SUCCESS); -} - #endif @@ -242,7 +208,7 @@ void board_init(void) { // manually manage CS nrf_gpio_cfg_output(MAX3421E_CS_PIN); - tuh_max3421_spi_cs_api(0, false); + nrf_gpio_pin_write(MAX3421E_CS_PIN, 1); // USB host using max3421e usb controller via SPI nrfx_spim_config_t cfg = { @@ -345,3 +311,40 @@ void nrf_error_cb(uint32_t id, uint32_t pc, uint32_t info) { (void) info; } #endif + +//--------------------------------------------------------------------+ +// API: SPI transfer with MAX3421E, must be implemented by application +//--------------------------------------------------------------------+ +#if CFG_TUH_ENABLED && defined(CFG_TUH_MAX3421) && CFG_TUH_MAX3421 + +void tuh_max3421e_int_api(uint8_t rhport, bool enabled) { + (void) rhport; + + // use NVIC_Enable/Disable instead since nrfx_gpiote_trigger_enable/disable clear pending and can miss interrupt + // when disabled and re-enabled. + if (enabled) { + NVIC_EnableIRQ(GPIOTE_IRQn); + } else { + NVIC_DisableIRQ(GPIOTE_IRQn); + } +} + +void tuh_max3421_spi_cs_api(uint8_t rhport, bool active) { + (void) rhport; + nrf_gpio_pin_write(MAX3421E_CS_PIN, active ? 0 : 1); +} + +bool tuh_max3421_spi_xfer_api(uint8_t rhport, uint8_t const *tx_buf, size_t tx_len, uint8_t *rx_buf, size_t rx_len) { + (void) rhport; + + nrfx_spim_xfer_desc_t xfer = { + .p_tx_buffer = tx_buf, + .tx_length = tx_len, + .p_rx_buffer = rx_buf, + .rx_length = rx_len, + }; + + return (nrfx_spim_xfer(&_spi, &xfer, 0) == NRFX_SUCCESS); +} + +#endif diff --git a/hw/bsp/samd51/boards/metro_m4_express/board.h b/hw/bsp/samd51/boards/metro_m4_express/board.h index 5d77345767..3441d03e98 100644 --- a/hw/bsp/samd51/boards/metro_m4_express/board.h +++ b/hw/bsp/samd51/boards/metro_m4_express/board.h @@ -43,6 +43,15 @@ #define UART_TX_PIN 23 #define UART_RX_PIN 22 +// SPI for USB host shield +#define MAX3421E_SERCOM SERCOM2 +#define MAX3421E_SCK_PIN 13 +#define MAX3421E_MOSI_PIN 12 +#define MAX3421E_MISO_PIN 14 +#define MAX3421E_CS_PIN 18 // D10 +#define MAX3241E_INTR_PIN 20 // D9 + + #ifdef __cplusplus } #endif diff --git a/hw/bsp/samd51/family.c b/hw/bsp/samd51/family.c index 2df9cbafbf..45a9aa5e00 100644 --- a/hw/bsp/samd51/family.c +++ b/hw/bsp/samd51/family.c @@ -43,42 +43,91 @@ #pragma GCC diagnostic pop #endif +//--------------------------------------------------------------------+ +// MACRO TYPEDEF CONSTANT ENUM DECLARATION +//--------------------------------------------------------------------+ + +/* Referenced GCLKs, should be initialized firstly */ +#define _GCLK_INIT_1ST 0xFFFFFFFF + +/* Not referenced GCLKs, initialized last */ +#define _GCLK_INIT_LAST (~_GCLK_INIT_1ST) //--------------------------------------------------------------------+ // Forward USB interrupt events to TinyUSB IRQ Handler //--------------------------------------------------------------------+ -void USB_0_Handler (void) -{ +void USB_0_Handler(void) { tud_int_handler(0); } -void USB_1_Handler (void) -{ +void USB_1_Handler(void) { tud_int_handler(0); } -void USB_2_Handler (void) -{ +void USB_2_Handler(void) { tud_int_handler(0); } -void USB_3_Handler (void) -{ +void USB_3_Handler(void) { tud_int_handler(0); } //--------------------------------------------------------------------+ -// MACRO TYPEDEF CONSTANT ENUM DECLARATION +// //--------------------------------------------------------------------+ -/* Referenced GCLKs, should be initialized firstly */ -#define _GCLK_INIT_1ST 0xFFFFFFFF +#if CFG_TUH_ENABLED && defined(CFG_TUH_MAX3421) && CFG_TUH_MAX3421 +void max3421_init(void) +{ + //------------- SPI Init -------------// -/* Not referenced GCLKs, initialized last */ -#define _GCLK_INIT_LAST (~_GCLK_INIT_1ST) + // Enable the APB clock for SERCOM2 + MCLK->APBBMASK.reg |= MCLK_APBBMASK_SERCOM2; -void board_init(void) -{ + // Configure GCLK for SERCOM2, initClockNVIC() + GCLK->PCHCTRL[SERCOM2_GCLK_ID_CORE].reg = GCLK_PCHCTRL_GEN_GCLK0_Val | (1 << GCLK_PCHCTRL_CHEN_Pos); + GCLK->PCHCTRL[SERCOM2_GCLK_ID_SLOW].reg = GCLK_PCHCTRL_GEN_GCLK3_Val | (1 << GCLK_PCHCTRL_CHEN_Pos); + + // Disable the SPI module + SERCOM2->SPI.CTRLA.bit.ENABLE = 0; + + // Reset the SPI module + SERCOM2->SPI.CTRLA.bit.SWRST = 1; + while (SERCOM2->SPI.SYNCBUSY.bit.SWRST); + + // Set up SPI in master mode, MSB first, SPI mode 0 + uint8_t const mosi_pad = 0; + uint8_t const miso_pad = 2; + SERCOM2->SPI.CTRLA.reg = SERCOM_SPI_CTRLA_MODE(3) | SERCOM_SPI_CTRLA_DOPO(mosi_pad) | SERCOM_SPI_CTRLA_DIPO(miso_pad); + + SERCOM2->SPI.CTRLB.reg = SERCOM_SPI_CTRLB_CHSIZE(0) | SERCOM_SPI_CTRLB_RXEN; + while( SERCOM2->SPI.SYNCBUSY.bit.CTRLB == 1 ); + + // Set the baud rate + uint32_t baudrate = 4000000u; + SERCOM2->SPI.BAUD.reg = (uint8_t)(SystemCoreClock / (2 * baudrate) - 1); // Replace 1000000 with your desired baud rate + + // Configure PA12 as MOSI (PAD0), PA13 as SCK (PAD1), PA14 as MISO (PAD2) + // 2 function C: PIO_SERCOM + gpio_set_pin_direction(MAX3421E_SCK_PIN, GPIO_DIRECTION_OUT); + gpio_set_pin_pull_mode(MAX3421E_SCK_PIN, GPIO_PULL_OFF); + gpio_set_pin_function(MAX3421E_SCK_PIN, 2); + + gpio_set_pin_direction(MAX3421E_MOSI_PIN, GPIO_DIRECTION_OUT); + gpio_set_pin_pull_mode(MAX3421E_MOSI_PIN, GPIO_PULL_OFF); + gpio_set_pin_function(MAX3421E_MOSI_PIN, 2); + + gpio_set_pin_direction(MAX3421E_MISO_PIN, GPIO_DIRECTION_IN); + gpio_set_pin_pull_mode(MAX3421E_MISO_PIN, GPIO_PULL_OFF); + gpio_set_pin_function(MAX3421E_MISO_PIN, 2); + + // Enable the SPI module + SERCOM2->SPI.CTRLA.bit.ENABLE = 1; + while (SERCOM2->SPI.SYNCBUSY.bit.ENABLE); +} +#endif + +void board_init(void) { // Clock init ( follow hpl_init.c ) hri_nvmctrl_set_CTRLA_RWS_bf(NVMCTRL, 0); @@ -104,7 +153,7 @@ void board_init(void) gpio_set_pin_direction(BUTTON_PIN, GPIO_DIRECTION_IN); gpio_set_pin_pull_mode(BUTTON_PIN, GPIO_PULL_UP); -#if CFG_TUSB_OS == OPT_OS_FREERTOS +#if CFG_TUSB_OS == OPT_OS_FREERTOS // If freeRTOS is used, IRQ priority is limit by max syscall ( smaller is higher ) NVIC_SetPriority(USB_0_IRQn, configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY); NVIC_SetPriority(USB_1_IRQn, configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY); @@ -129,45 +178,145 @@ void board_init(void) gpio_set_pin_function(PIN_PA24, PINMUX_PA24H_USB_DM); gpio_set_pin_function(PIN_PA25, PINMUX_PA25H_USB_DP); + +#if CFG_TUH_ENABLED && defined(CFG_TUH_MAX3421) && CFG_TUH_MAX3421 + // CS pin + gpio_set_pin_direction(MAX3421E_CS_PIN, GPIO_DIRECTION_OUT); + gpio_set_pin_level(MAX3421E_CS_PIN, 1); + + // SPI + max3421_init(); + + // INT pin with external interrupt + gpio_set_pin_direction(MAX3241E_INTR_PIN, GPIO_DIRECTION_IN); + gpio_set_pin_pull_mode(MAX3241E_INTR_PIN, GPIO_PULL_UP); + + // Enable the APB clock for EIC (External Interrupt Controller) + MCLK->APBAMASK.reg |= MCLK_APBAMASK_EIC; + + // Configure GCLK for EIC + GCLK->PCHCTRL[EIC_GCLK_ID].reg = GCLK_PCHCTRL_GEN_GCLK0_Val | (1 << GCLK_PCHCTRL_CHEN_Pos); + + // Configure PA20 as an input + PORT->Group[0].DIRCLR.reg = PORT_PA20; + PORT->Group[0].PINCFG[20].reg = PORT_PINCFG_INEN | PORT_PINCFG_PULLEN; + PORT->Group[0].OUTSET.reg = PORT_PA20; // Enable pull-up + + // Configure PA20 to use EIC + PORT->Group[0].PMUX[10].bit.PMUXE = MUX_PA20A_EIC_EXTINT4; + PORT->Group[0].PINCFG[20].bit.PMUXEN = 1; + + // Disable EIC + EIC->CTRLA.bit.ENABLE = 0; + while (EIC->SYNCBUSY.bit.ENABLE); + + // Configure EXTINT4 (PA20) to trigger on falling edge + EIC->CONFIG[0].reg |= EIC_CONFIG_SENSE4_FALL; + + // Enable EXTINT4 + EIC->INTENSET.reg = EIC_INTENSET_EXTINT(1 << 4); + + // Enable EIC + EIC->CTRLA.bit.ENABLE = 1; + while (EIC->SYNCBUSY.bit.ENABLE); + +#endif } //--------------------------------------------------------------------+ // Board porting API //--------------------------------------------------------------------+ -void board_led_write(bool state) -{ +void board_led_write(bool state) { gpio_set_pin_level(LED_PIN, state); } -uint32_t board_button_read(void) -{ +uint32_t board_button_read(void) { // button is active low return gpio_get_pin_level(BUTTON_PIN) ? 0 : 1; } -int board_uart_read(uint8_t* buf, int len) -{ - (void) buf; (void) len; +int board_uart_read(uint8_t *buf, int len) { + (void) buf; + (void) len; return 0; } -int board_uart_write(void const * buf, int len) -{ - (void) buf; (void) len; +int board_uart_write(void const *buf, int len) { + (void) buf; + (void) len; return 0; } -#if CFG_TUSB_OS == OPT_OS_NONE +#if CFG_TUSB_OS == OPT_OS_NONE volatile uint32_t system_ticks = 0; -void SysTick_Handler (void) -{ +void SysTick_Handler(void) { system_ticks++; } -uint32_t board_millis(void) -{ +uint32_t board_millis(void) { return system_ticks; } + +//--------------------------------------------------------------------+ +// API: SPI transfer with MAX3421E, must be implemented by application +//--------------------------------------------------------------------+ +#if CFG_TUH_ENABLED && defined(CFG_TUH_MAX3421) && CFG_TUH_MAX3421 + +void EIC_4_Handler(void) +{ + // Clear the interrupt flag + EIC->INTFLAG.reg = EIC_INTFLAG_EXTINT(1 << 4); + + // Call the TinyUSB interrupt handler + tuh_int_handler(1); +} + +void tuh_max3421e_int_api(uint8_t rhport, bool enabled) { + (void) rhport; + + if (enabled) { + NVIC_EnableIRQ(EIC_4_IRQn); + } else { + NVIC_DisableIRQ(EIC_4_IRQn); + } +} + +void tuh_max3421_spi_cs_api(uint8_t rhport, bool active) { + (void) rhport; + gpio_set_pin_level(MAX3421E_CS_PIN, active ? 0 : 1); +} + +bool tuh_max3421_spi_xfer_api(uint8_t rhport, uint8_t const *tx_buf, size_t tx_len, uint8_t *rx_buf, size_t rx_len) { + (void) rhport; + + size_t count = 0; + while (count < tx_len || count < rx_len) { + // Wait for the transmit buffer to be empty +// while (!SERCOM2->SPI.INTFLAG.bit.DRE); + + // Write data to be transmitted + uint8_t data = 0x00; + if (count < tx_len) { + data = tx_buf[count]; + } + + SERCOM2->SPI.DATA.bit.DATA = data; + + // Wait for the receive buffer to be filled + while (!SERCOM2->SPI.INTFLAG.bit.RXC); + + // Read received data + if (rx_buf) { + rx_buf[count] = SERCOM2->SPI.DATA.bit.DATA; + } + + count++; + } + + return true; +} +#endif + #endif diff --git a/hw/bsp/samd51/family.cmake b/hw/bsp/samd51/family.cmake index fa9586066a..1dce483fdb 100644 --- a/hw/bsp/samd51/family.cmake +++ b/hw/bsp/samd51/family.cmake @@ -93,6 +93,7 @@ function(family_configure_example TARGET RTOS) family_add_tinyusb(${TARGET} OPT_MCU_SAMD51 ${RTOS}) target_sources(${TARGET}-tinyusb PUBLIC ${TOP}/src/portable/microchip/samd/dcd_samd.c + ${TOP}/src/portable/analog/max3421/hcd_max3421.c ) target_link_libraries(${TARGET}-tinyusb PUBLIC board_${BOARD}) From 1d68f2a3280cdc76912ec7e89238640e950e542c Mon Sep 17 00:00:00 2001 From: hathach Date: Fri, 8 Sep 2023 18:39:09 +0700 Subject: [PATCH 28/34] metro m4 working with max3421e --- hw/bsp/samd51/family.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/hw/bsp/samd51/family.c b/hw/bsp/samd51/family.c index 45a9aa5e00..51cfd19bac 100644 --- a/hw/bsp/samd51/family.c +++ b/hw/bsp/samd51/family.c @@ -294,7 +294,7 @@ bool tuh_max3421_spi_xfer_api(uint8_t rhport, uint8_t const *tx_buf, size_t tx_l size_t count = 0; while (count < tx_len || count < rx_len) { // Wait for the transmit buffer to be empty -// while (!SERCOM2->SPI.INTFLAG.bit.DRE); + while (!SERCOM2->SPI.INTFLAG.bit.DRE); // Write data to be transmitted uint8_t data = 0x00; @@ -302,19 +302,24 @@ bool tuh_max3421_spi_xfer_api(uint8_t rhport, uint8_t const *tx_buf, size_t tx_l data = tx_buf[count]; } - SERCOM2->SPI.DATA.bit.DATA = data; + SERCOM2->SPI.DATA.reg = (uint32_t) data; // Wait for the receive buffer to be filled while (!SERCOM2->SPI.INTFLAG.bit.RXC); // Read received data - if (rx_buf) { - rx_buf[count] = SERCOM2->SPI.DATA.bit.DATA; + data = (uint8_t) SERCOM2->SPI.DATA.reg; + if (count < rx_len) { + rx_buf[count] = data; } count++; } + // wait for bus idle and clear flags + while (!(SERCOM2->SPI.INTFLAG.reg & (SERCOM_SPI_INTFLAG_TXC | SERCOM_SPI_INTFLAG_DRE))); + SERCOM2->SPI.INTFLAG.reg = SERCOM_SPI_INTFLAG_TXC | SERCOM_SPI_INTFLAG_DRE; + return true; } #endif From c074488f75522c7c29dc7853aa2d8597b4858f89 Mon Sep 17 00:00:00 2001 From: hathach Date: Sat, 9 Sep 2023 12:20:16 +0700 Subject: [PATCH 29/34] minor rename --- .../boards/feather_nrf52840_express/board.h | 10 +- hw/bsp/nrf/boards/pca10056/board.h | 10 +- hw/bsp/nrf/boards/pca10095/board.h | 10 +- hw/bsp/nrf/family.c | 22 +-- hw/bsp/samd51/boards/metro_m4_express/board.h | 12 +- hw/bsp/samd51/family.c | 183 +++++++++--------- src/portable/analog/max3421/hcd_max3421.c | 14 +- 7 files changed, 131 insertions(+), 130 deletions(-) diff --git a/hw/bsp/nrf/boards/feather_nrf52840_express/board.h b/hw/bsp/nrf/boards/feather_nrf52840_express/board.h index e6e7590acc..76100a14a2 100644 --- a/hw/bsp/nrf/boards/feather_nrf52840_express/board.h +++ b/hw/bsp/nrf/boards/feather_nrf52840_express/board.h @@ -46,11 +46,11 @@ #define UART_TX_PIN 25 // SPI for USB host shield -#define MAX3421E_SCK_PIN 14 -#define MAX3421E_MOSI_PIN 13 -#define MAX3421E_MISO_PIN 15 -#define MAX3421E_CS_PIN 27 -#define MAX3241E_INTR_PIN 26 +#define MAX3421_SCK_PIN 14 +#define MAX3421_MOSI_PIN 13 +#define MAX3421_MISO_PIN 15 +#define MAX3421_CS_PIN 27 +#define MAX3421_INTR_PIN 26 #ifdef __cplusplus } diff --git a/hw/bsp/nrf/boards/pca10056/board.h b/hw/bsp/nrf/boards/pca10056/board.h index 16d31addb8..9459e79112 100644 --- a/hw/bsp/nrf/boards/pca10056/board.h +++ b/hw/bsp/nrf/boards/pca10056/board.h @@ -46,11 +46,11 @@ #define UART_TX_PIN 6 // SPI for USB host shield -#define MAX3421E_SCK_PIN _PINNUM(1, 15) -#define MAX3421E_MOSI_PIN _PINNUM(1, 13) -#define MAX3421E_MISO_PIN _PINNUM(1, 14) -#define MAX3421E_CS_PIN _PINNUM(1, 12) -#define MAX3241E_INTR_PIN _PINNUM(1, 11) +#define MAX3421_SCK_PIN _PINNUM(1, 15) +#define MAX3421_MOSI_PIN _PINNUM(1, 13) +#define MAX3421_MISO_PIN _PINNUM(1, 14) +#define MAX3421_CS_PIN _PINNUM(1, 12) +#define MAX3421_INTR_PIN _PINNUM(1, 11) #ifdef __cplusplus } diff --git a/hw/bsp/nrf/boards/pca10095/board.h b/hw/bsp/nrf/boards/pca10095/board.h index b9d3a19dc8..ad3379bf6e 100644 --- a/hw/bsp/nrf/boards/pca10095/board.h +++ b/hw/bsp/nrf/boards/pca10095/board.h @@ -46,11 +46,11 @@ #define UART_TX_PIN 33 // SPI for USB host shield -#define MAX3421E_SCK_PIN _PINNUM(1, 15) -#define MAX3421E_MOSI_PIN _PINNUM(1, 13) -#define MAX3421E_MISO_PIN _PINNUM(1, 14) -#define MAX3421E_CS_PIN _PINNUM(1, 12) -#define MAX3241E_INTR_PIN _PINNUM(1, 11) +#define MAX3421_SCK_PIN _PINNUM(1, 15) +#define MAX3421_MOSI_PIN _PINNUM(1, 13) +#define MAX3421_MISO_PIN _PINNUM(1, 14) +#define MAX3421_CS_PIN _PINNUM(1, 12) +#define MAX3421_INTR_PIN _PINNUM(1, 11) #ifdef __cplusplus } diff --git a/hw/bsp/nrf/family.c b/hw/bsp/nrf/family.c index 47c765a96d..6fcfd94769 100644 --- a/hw/bsp/nrf/family.c +++ b/hw/bsp/nrf/family.c @@ -97,8 +97,8 @@ TU_ATTR_UNUSED static void power_event_handler(nrfx_power_usb_evt_t event) { #if CFG_TUH_ENABLED && defined(CFG_TUH_MAX3421) && CFG_TUH_MAX3421 static nrfx_spim_t _spi = NRFX_SPIM_INSTANCE(1); -void max3421e_int_handler(nrfx_gpiote_pin_t pin, nrf_gpiote_polarity_t action) { - if (!(pin == MAX3241E_INTR_PIN && action == NRF_GPIOTE_POLARITY_HITOLO)) return; +void max3421_int_handler(nrfx_gpiote_pin_t pin, nrf_gpiote_polarity_t action) { + if (!(pin == MAX3421_INTR_PIN && action == NRF_GPIOTE_POLARITY_HITOLO)) return; tuh_int_handler(1); } @@ -207,14 +207,14 @@ void board_init(void) { #endif // manually manage CS - nrf_gpio_cfg_output(MAX3421E_CS_PIN); - nrf_gpio_pin_write(MAX3421E_CS_PIN, 1); + nrf_gpio_cfg_output(MAX3421_CS_PIN); + nrf_gpio_pin_write(MAX3421_CS_PIN, 1); // USB host using max3421e usb controller via SPI nrfx_spim_config_t cfg = { - .sck_pin = MAX3421E_SCK_PIN, - .mosi_pin = MAX3421E_MOSI_PIN, - .miso_pin = MAX3421E_MISO_PIN, + .sck_pin = MAX3421_SCK_PIN, + .mosi_pin = MAX3421_MOSI_PIN, + .miso_pin = MAX3421_MISO_PIN, .ss_pin = NRFX_SPIM_PIN_NOT_USED, .ss_active_high = false, .irq_priority = 3, @@ -233,8 +233,8 @@ void board_init(void) { nrfx_gpiote_in_config_t in_config = NRFX_GPIOTE_CONFIG_IN_SENSE_HITOLO(true); in_config.pull = NRF_GPIO_PIN_PULLUP; - nrfx_gpiote_in_init(MAX3241E_INTR_PIN, &in_config, max3421e_int_handler); - nrfx_gpiote_trigger_enable(MAX3241E_INTR_PIN, true); + nrfx_gpiote_in_init(MAX3421_INTR_PIN, &in_config, max3421_int_handler); + nrfx_gpiote_trigger_enable(MAX3421_INTR_PIN, true); #endif } @@ -317,7 +317,7 @@ void nrf_error_cb(uint32_t id, uint32_t pc, uint32_t info) { //--------------------------------------------------------------------+ #if CFG_TUH_ENABLED && defined(CFG_TUH_MAX3421) && CFG_TUH_MAX3421 -void tuh_max3421e_int_api(uint8_t rhport, bool enabled) { +void tuh_max3421_int_api(uint8_t rhport, bool enabled) { (void) rhport; // use NVIC_Enable/Disable instead since nrfx_gpiote_trigger_enable/disable clear pending and can miss interrupt @@ -331,7 +331,7 @@ void tuh_max3421e_int_api(uint8_t rhport, bool enabled) { void tuh_max3421_spi_cs_api(uint8_t rhport, bool active) { (void) rhport; - nrf_gpio_pin_write(MAX3421E_CS_PIN, active ? 0 : 1); + nrf_gpio_pin_write(MAX3421_CS_PIN, active ? 0 : 1); } bool tuh_max3421_spi_xfer_api(uint8_t rhport, uint8_t const *tx_buf, size_t tx_len, uint8_t *rx_buf, size_t rx_len) { diff --git a/hw/bsp/samd51/boards/metro_m4_express/board.h b/hw/bsp/samd51/boards/metro_m4_express/board.h index 3441d03e98..fe2a867a4d 100644 --- a/hw/bsp/samd51/boards/metro_m4_express/board.h +++ b/hw/bsp/samd51/boards/metro_m4_express/board.h @@ -44,12 +44,12 @@ #define UART_RX_PIN 22 // SPI for USB host shield -#define MAX3421E_SERCOM SERCOM2 -#define MAX3421E_SCK_PIN 13 -#define MAX3421E_MOSI_PIN 12 -#define MAX3421E_MISO_PIN 14 -#define MAX3421E_CS_PIN 18 // D10 -#define MAX3241E_INTR_PIN 20 // D9 +#define MAX3421_SERCOM 2 // SERCOM2 +#define MAX3421_SCK_PIN 13 +#define MAX3421_MOSI_PIN 12 +#define MAX3421_MISO_PIN 14 +#define MAX3421_CS_PIN 18 // D10 +#define MAX3421_INTR_PIN 20 // D9 #ifdef __cplusplus diff --git a/hw/bsp/samd51/family.c b/hw/bsp/samd51/family.c index 51cfd19bac..34dd93cef7 100644 --- a/hw/bsp/samd51/family.c +++ b/hw/bsp/samd51/family.c @@ -73,58 +73,14 @@ void USB_3_Handler(void) { } //--------------------------------------------------------------------+ -// +// Implementation //--------------------------------------------------------------------+ #if CFG_TUH_ENABLED && defined(CFG_TUH_MAX3421) && CFG_TUH_MAX3421 -void max3421_init(void) -{ - //------------- SPI Init -------------// - - // Enable the APB clock for SERCOM2 - MCLK->APBBMASK.reg |= MCLK_APBBMASK_SERCOM2; - - // Configure GCLK for SERCOM2, initClockNVIC() - GCLK->PCHCTRL[SERCOM2_GCLK_ID_CORE].reg = GCLK_PCHCTRL_GEN_GCLK0_Val | (1 << GCLK_PCHCTRL_CHEN_Pos); - GCLK->PCHCTRL[SERCOM2_GCLK_ID_SLOW].reg = GCLK_PCHCTRL_GEN_GCLK3_Val | (1 << GCLK_PCHCTRL_CHEN_Pos); +static void max3421_init(void); - // Disable the SPI module - SERCOM2->SPI.CTRLA.bit.ENABLE = 0; - - // Reset the SPI module - SERCOM2->SPI.CTRLA.bit.SWRST = 1; - while (SERCOM2->SPI.SYNCBUSY.bit.SWRST); +//#define - // Set up SPI in master mode, MSB first, SPI mode 0 - uint8_t const mosi_pad = 0; - uint8_t const miso_pad = 2; - SERCOM2->SPI.CTRLA.reg = SERCOM_SPI_CTRLA_MODE(3) | SERCOM_SPI_CTRLA_DOPO(mosi_pad) | SERCOM_SPI_CTRLA_DIPO(miso_pad); - - SERCOM2->SPI.CTRLB.reg = SERCOM_SPI_CTRLB_CHSIZE(0) | SERCOM_SPI_CTRLB_RXEN; - while( SERCOM2->SPI.SYNCBUSY.bit.CTRLB == 1 ); - - // Set the baud rate - uint32_t baudrate = 4000000u; - SERCOM2->SPI.BAUD.reg = (uint8_t)(SystemCoreClock / (2 * baudrate) - 1); // Replace 1000000 with your desired baud rate - - // Configure PA12 as MOSI (PAD0), PA13 as SCK (PAD1), PA14 as MISO (PAD2) - // 2 function C: PIO_SERCOM - gpio_set_pin_direction(MAX3421E_SCK_PIN, GPIO_DIRECTION_OUT); - gpio_set_pin_pull_mode(MAX3421E_SCK_PIN, GPIO_PULL_OFF); - gpio_set_pin_function(MAX3421E_SCK_PIN, 2); - - gpio_set_pin_direction(MAX3421E_MOSI_PIN, GPIO_DIRECTION_OUT); - gpio_set_pin_pull_mode(MAX3421E_MOSI_PIN, GPIO_PULL_OFF); - gpio_set_pin_function(MAX3421E_MOSI_PIN, 2); - - gpio_set_pin_direction(MAX3421E_MISO_PIN, GPIO_DIRECTION_IN); - gpio_set_pin_pull_mode(MAX3421E_MISO_PIN, GPIO_PULL_OFF); - gpio_set_pin_function(MAX3421E_MISO_PIN, 2); - - // Enable the SPI module - SERCOM2->SPI.CTRLA.bit.ENABLE = 1; - while (SERCOM2->SPI.SYNCBUSY.bit.ENABLE); -} #endif void board_init(void) { @@ -180,46 +136,7 @@ void board_init(void) { gpio_set_pin_function(PIN_PA25, PINMUX_PA25H_USB_DP); #if CFG_TUH_ENABLED && defined(CFG_TUH_MAX3421) && CFG_TUH_MAX3421 - // CS pin - gpio_set_pin_direction(MAX3421E_CS_PIN, GPIO_DIRECTION_OUT); - gpio_set_pin_level(MAX3421E_CS_PIN, 1); - - // SPI max3421_init(); - - // INT pin with external interrupt - gpio_set_pin_direction(MAX3241E_INTR_PIN, GPIO_DIRECTION_IN); - gpio_set_pin_pull_mode(MAX3241E_INTR_PIN, GPIO_PULL_UP); - - // Enable the APB clock for EIC (External Interrupt Controller) - MCLK->APBAMASK.reg |= MCLK_APBAMASK_EIC; - - // Configure GCLK for EIC - GCLK->PCHCTRL[EIC_GCLK_ID].reg = GCLK_PCHCTRL_GEN_GCLK0_Val | (1 << GCLK_PCHCTRL_CHEN_Pos); - - // Configure PA20 as an input - PORT->Group[0].DIRCLR.reg = PORT_PA20; - PORT->Group[0].PINCFG[20].reg = PORT_PINCFG_INEN | PORT_PINCFG_PULLEN; - PORT->Group[0].OUTSET.reg = PORT_PA20; // Enable pull-up - - // Configure PA20 to use EIC - PORT->Group[0].PMUX[10].bit.PMUXE = MUX_PA20A_EIC_EXTINT4; - PORT->Group[0].PINCFG[20].bit.PMUXEN = 1; - - // Disable EIC - EIC->CTRLA.bit.ENABLE = 0; - while (EIC->SYNCBUSY.bit.ENABLE); - - // Configure EXTINT4 (PA20) to trigger on falling edge - EIC->CONFIG[0].reg |= EIC_CONFIG_SENSE4_FALL; - - // Enable EXTINT4 - EIC->INTENSET.reg = EIC_INTENSET_EXTINT(1 << 4); - - // Enable EIC - EIC->CTRLA.bit.ENABLE = 1; - while (EIC->SYNCBUSY.bit.ENABLE); - #endif } @@ -264,8 +181,91 @@ uint32_t board_millis(void) { //--------------------------------------------------------------------+ #if CFG_TUH_ENABLED && defined(CFG_TUH_MAX3421) && CFG_TUH_MAX3421 -void EIC_4_Handler(void) -{ +static void max3421_init(void) { + // CS pin + gpio_set_pin_direction(MAX3421_CS_PIN, GPIO_DIRECTION_OUT); + gpio_set_pin_level(MAX3421_CS_PIN, 1); + + //------------- SPI Init -------------// + + // Enable the APB clock for SERCOM2 + MCLK->APBBMASK.reg |= MCLK_APBBMASK_SERCOM2; + + // Configure GCLK for SERCOM2, initClockNVIC() + GCLK->PCHCTRL[SERCOM2_GCLK_ID_CORE].reg = GCLK_PCHCTRL_GEN_GCLK0_Val | (1 << GCLK_PCHCTRL_CHEN_Pos); + GCLK->PCHCTRL[SERCOM2_GCLK_ID_SLOW].reg = GCLK_PCHCTRL_GEN_GCLK3_Val | (1 << GCLK_PCHCTRL_CHEN_Pos); + + // Disable the SPI module + SERCOM2->SPI.CTRLA.bit.ENABLE = 0; + + // Reset the SPI module + SERCOM2->SPI.CTRLA.bit.SWRST = 1; + while (SERCOM2->SPI.SYNCBUSY.bit.SWRST); + + // Set up SPI in master mode, MSB first, SPI mode 0 + uint8_t const mosi_pad = 0; + uint8_t const miso_pad = 2; + SERCOM2->SPI.CTRLA.reg = SERCOM_SPI_CTRLA_MODE(3) | SERCOM_SPI_CTRLA_DOPO(mosi_pad) | SERCOM_SPI_CTRLA_DIPO(miso_pad); + + SERCOM2->SPI.CTRLB.reg = SERCOM_SPI_CTRLB_CHSIZE(0) | SERCOM_SPI_CTRLB_RXEN; + while (SERCOM2->SPI.SYNCBUSY.bit.CTRLB == 1); + + // Set the baud rate + uint32_t baudrate = 4000000u; + SERCOM2->SPI.BAUD.reg = (uint8_t) (SystemCoreClock / (2 * baudrate) - + 1); // Replace 1000000 with your desired baud rate + + // Configure PA12 as MOSI (PAD0), PA13 as SCK (PAD1), PA14 as MISO (PAD2) + // 2 function C: PIO_SERCOM + gpio_set_pin_direction(MAX3421_SCK_PIN, GPIO_DIRECTION_OUT); + gpio_set_pin_pull_mode(MAX3421_SCK_PIN, GPIO_PULL_OFF); + gpio_set_pin_function(MAX3421_SCK_PIN, 2); + + gpio_set_pin_direction(MAX3421_MOSI_PIN, GPIO_DIRECTION_OUT); + gpio_set_pin_pull_mode(MAX3421_MOSI_PIN, GPIO_PULL_OFF); + gpio_set_pin_function(MAX3421_MOSI_PIN, 2); + + gpio_set_pin_direction(MAX3421_MISO_PIN, GPIO_DIRECTION_IN); + gpio_set_pin_pull_mode(MAX3421_MISO_PIN, GPIO_PULL_OFF); + gpio_set_pin_function(MAX3421_MISO_PIN, 2); + + // Enable the SPI module + SERCOM2->SPI.CTRLA.bit.ENABLE = 1; + while (SERCOM2->SPI.SYNCBUSY.bit.ENABLE); + + //------------- External Interrupt -------------// + + // INT pin with external interrupt + gpio_set_pin_direction(MAX3421_INTR_PIN, GPIO_DIRECTION_IN); + gpio_set_pin_pull_mode(MAX3421_INTR_PIN, GPIO_PULL_UP); + + // Enable the APB clock for EIC (External Interrupt Controller) + MCLK->APBAMASK.reg |= MCLK_APBAMASK_EIC; + + // Configure GCLK for EIC + GCLK->PCHCTRL[EIC_GCLK_ID].reg = GCLK_PCHCTRL_GEN_GCLK0_Val | (1 << GCLK_PCHCTRL_CHEN_Pos); + + // Configure PA20 as an input with function A (external interrupt) + gpio_set_pin_direction(MAX3421_INTR_PIN, GPIO_DIRECTION_IN); + gpio_set_pin_pull_mode(MAX3421_INTR_PIN, GPIO_PULL_UP); + gpio_set_pin_function(MAX3421_INTR_PIN, 0); + + // Disable EIC + EIC->CTRLA.bit.ENABLE = 0; + while (EIC->SYNCBUSY.bit.ENABLE); + + // Configure EXTINT4 (PA20) to trigger on falling edge + EIC->CONFIG[0].reg |= EIC_CONFIG_SENSE4_FALL; + + // Enable EXTINT4 + EIC->INTENSET.reg = EIC_INTENSET_EXTINT(1 << 4); + + // Enable EIC + EIC->CTRLA.bit.ENABLE = 1; + while (EIC->SYNCBUSY.bit.ENABLE); +} + +void EIC_4_Handler(void) { // Clear the interrupt flag EIC->INTFLAG.reg = EIC_INTFLAG_EXTINT(1 << 4); @@ -273,7 +273,7 @@ void EIC_4_Handler(void) tuh_int_handler(1); } -void tuh_max3421e_int_api(uint8_t rhport, bool enabled) { +void tuh_max3421_int_api(uint8_t rhport, bool enabled) { (void) rhport; if (enabled) { @@ -285,7 +285,7 @@ void tuh_max3421e_int_api(uint8_t rhport, bool enabled) { void tuh_max3421_spi_cs_api(uint8_t rhport, bool active) { (void) rhport; - gpio_set_pin_level(MAX3421E_CS_PIN, active ? 0 : 1); + gpio_set_pin_level(MAX3421_CS_PIN, active ? 0 : 1); } bool tuh_max3421_spi_xfer_api(uint8_t rhport, uint8_t const *tx_buf, size_t tx_len, uint8_t *rx_buf, size_t rx_len) { @@ -299,7 +299,7 @@ bool tuh_max3421_spi_xfer_api(uint8_t rhport, uint8_t const *tx_buf, size_t tx_l // Write data to be transmitted uint8_t data = 0x00; if (count < tx_len) { - data = tx_buf[count]; + data = tx_buf[count]; } SERCOM2->SPI.DATA.reg = (uint32_t) data; @@ -322,6 +322,7 @@ bool tuh_max3421_spi_xfer_api(uint8_t rhport, uint8_t const *tx_buf, size_t tx_l return true; } + #endif #endif diff --git a/src/portable/analog/max3421/hcd_max3421.c b/src/portable/analog/max3421/hcd_max3421.c index 95cf5516e9..238b518a0e 100644 --- a/src/portable/analog/max3421/hcd_max3421.c +++ b/src/portable/analog/max3421/hcd_max3421.c @@ -212,7 +212,7 @@ static max3421_data_t _hcd_data; void tuh_max3421_spi_cs_api(uint8_t rhport, bool active); bool tuh_max3421_spi_xfer_api(uint8_t rhport, uint8_t const * tx_buf, size_t tx_len, uint8_t * rx_buf, size_t rx_len); -void tuh_max3421e_int_api(uint8_t rhport, bool enabled); +void tuh_max3421_int_api(uint8_t rhport, bool enabled); static void handle_connect_irq(uint8_t rhport, bool in_isr); static inline void hirq_write(uint8_t rhport, uint8_t data, bool in_isr); @@ -225,7 +225,7 @@ static void max3421_spi_lock(uint8_t rhport, bool in_isr) { // disable interrupt and mutex lock (for pre-emptive RTOS) if not in_isr if (!in_isr) { (void) osal_mutex_lock(_hcd_data.spi_mutex, OSAL_TIMEOUT_WAIT_FOREVER); - tuh_max3421e_int_api(rhport, false); + tuh_max3421_int_api(rhport, false); } // assert CS @@ -238,7 +238,7 @@ static void max3421_spi_unlock(uint8_t rhport, bool in_isr) { // mutex unlock and re-enable interrupt if (!in_isr) { - tuh_max3421e_int_api(rhport, true); + tuh_max3421_int_api(rhport, true); (void) osal_mutex_unlock(_hcd_data.spi_mutex); } } @@ -411,7 +411,7 @@ bool hcd_configure(uint8_t rhport, uint32_t cfg_id, const void* cfg_param) { bool hcd_init(uint8_t rhport) { (void) rhport; - tuh_max3421e_int_api(rhport, false); + tuh_max3421_int_api(rhport, false); tuh_max3421_spi_cs_api(rhport, false); TU_LOG2_INT(sizeof(max3421_ep_t)); @@ -450,7 +450,7 @@ bool hcd_init(uint8_t rhport) { // Enable IRQ hien_write(rhport, DEFAULT_HIEN, false); - tuh_max3421e_int_api(rhport, true); + tuh_max3421_int_api(rhport, true); // Enable Interrupt pin reg_write(rhport, CPUCTL_ADDR, CPUCTL_IE, false); @@ -461,13 +461,13 @@ bool hcd_init(uint8_t rhport) { // Enable USB interrupt // Not actually enable GPIO interrupt, just set variable to prevent handler to process void hcd_int_enable (uint8_t rhport) { - tuh_max3421e_int_api(rhport, true); + tuh_max3421_int_api(rhport, true); } // Disable USB interrupt // Not actually disable GPIO interrupt, just set variable to prevent handler to process void hcd_int_disable(uint8_t rhport) { - tuh_max3421e_int_api(rhport, false); + tuh_max3421_int_api(rhport, false); } // Get frame number (1ms) From 605ad73ec02033aa6b66e6899e232537ca2354bb Mon Sep 17 00:00:00 2001 From: hathach Date: Sat, 9 Sep 2023 13:04:36 +0700 Subject: [PATCH 30/34] refactor max3421_init() for samd51 to be generic for sercom and eic --- hw/bsp/samd51/boards/metro_m4_express/board.h | 17 +-- hw/bsp/samd51/family.c | 112 +++++++++++------- 2 files changed, 80 insertions(+), 49 deletions(-) diff --git a/hw/bsp/samd51/boards/metro_m4_express/board.h b/hw/bsp/samd51/boards/metro_m4_express/board.h index fe2a867a4d..aa6bdd0c8c 100644 --- a/hw/bsp/samd51/boards/metro_m4_express/board.h +++ b/hw/bsp/samd51/boards/metro_m4_express/board.h @@ -44,13 +44,16 @@ #define UART_RX_PIN 22 // SPI for USB host shield -#define MAX3421_SERCOM 2 // SERCOM2 -#define MAX3421_SCK_PIN 13 -#define MAX3421_MOSI_PIN 12 -#define MAX3421_MISO_PIN 14 -#define MAX3421_CS_PIN 18 // D10 -#define MAX3421_INTR_PIN 20 // D9 - +#define MAX3421_SERCOM_ID 2 // SERCOM2 +#define MAX3421_SCK_PIN 13 +#define MAX3421_MOSI_PIN 12 +#define MAX3421_MOSI_PAD 0 +#define MAX3421_MISO_PIN 14 +#define MAX3421_MISO_PAD 2 +#define MAX3421_CS_PIN 18 // D10 + +#define MAX3421_INTR_PIN 20 // D9 +#define MAX3421_INTR_EIC_ID 4 // EIC4 #ifdef __cplusplus } diff --git a/hw/bsp/samd51/family.c b/hw/bsp/samd51/family.c index 34dd93cef7..f9e1718d0e 100644 --- a/hw/bsp/samd51/family.c +++ b/hw/bsp/samd51/family.c @@ -79,7 +79,8 @@ void USB_3_Handler(void) { #if CFG_TUH_ENABLED && defined(CFG_TUH_MAX3421) && CFG_TUH_MAX3421 static void max3421_init(void); -//#define +#define MAX3421_SERCOM TU_XSTRCAT(SERCOM, MAX3421_SERCOM_ID) +#define MAX3421_EIC_Handler TU_XSTRCAT3(EIC_, MAX3421_INTR_EIC_ID, _Handler) #endif @@ -182,41 +183,55 @@ uint32_t board_millis(void) { #if CFG_TUH_ENABLED && defined(CFG_TUH_MAX3421) && CFG_TUH_MAX3421 static void max3421_init(void) { - // CS pin - gpio_set_pin_direction(MAX3421_CS_PIN, GPIO_DIRECTION_OUT); - gpio_set_pin_level(MAX3421_CS_PIN, 1); - //------------- SPI Init -------------// - - // Enable the APB clock for SERCOM2 - MCLK->APBBMASK.reg |= MCLK_APBBMASK_SERCOM2; - - // Configure GCLK for SERCOM2, initClockNVIC() - GCLK->PCHCTRL[SERCOM2_GCLK_ID_CORE].reg = GCLK_PCHCTRL_GEN_GCLK0_Val | (1 << GCLK_PCHCTRL_CHEN_Pos); - GCLK->PCHCTRL[SERCOM2_GCLK_ID_SLOW].reg = GCLK_PCHCTRL_GEN_GCLK3_Val | (1 << GCLK_PCHCTRL_CHEN_Pos); + uint32_t const baudrate = 4000000u; + + struct { + volatile uint32_t *mck_apb; + uint32_t mask; + uint8_t gclk_id_core; + uint8_t gclk_id_slow; + } const sercom_clock[] = { + { &MCLK->APBAMASK.reg, MCLK_APBAMASK_SERCOM0, SERCOM0_GCLK_ID_CORE, SERCOM0_GCLK_ID_SLOW }, + { &MCLK->APBAMASK.reg, MCLK_APBAMASK_SERCOM1, SERCOM1_GCLK_ID_CORE, SERCOM1_GCLK_ID_SLOW }, + { &MCLK->APBBMASK.reg, MCLK_APBBMASK_SERCOM2, SERCOM2_GCLK_ID_CORE, SERCOM2_GCLK_ID_SLOW }, + { &MCLK->APBBMASK.reg, MCLK_APBBMASK_SERCOM3, SERCOM3_GCLK_ID_CORE, SERCOM3_GCLK_ID_SLOW }, + { &MCLK->APBDMASK.reg, MCLK_APBDMASK_SERCOM4, SERCOM4_GCLK_ID_CORE, SERCOM4_GCLK_ID_SLOW }, + { &MCLK->APBDMASK.reg, MCLK_APBDMASK_SERCOM5, SERCOM5_GCLK_ID_CORE, SERCOM5_GCLK_ID_SLOW }, + #ifdef SERCOM6_GCLK_ID_CORE + { &MCLK->APBDMASK.reg, MCLK_APBDMASK_SERCOM6, SERCOM6_GCLK_ID_CORE, SERCOM6_GCLK_ID_SLOW }, + #endif + #ifdef SERCOM7_GCLK_ID_CORE + { &MCLK->APBDMASK.reg, MCLK_APBDMASK_SERCOM7, SERCOM7_GCLK_ID_CORE, SERCOM7_GCLK_ID_SLOW }, + #endif + }; + + Sercom* sercom = MAX3421_SERCOM; + + // Enable the APB clock for SERCOM + *sercom_clock[MAX3421_SERCOM_ID].mck_apb |= sercom_clock[MAX3421_SERCOM_ID].mask; + + // Configure GCLK for SERCOM + GCLK->PCHCTRL[sercom_clock[MAX3421_SERCOM_ID].gclk_id_core].reg = GCLK_PCHCTRL_GEN_GCLK0_Val | (1 << GCLK_PCHCTRL_CHEN_Pos); + GCLK->PCHCTRL[sercom_clock[MAX3421_SERCOM_ID].gclk_id_slow].reg = GCLK_PCHCTRL_GEN_GCLK3_Val | (1 << GCLK_PCHCTRL_CHEN_Pos); // Disable the SPI module - SERCOM2->SPI.CTRLA.bit.ENABLE = 0; + sercom->SPI.CTRLA.bit.ENABLE = 0; // Reset the SPI module - SERCOM2->SPI.CTRLA.bit.SWRST = 1; - while (SERCOM2->SPI.SYNCBUSY.bit.SWRST); + sercom->SPI.CTRLA.bit.SWRST = 1; + while (sercom->SPI.SYNCBUSY.bit.SWRST); // Set up SPI in master mode, MSB first, SPI mode 0 - uint8_t const mosi_pad = 0; - uint8_t const miso_pad = 2; - SERCOM2->SPI.CTRLA.reg = SERCOM_SPI_CTRLA_MODE(3) | SERCOM_SPI_CTRLA_DOPO(mosi_pad) | SERCOM_SPI_CTRLA_DIPO(miso_pad); + sercom->SPI.CTRLA.reg = SERCOM_SPI_CTRLA_MODE(3) | SERCOM_SPI_CTRLA_DOPO(MAX3421_MOSI_PAD) | SERCOM_SPI_CTRLA_DIPO(MAX3421_MISO_PAD); - SERCOM2->SPI.CTRLB.reg = SERCOM_SPI_CTRLB_CHSIZE(0) | SERCOM_SPI_CTRLB_RXEN; - while (SERCOM2->SPI.SYNCBUSY.bit.CTRLB == 1); + sercom->SPI.CTRLB.reg = SERCOM_SPI_CTRLB_CHSIZE(0) | SERCOM_SPI_CTRLB_RXEN; + while (sercom->SPI.SYNCBUSY.bit.CTRLB == 1); // Set the baud rate - uint32_t baudrate = 4000000u; - SERCOM2->SPI.BAUD.reg = (uint8_t) (SystemCoreClock / (2 * baudrate) - - 1); // Replace 1000000 with your desired baud rate + sercom->SPI.BAUD.reg = (uint8_t) (SystemCoreClock / (2 * baudrate) - 1); - // Configure PA12 as MOSI (PAD0), PA13 as SCK (PAD1), PA14 as MISO (PAD2) - // 2 function C: PIO_SERCOM + // Configure PA12 as MOSI (PAD0), PA13 as SCK (PAD1), PA14 as MISO (PAD2), function C (sercom) gpio_set_pin_direction(MAX3421_SCK_PIN, GPIO_DIRECTION_OUT); gpio_set_pin_pull_mode(MAX3421_SCK_PIN, GPIO_PULL_OFF); gpio_set_pin_function(MAX3421_SCK_PIN, 2); @@ -229,16 +244,16 @@ static void max3421_init(void) { gpio_set_pin_pull_mode(MAX3421_MISO_PIN, GPIO_PULL_OFF); gpio_set_pin_function(MAX3421_MISO_PIN, 2); + // CS pin + gpio_set_pin_direction(MAX3421_CS_PIN, GPIO_DIRECTION_OUT); + gpio_set_pin_level(MAX3421_CS_PIN, 1); + // Enable the SPI module - SERCOM2->SPI.CTRLA.bit.ENABLE = 1; - while (SERCOM2->SPI.SYNCBUSY.bit.ENABLE); + sercom->SPI.CTRLA.bit.ENABLE = 1; + while (sercom->SPI.SYNCBUSY.bit.ENABLE); //------------- External Interrupt -------------// - // INT pin with external interrupt - gpio_set_pin_direction(MAX3421_INTR_PIN, GPIO_DIRECTION_IN); - gpio_set_pin_pull_mode(MAX3421_INTR_PIN, GPIO_PULL_UP); - // Enable the APB clock for EIC (External Interrupt Controller) MCLK->APBAMASK.reg |= MCLK_APBAMASK_EIC; @@ -255,19 +270,30 @@ static void max3421_init(void) { while (EIC->SYNCBUSY.bit.ENABLE); // Configure EXTINT4 (PA20) to trigger on falling edge - EIC->CONFIG[0].reg |= EIC_CONFIG_SENSE4_FALL; + volatile uint32_t * eic_config; + uint8_t sense_shift; + if ( MAX3421_INTR_EIC_ID < 8 ) { + eic_config = &EIC->CONFIG[0].reg; + sense_shift = MAX3421_INTR_EIC_ID * 4; + } else { + eic_config = &EIC->CONFIG[1].reg; + sense_shift = (MAX3421_INTR_EIC_ID - 8) * 4; + } - // Enable EXTINT4 - EIC->INTENSET.reg = EIC_INTENSET_EXTINT(1 << 4); + *eic_config &= ~(7 << sense_shift); + *eic_config |= 2 << sense_shift; + + // Enable External Interrupt + EIC->INTENSET.reg = EIC_INTENSET_EXTINT(1 << MAX3421_INTR_EIC_ID); // Enable EIC EIC->CTRLA.bit.ENABLE = 1; while (EIC->SYNCBUSY.bit.ENABLE); } -void EIC_4_Handler(void) { +void MAX3421_EIC_Handler(void) { // Clear the interrupt flag - EIC->INTFLAG.reg = EIC_INTFLAG_EXTINT(1 << 4); + EIC->INTFLAG.reg = EIC_INTFLAG_EXTINT(1 << MAX3421_INTR_EIC_ID); // Call the TinyUSB interrupt handler tuh_int_handler(1); @@ -291,10 +317,12 @@ void tuh_max3421_spi_cs_api(uint8_t rhport, bool active) { bool tuh_max3421_spi_xfer_api(uint8_t rhport, uint8_t const *tx_buf, size_t tx_len, uint8_t *rx_buf, size_t rx_len) { (void) rhport; + Sercom* sercom = MAX3421_SERCOM; + size_t count = 0; while (count < tx_len || count < rx_len) { // Wait for the transmit buffer to be empty - while (!SERCOM2->SPI.INTFLAG.bit.DRE); + while (!sercom->SPI.INTFLAG.bit.DRE); // Write data to be transmitted uint8_t data = 0x00; @@ -302,13 +330,13 @@ bool tuh_max3421_spi_xfer_api(uint8_t rhport, uint8_t const *tx_buf, size_t tx_l data = tx_buf[count]; } - SERCOM2->SPI.DATA.reg = (uint32_t) data; + sercom->SPI.DATA.reg = (uint32_t) data; // Wait for the receive buffer to be filled - while (!SERCOM2->SPI.INTFLAG.bit.RXC); + while (!sercom->SPI.INTFLAG.bit.RXC); // Read received data - data = (uint8_t) SERCOM2->SPI.DATA.reg; + data = (uint8_t) sercom->SPI.DATA.reg; if (count < rx_len) { rx_buf[count] = data; } @@ -317,8 +345,8 @@ bool tuh_max3421_spi_xfer_api(uint8_t rhport, uint8_t const *tx_buf, size_t tx_l } // wait for bus idle and clear flags - while (!(SERCOM2->SPI.INTFLAG.reg & (SERCOM_SPI_INTFLAG_TXC | SERCOM_SPI_INTFLAG_DRE))); - SERCOM2->SPI.INTFLAG.reg = SERCOM_SPI_INTFLAG_TXC | SERCOM_SPI_INTFLAG_DRE; + while (!(sercom->SPI.INTFLAG.reg & (SERCOM_SPI_INTFLAG_TXC | SERCOM_SPI_INTFLAG_DRE))); + sercom->SPI.INTFLAG.reg = SERCOM_SPI_INTFLAG_TXC | SERCOM_SPI_INTFLAG_DRE; return true; } From e32c1e08bd701b5dda7d081b10ba3262e2061326 Mon Sep 17 00:00:00 2001 From: hathach Date: Sat, 9 Sep 2023 16:50:16 +0700 Subject: [PATCH 31/34] both samd21/d51 works perfectly with max3421e --- hw/bsp/samd21/boards/metro_m0_express/board.h | 16 ++ hw/bsp/samd21/family.c | 226 +++++++++++++++--- hw/bsp/samd21/family.cmake | 1 + hw/bsp/samd51/boards/metro_m4_express/board.h | 24 +- hw/bsp/samd51/family.c | 19 +- 5 files changed, 233 insertions(+), 53 deletions(-) diff --git a/hw/bsp/samd21/boards/metro_m0_express/board.h b/hw/bsp/samd21/boards/metro_m0_express/board.h index d26aae53c7..6dd53e901b 100644 --- a/hw/bsp/samd21/boards/metro_m0_express/board.h +++ b/hw/bsp/samd21/boards/metro_m0_express/board.h @@ -43,6 +43,22 @@ #define UART_RX_PIN 4 #define UART_TX_PIN 5 +// SPI for USB host shield +#define MAX3421_SERCOM_ID 4 // SERCOM4 +#define MAX3421_SERCOM_FUNCTION 3 // function D (Sercom Alt) + +#define MAX3421_SCK_PIN (32+11) +#define MAX3421_MOSI_PIN (32+10) +#define MAX3421_MISO_PIN 12 +#define MAX3421_TX_PAD 1 // MOSI = PAD_2, SCK = PAD_3 +#define MAX3421_RX_PAD 0 // MISO = PAD_2 + +#define MAX3421_CS_PIN 18 // D10 + +#define MAX3421_INTR_PIN 7 // D9 +#define MAX3421_INTR_EIC_ID 7 // EIC7 + + #ifdef __cplusplus } #endif diff --git a/hw/bsp/samd21/family.c b/hw/bsp/samd21/family.c index 2121e028a4..cfe66b8dc5 100644 --- a/hw/bsp/samd21/family.c +++ b/hw/bsp/samd21/family.c @@ -46,31 +46,35 @@ #pragma GCC diagnostic pop #endif +//--------------------------------------------------------------------+ +// MACRO TYPEDEF CONSTANT ENUM DECLARATION +//--------------------------------------------------------------------+ + +/* Referenced GCLKs, should be initialized firstly */ +#define _GCLK_INIT_1ST (1 << 0 | 1 << 1) + +/* Not referenced GCLKs, initialized last */ +#define _GCLK_INIT_LAST (~_GCLK_INIT_1ST) + //--------------------------------------------------------------------+ // Forward USB interrupt events to TinyUSB IRQ Handler //--------------------------------------------------------------------+ -void USB_Handler(void) -{ +void USB_Handler(void) { tud_int_handler(0); } //--------------------------------------------------------------------+ -// UART support +// Implementation //--------------------------------------------------------------------+ static void uart_init(void); -//--------------------------------------------------------------------+ -// MACRO TYPEDEF CONSTANT ENUM DECLARATION -//--------------------------------------------------------------------+ - -/* Referenced GCLKs, should be initialized firstly */ -#define _GCLK_INIT_1ST (1 << 0 | 1 << 1) +#if CFG_TUH_ENABLED && defined(CFG_TUH_MAX3421) && CFG_TUH_MAX3421 +#define MAX3421_SERCOM TU_XSTRCAT(SERCOM, MAX3421_SERCOM_ID) -/* Not referenced GCLKs, initialized last */ -#define _GCLK_INIT_LAST (~_GCLK_INIT_1ST) +static void max3421_init(void); +#endif -void board_init(void) -{ +void board_init(void) { // Clock init ( follow hpl_init.c ) hri_nvmctrl_set_CTRLB_RWS_bf(NVMCTRL, 2); @@ -85,7 +89,7 @@ void board_init(void) // Update SystemCoreClock since it is hard coded with asf4 and not correct // Init 1ms tick timer (samd SystemCoreClock may not correct) SystemCoreClock = CONF_CPU_FREQUENCY; -#if CFG_TUSB_OS == OPT_OS_NONE +#if CFG_TUSB_OS == OPT_OS_NONE SysTick_Config(CONF_CPU_FREQUENCY / 1000); #endif @@ -103,7 +107,7 @@ void board_init(void) uart_init(); -#if CFG_TUSB_OS == OPT_OS_FREERTOS +#if CFG_TUSB_OS == OPT_OS_FREERTOS // If freeRTOS is used, IRQ priority is limit by max syscall ( smaller is higher ) NVIC_SetPriority(USB_IRQn, configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY); #endif @@ -134,22 +138,24 @@ void board_init(void) gpio_set_pin_function(PIN_PA19, PINMUX_PA19F_TCC0_WO3); _gclk_enable_channel(TCC0_GCLK_ID, GCLK_CLKCTRL_GEN_GCLK0_Val); + +#if CFG_TUH_ENABLED && defined(CFG_TUH_MAX3421) && CFG_TUH_MAX3421 + max3421_init(); +#endif } //--------------------------------------------------------------------+ // Board porting API //--------------------------------------------------------------------+ -void board_led_write(bool state) -{ - (void)state; +void board_led_write(bool state) { + (void) state; #ifdef LED_PIN - gpio_set_pin_level(LED_PIN, state ? LED_STATE_ON : (1-LED_STATE_ON)); + gpio_set_pin_level(LED_PIN, state ? LED_STATE_ON : (1 - LED_STATE_ON)); #endif } -uint32_t board_button_read(void) -{ +uint32_t board_button_read(void) { #ifdef BUTTON_PIN return BUTTON_STATE_ACTIVE == gpio_get_pin_level(BUTTON_PIN); #else @@ -227,33 +233,185 @@ int board_uart_write(void const * buf, int len) } #else // ! defined(UART_SERCOM) -static void uart_init(void) -{ +static void uart_init(void) { } -int board_uart_read(uint8_t* buf, int len) -{ - (void) buf; (void) len; +int board_uart_read(uint8_t *buf, int len) { + (void) buf; + (void) len; return 0; } -int board_uart_write(void const * buf, int len) -{ - (void) buf; (void) len; +int board_uart_write(void const *buf, int len) { + (void) buf; + (void) len; return 0; } + #endif -#if CFG_TUSB_OS == OPT_OS_NONE +#if CFG_TUSB_OS == OPT_OS_NONE volatile uint32_t system_ticks = 0; -void SysTick_Handler (void) -{ + +void SysTick_Handler(void) { system_ticks++; } -uint32_t board_millis(void) -{ +uint32_t board_millis(void) { return system_ticks; } + +//--------------------------------------------------------------------+ +// +//--------------------------------------------------------------------+ +#if CFG_TUH_ENABLED && defined(CFG_TUH_MAX3421) && CFG_TUH_MAX3421 + +static void max3421_init(void) { + //------------- SPI Init -------------// + uint32_t const baudrate = 4000000u; + + // Enable the APB clock for SERCOM + PM->APBCMASK.reg |= 1u << (PM_APBCMASK_SERCOM0_Pos + MAX3421_SERCOM_ID); + + // Configure GCLK for SERCOM +// GCLK->CLKCTRL.reg = GCLK_CLKCTRL_ID_SERCOM4_CORE | GCLK_CLKCTRL_GEN_GCLK0 | GCLK_CLKCTRL_CLKEN; + GCLK->CLKCTRL.reg = GCLK_CLKCTRL_ID(GCLK_CLKCTRL_ID_SERCOM0_CORE_Val+MAX3421_SERCOM_ID) | + GCLK_CLKCTRL_GEN_GCLK0 | GCLK_CLKCTRL_CLKEN; + while (GCLK->STATUS.bit.SYNCBUSY); + + Sercom* sercom = MAX3421_SERCOM; + + // Disable the SPI module + sercom->SPI.CTRLA.bit.ENABLE = 0; + + // Reset the SPI module + sercom->SPI.CTRLA.bit.SWRST = 1; + while (sercom->SPI.SYNCBUSY.bit.SWRST); + + // Set up SPI in master mode, MSB first, SPI mode 0 + sercom->SPI.CTRLA.reg = SERCOM_SPI_CTRLA_DOPO(MAX3421_TX_PAD) | SERCOM_SPI_CTRLA_DIPO(MAX3421_RX_PAD) | + SERCOM_SPI_CTRLA_MODE(3); + + sercom->SPI.CTRLB.reg = SERCOM_SPI_CTRLB_CHSIZE(0) | SERCOM_SPI_CTRLB_RXEN; + while (sercom->SPI.SYNCBUSY.bit.CTRLB == 1); + + // Set the baud rate + sercom->SPI.BAUD.reg = (uint8_t) (SystemCoreClock / (2 * baudrate) - 1); + + // Configure PA12 as MOSI (PAD0), PA13 as SCK (PAD1), PA14 as MISO (PAD2), function C (sercom) + gpio_set_pin_direction(MAX3421_SCK_PIN, GPIO_DIRECTION_OUT); + gpio_set_pin_pull_mode(MAX3421_SCK_PIN, GPIO_PULL_OFF); + gpio_set_pin_function(MAX3421_SCK_PIN, MAX3421_SERCOM_FUNCTION); + + gpio_set_pin_direction(MAX3421_MOSI_PIN, GPIO_DIRECTION_OUT); + gpio_set_pin_pull_mode(MAX3421_MOSI_PIN, GPIO_PULL_OFF); + gpio_set_pin_function(MAX3421_MOSI_PIN, MAX3421_SERCOM_FUNCTION); + + gpio_set_pin_direction(MAX3421_MISO_PIN, GPIO_DIRECTION_IN); + gpio_set_pin_pull_mode(MAX3421_MISO_PIN, GPIO_PULL_OFF); + gpio_set_pin_function(MAX3421_MISO_PIN, MAX3421_SERCOM_FUNCTION); + + // CS pin + gpio_set_pin_direction(MAX3421_CS_PIN, GPIO_DIRECTION_OUT); + gpio_set_pin_level(MAX3421_CS_PIN, 1); + + // Enable the SPI module + sercom->SPI.CTRLA.bit.ENABLE = 1; + while (sercom->SPI.SYNCBUSY.bit.ENABLE); + + //------------- External Interrupt -------------// + + // Enable the APB clock for EIC (External Interrupt Controller) + PM->APBAMASK.reg |= PM_APBAMASK_EIC; + + // Configure GCLK for EIC + GCLK->CLKCTRL.reg = GCLK_CLKCTRL_ID_EIC | GCLK_CLKCTRL_GEN_GCLK0 | GCLK_CLKCTRL_CLKEN; + while (GCLK->STATUS.bit.SYNCBUSY); + + // Configure PA20 as an input with function A (external interrupt) + gpio_set_pin_direction(MAX3421_INTR_PIN, GPIO_DIRECTION_IN); + gpio_set_pin_pull_mode(MAX3421_INTR_PIN, GPIO_PULL_UP); + gpio_set_pin_function(MAX3421_INTR_PIN, 0); + + // Disable EIC + EIC->CTRL.bit.ENABLE = 0; + while (EIC->STATUS.bit.SYNCBUSY); + + // Configure EIC to trigger on falling edge + uint8_t const sense_shift = MAX3421_INTR_EIC_ID * 4; + EIC->CONFIG[0].reg &= ~(7 << sense_shift); + EIC->CONFIG[0].reg |= 2 << sense_shift; + + // Enable External Interrupt + EIC->INTENSET.reg = EIC_INTENSET_EXTINT(1 << MAX3421_INTR_EIC_ID); + + // Enable EIC + EIC->CTRL.bit.ENABLE = 1; + while (EIC->STATUS.bit.SYNCBUSY); +} + +void EIC_Handler(void) { + // Clear the interrupt flag + EIC->INTFLAG.reg = EIC_INTFLAG_EXTINT(1 << MAX3421_INTR_EIC_ID); + + // Call the TinyUSB interrupt handler + tuh_int_handler(1); +} + +void tuh_max3421_int_api(uint8_t rhport, bool enabled) { + (void) rhport; + + if (enabled) { + NVIC_EnableIRQ(EIC_IRQn); + } else { + NVIC_DisableIRQ(EIC_IRQn); + } +} + +void tuh_max3421_spi_cs_api(uint8_t rhport, bool active) { + (void) rhport; + gpio_set_pin_level(MAX3421_CS_PIN, active ? 0 : 1); +} + +bool tuh_max3421_spi_xfer_api(uint8_t rhport, uint8_t const *tx_buf, size_t tx_len, uint8_t *rx_buf, size_t rx_len) { + (void) rhport; + + Sercom* sercom = MAX3421_SERCOM; + + size_t count = 0; + while (count < tx_len || count < rx_len) { + // Wait for the transmit buffer to be empty + while (!sercom->SPI.INTFLAG.bit.DRE); + + // Write data to be transmitted + uint8_t data = 0x00; + if (count < tx_len) { + data = tx_buf[count]; + } + + sercom->SPI.DATA.reg = (uint32_t) data; + + // Wait for the receive buffer to be filled + while (!sercom->SPI.INTFLAG.bit.RXC); + + // Read received data + data = (uint8_t) sercom->SPI.DATA.reg; + if (count < rx_len) { + rx_buf[count] = data; + } + + count++; + } + + // wait for bus idle and clear flags + while (!(sercom->SPI.INTFLAG.reg & (SERCOM_SPI_INTFLAG_TXC | SERCOM_SPI_INTFLAG_DRE))); + sercom->SPI.INTFLAG.reg = SERCOM_SPI_INTFLAG_TXC | SERCOM_SPI_INTFLAG_DRE; + + return true; +} + +#endif + + #endif diff --git a/hw/bsp/samd21/family.cmake b/hw/bsp/samd21/family.cmake index 07186934a0..ffbf687a17 100644 --- a/hw/bsp/samd21/family.cmake +++ b/hw/bsp/samd21/family.cmake @@ -94,6 +94,7 @@ function(family_configure_example TARGET RTOS) family_add_tinyusb(${TARGET} OPT_MCU_SAMD21 ${RTOS}) target_sources(${TARGET}-tinyusb PUBLIC ${TOP}/src/portable/microchip/samd/dcd_samd.c + ${TOP}/src/portable/analog/max3421/hcd_max3421.c ) target_link_libraries(${TARGET}-tinyusb PUBLIC board_${BOARD}) diff --git a/hw/bsp/samd51/boards/metro_m4_express/board.h b/hw/bsp/samd51/boards/metro_m4_express/board.h index aa6bdd0c8c..b3b80db89b 100644 --- a/hw/bsp/samd51/boards/metro_m4_express/board.h +++ b/hw/bsp/samd51/boards/metro_m4_express/board.h @@ -44,16 +44,20 @@ #define UART_RX_PIN 22 // SPI for USB host shield -#define MAX3421_SERCOM_ID 2 // SERCOM2 -#define MAX3421_SCK_PIN 13 -#define MAX3421_MOSI_PIN 12 -#define MAX3421_MOSI_PAD 0 -#define MAX3421_MISO_PIN 14 -#define MAX3421_MISO_PAD 2 -#define MAX3421_CS_PIN 18 // D10 - -#define MAX3421_INTR_PIN 20 // D9 -#define MAX3421_INTR_EIC_ID 4 // EIC4 +#define MAX3421_SERCOM_ID 2 // SERCOM2 +#define MAX3421_SERCOM_FUNCTION 2 // function C + +#define MAX3421_SCK_PIN 13 +#define MAX3421_MOSI_PIN 12 +#define MAX3421_MISO_PIN 14 +#define MAX3421_TX_PAD 0 // MOSI = PAD_0, SCK = PAD_1 +#define MAX3421_RX_PAD 2 // MISO = PAD_2 + +#define MAX3421_CS_PIN 18 // D10 + +#define MAX3421_INTR_PIN 20 // D9 +#define MAX3421_INTR_EIC_ID 4 // EIC4 + #ifdef __cplusplus } diff --git a/hw/bsp/samd51/family.c b/hw/bsp/samd51/family.c index f9e1718d0e..2cf00c7af4 100644 --- a/hw/bsp/samd51/family.c +++ b/hw/bsp/samd51/family.c @@ -77,11 +77,10 @@ void USB_3_Handler(void) { //--------------------------------------------------------------------+ #if CFG_TUH_ENABLED && defined(CFG_TUH_MAX3421) && CFG_TUH_MAX3421 -static void max3421_init(void); - #define MAX3421_SERCOM TU_XSTRCAT(SERCOM, MAX3421_SERCOM_ID) #define MAX3421_EIC_Handler TU_XSTRCAT3(EIC_, MAX3421_INTR_EIC_ID, _Handler) +static void max3421_init(void); #endif void board_init(void) { @@ -223,7 +222,8 @@ static void max3421_init(void) { while (sercom->SPI.SYNCBUSY.bit.SWRST); // Set up SPI in master mode, MSB first, SPI mode 0 - sercom->SPI.CTRLA.reg = SERCOM_SPI_CTRLA_MODE(3) | SERCOM_SPI_CTRLA_DOPO(MAX3421_MOSI_PAD) | SERCOM_SPI_CTRLA_DIPO(MAX3421_MISO_PAD); + sercom->SPI.CTRLA.reg = SERCOM_SPI_CTRLA_DOPO(MAX3421_TX_PAD) | SERCOM_SPI_CTRLA_DIPO(MAX3421_RX_PAD) | + SERCOM_SPI_CTRLA_MODE(3); sercom->SPI.CTRLB.reg = SERCOM_SPI_CTRLB_CHSIZE(0) | SERCOM_SPI_CTRLB_RXEN; while (sercom->SPI.SYNCBUSY.bit.CTRLB == 1); @@ -234,15 +234,15 @@ static void max3421_init(void) { // Configure PA12 as MOSI (PAD0), PA13 as SCK (PAD1), PA14 as MISO (PAD2), function C (sercom) gpio_set_pin_direction(MAX3421_SCK_PIN, GPIO_DIRECTION_OUT); gpio_set_pin_pull_mode(MAX3421_SCK_PIN, GPIO_PULL_OFF); - gpio_set_pin_function(MAX3421_SCK_PIN, 2); + gpio_set_pin_function(MAX3421_SCK_PIN, MAX3421_SERCOM_FUNCTION); gpio_set_pin_direction(MAX3421_MOSI_PIN, GPIO_DIRECTION_OUT); gpio_set_pin_pull_mode(MAX3421_MOSI_PIN, GPIO_PULL_OFF); - gpio_set_pin_function(MAX3421_MOSI_PIN, 2); + gpio_set_pin_function(MAX3421_MOSI_PIN, MAX3421_SERCOM_FUNCTION); gpio_set_pin_direction(MAX3421_MISO_PIN, GPIO_DIRECTION_IN); gpio_set_pin_pull_mode(MAX3421_MISO_PIN, GPIO_PULL_OFF); - gpio_set_pin_function(MAX3421_MISO_PIN, 2); + gpio_set_pin_function(MAX3421_MISO_PIN, MAX3421_SERCOM_FUNCTION); // CS pin gpio_set_pin_direction(MAX3421_CS_PIN, GPIO_DIRECTION_OUT); @@ -269,7 +269,7 @@ static void max3421_init(void) { EIC->CTRLA.bit.ENABLE = 0; while (EIC->SYNCBUSY.bit.ENABLE); - // Configure EXTINT4 (PA20) to trigger on falling edge + // Configure EIC to trigger on falling edge volatile uint32_t * eic_config; uint8_t sense_shift; if ( MAX3421_INTR_EIC_ID < 8 ) { @@ -302,10 +302,11 @@ void MAX3421_EIC_Handler(void) { void tuh_max3421_int_api(uint8_t rhport, bool enabled) { (void) rhport; + const IRQn_Type irq = EIC_0_IRQn + MAX3421_INTR_EIC_ID; if (enabled) { - NVIC_EnableIRQ(EIC_4_IRQn); + NVIC_EnableIRQ(irq); } else { - NVIC_DisableIRQ(EIC_4_IRQn); + NVIC_DisableIRQ(irq); } } From ab9585401b9964407cbf2bc7bffdf762353817f9 Mon Sep 17 00:00:00 2001 From: hathach Date: Mon, 11 Sep 2023 11:35:51 +0700 Subject: [PATCH 32/34] wrap up build cmake & make support for max3421, to enable the Host driver, 'MAX3421_HOST=1' must be added as part of make/cmake command --- .idea/cmake.xml | 6 ++-- .idea/runConfigurations/kl25.xml | 2 +- .idea/runConfigurations/lpc1857.xml | 2 +- .idea/runConfigurations/lpc4088.xml | 2 +- .idea/runConfigurations/lpc54628.xml | 10 ++++++ .idea/runConfigurations/lpc55s69.xml | 10 ++++++ .idea/runConfigurations/mcx947.xml | 2 +- .idea/runConfigurations/nrf52840.xml | 2 +- .idea/runConfigurations/nrf5340.xml | 2 +- .idea/runConfigurations/ra4m1.xml | 2 +- .idea/runConfigurations/ra6m1.xml | 2 +- .idea/runConfigurations/ra6m5.xml | 2 +- .idea/runConfigurations/rt1010.xml | 2 +- .idea/runConfigurations/rt1060.xml | 2 +- .idea/runConfigurations/samd21g18.xml | 10 ++++++ .idea/runConfigurations/samd51j19.xml | 10 ++++++ .idea/runConfigurations/stlink.xml | 2 +- .idea/runConfigurations/stm32g474.xml | 2 +- .idea/runConfigurations/stm32h743.xml | 2 +- .idea/runConfigurations/uno_r4.xml | 2 +- examples/dual/host_hid_to_device_cdc/only.txt | 1 + examples/host/bare_api/only.txt | 1 + examples/host/cdc_msc_hid/only.txt | 1 + examples/host/cdc_msc_hid/src/tusb_config.h | 3 -- examples/host/hid_controller/only.txt | 1 + examples/host/msc_file_explorer/only.txt | 1 + .../host/msc_file_explorer/src/tusb_config.h | 3 -- examples/make.mk | 13 ++++---- examples/rules.mk | 2 +- hw/bsp/family_support.cmake | 14 ++++++++ hw/bsp/nrf/family.cmake | 1 - hw/bsp/samd21/family.cmake | 1 - hw/bsp/samd21/family.mk | 32 +++++++++---------- hw/bsp/samd51/family.cmake | 1 - 34 files changed, 101 insertions(+), 50 deletions(-) create mode 100644 .idea/runConfigurations/lpc54628.xml create mode 100644 .idea/runConfigurations/lpc55s69.xml create mode 100644 .idea/runConfigurations/samd21g18.xml create mode 100644 .idea/runConfigurations/samd51j19.xml diff --git a/.idea/cmake.xml b/.idea/cmake.xml index 8d19b76247..89ec1066ca 100644 --- a/.idea/cmake.xml +++ b/.idea/cmake.xml @@ -33,7 +33,7 @@ - + @@ -53,8 +53,8 @@ - - + + \ No newline at end of file diff --git a/.idea/runConfigurations/kl25.xml b/.idea/runConfigurations/kl25.xml index a08c20d441..66f8ea6841 100644 --- a/.idea/runConfigurations/kl25.xml +++ b/.idea/runConfigurations/kl25.xml @@ -1,5 +1,5 @@ - + diff --git a/.idea/runConfigurations/lpc1857.xml b/.idea/runConfigurations/lpc1857.xml index 7525f51f7b..f7d4ba4022 100644 --- a/.idea/runConfigurations/lpc1857.xml +++ b/.idea/runConfigurations/lpc1857.xml @@ -1,5 +1,5 @@ - + diff --git a/.idea/runConfigurations/lpc4088.xml b/.idea/runConfigurations/lpc4088.xml index 7b32b2b856..9118769032 100644 --- a/.idea/runConfigurations/lpc4088.xml +++ b/.idea/runConfigurations/lpc4088.xml @@ -1,5 +1,5 @@ - + diff --git a/.idea/runConfigurations/lpc54628.xml b/.idea/runConfigurations/lpc54628.xml new file mode 100644 index 0000000000..e0047f187e --- /dev/null +++ b/.idea/runConfigurations/lpc54628.xml @@ -0,0 +1,10 @@ + + + + + + + + + \ No newline at end of file diff --git a/.idea/runConfigurations/lpc55s69.xml b/.idea/runConfigurations/lpc55s69.xml new file mode 100644 index 0000000000..d5e9b117a8 --- /dev/null +++ b/.idea/runConfigurations/lpc55s69.xml @@ -0,0 +1,10 @@ + + + + + + + + + \ No newline at end of file diff --git a/.idea/runConfigurations/mcx947.xml b/.idea/runConfigurations/mcx947.xml index 77dec59f8a..31e5c27dda 100644 --- a/.idea/runConfigurations/mcx947.xml +++ b/.idea/runConfigurations/mcx947.xml @@ -1,5 +1,5 @@ - + diff --git a/.idea/runConfigurations/nrf52840.xml b/.idea/runConfigurations/nrf52840.xml index 2f3f1876a1..3ffa16385f 100644 --- a/.idea/runConfigurations/nrf52840.xml +++ b/.idea/runConfigurations/nrf52840.xml @@ -1,5 +1,5 @@ - + diff --git a/.idea/runConfigurations/nrf5340.xml b/.idea/runConfigurations/nrf5340.xml index 98fe39d802..2f8009444d 100644 --- a/.idea/runConfigurations/nrf5340.xml +++ b/.idea/runConfigurations/nrf5340.xml @@ -1,5 +1,5 @@ - + diff --git a/.idea/runConfigurations/ra4m1.xml b/.idea/runConfigurations/ra4m1.xml index 561b509a28..6135e5cf37 100644 --- a/.idea/runConfigurations/ra4m1.xml +++ b/.idea/runConfigurations/ra4m1.xml @@ -1,5 +1,5 @@ - + diff --git a/.idea/runConfigurations/ra6m1.xml b/.idea/runConfigurations/ra6m1.xml index 099510c60e..0833d43b35 100644 --- a/.idea/runConfigurations/ra6m1.xml +++ b/.idea/runConfigurations/ra6m1.xml @@ -1,5 +1,5 @@ - + diff --git a/.idea/runConfigurations/ra6m5.xml b/.idea/runConfigurations/ra6m5.xml index 0cffac1359..606e04e520 100644 --- a/.idea/runConfigurations/ra6m5.xml +++ b/.idea/runConfigurations/ra6m5.xml @@ -1,5 +1,5 @@ - + diff --git a/.idea/runConfigurations/rt1010.xml b/.idea/runConfigurations/rt1010.xml index 63df076b18..f4f48181c6 100644 --- a/.idea/runConfigurations/rt1010.xml +++ b/.idea/runConfigurations/rt1010.xml @@ -1,5 +1,5 @@ - + diff --git a/.idea/runConfigurations/rt1060.xml b/.idea/runConfigurations/rt1060.xml index 147f197a23..3d740edebb 100644 --- a/.idea/runConfigurations/rt1060.xml +++ b/.idea/runConfigurations/rt1060.xml @@ -1,5 +1,5 @@ - + diff --git a/.idea/runConfigurations/samd21g18.xml b/.idea/runConfigurations/samd21g18.xml new file mode 100644 index 0000000000..9a1e65563a --- /dev/null +++ b/.idea/runConfigurations/samd21g18.xml @@ -0,0 +1,10 @@ + + + + + + + + + \ No newline at end of file diff --git a/.idea/runConfigurations/samd51j19.xml b/.idea/runConfigurations/samd51j19.xml new file mode 100644 index 0000000000..74d0e36498 --- /dev/null +++ b/.idea/runConfigurations/samd51j19.xml @@ -0,0 +1,10 @@ + + + + + + + + + \ No newline at end of file diff --git a/.idea/runConfigurations/stlink.xml b/.idea/runConfigurations/stlink.xml index 7e9166d902..b29b63f1a9 100644 --- a/.idea/runConfigurations/stlink.xml +++ b/.idea/runConfigurations/stlink.xml @@ -1,5 +1,5 @@ - + diff --git a/.idea/runConfigurations/stm32g474.xml b/.idea/runConfigurations/stm32g474.xml index 2e4c4b82a3..a7267fe90e 100644 --- a/.idea/runConfigurations/stm32g474.xml +++ b/.idea/runConfigurations/stm32g474.xml @@ -1,5 +1,5 @@ - + diff --git a/.idea/runConfigurations/stm32h743.xml b/.idea/runConfigurations/stm32h743.xml index f0ab6e9e7b..9cd142de02 100644 --- a/.idea/runConfigurations/stm32h743.xml +++ b/.idea/runConfigurations/stm32h743.xml @@ -1,5 +1,5 @@ - + diff --git a/.idea/runConfigurations/uno_r4.xml b/.idea/runConfigurations/uno_r4.xml index e9e1ebb8d6..75eb3df4d0 100644 --- a/.idea/runConfigurations/uno_r4.xml +++ b/.idea/runConfigurations/uno_r4.xml @@ -1,5 +1,5 @@ - + diff --git a/examples/dual/host_hid_to_device_cdc/only.txt b/examples/dual/host_hid_to_device_cdc/only.txt index a3b567f9a0..cfc87eb4ec 100644 --- a/examples/dual/host_hid_to_device_cdc/only.txt +++ b/examples/dual/host_hid_to_device_cdc/only.txt @@ -3,3 +3,4 @@ board:mimxrt1064_evk board:mcb1800 mcu:RP2040 mcu:ra6m5 +mcu:MAX3421 diff --git a/examples/host/bare_api/only.txt b/examples/host/bare_api/only.txt index f8aa2186f0..3837ac8a20 100644 --- a/examples/host/bare_api/only.txt +++ b/examples/host/bare_api/only.txt @@ -10,3 +10,4 @@ mcu:RP2040 mcu:MSP432E4 mcu:RX65X mcu:RAXXX +mcu:MAX3421 diff --git a/examples/host/cdc_msc_hid/only.txt b/examples/host/cdc_msc_hid/only.txt index f8aa2186f0..3837ac8a20 100644 --- a/examples/host/cdc_msc_hid/only.txt +++ b/examples/host/cdc_msc_hid/only.txt @@ -10,3 +10,4 @@ mcu:RP2040 mcu:MSP432E4 mcu:RX65X mcu:RAXXX +mcu:MAX3421 diff --git a/examples/host/cdc_msc_hid/src/tusb_config.h b/examples/host/cdc_msc_hid/src/tusb_config.h index 8d3ef88919..c8e9138e33 100644 --- a/examples/host/cdc_msc_hid/src/tusb_config.h +++ b/examples/host/cdc_msc_hid/src/tusb_config.h @@ -38,9 +38,6 @@ // change to 1 if using pico-pio-usb as host controller for raspberry rp2040 #define CFG_TUH_RPI_PIO_USB 0 #define BOARD_TUH_RHPORT CFG_TUH_RPI_PIO_USB -//#elif CFG_TUSB_MCU == OPT_MCU_NRF5X -// // Use external USB controller (via SPI) MAX3421E (aka usb host shield) -// #define CFG_TUH_MAX3421 1 #endif // RHPort number used for host can be defined by board.mk, default to port 0 diff --git a/examples/host/hid_controller/only.txt b/examples/host/hid_controller/only.txt index f8aa2186f0..3837ac8a20 100644 --- a/examples/host/hid_controller/only.txt +++ b/examples/host/hid_controller/only.txt @@ -10,3 +10,4 @@ mcu:RP2040 mcu:MSP432E4 mcu:RX65X mcu:RAXXX +mcu:MAX3421 diff --git a/examples/host/msc_file_explorer/only.txt b/examples/host/msc_file_explorer/only.txt index f8aa2186f0..3837ac8a20 100644 --- a/examples/host/msc_file_explorer/only.txt +++ b/examples/host/msc_file_explorer/only.txt @@ -10,3 +10,4 @@ mcu:RP2040 mcu:MSP432E4 mcu:RX65X mcu:RAXXX +mcu:MAX3421 diff --git a/examples/host/msc_file_explorer/src/tusb_config.h b/examples/host/msc_file_explorer/src/tusb_config.h index e6186ba46f..b4ccd82233 100644 --- a/examples/host/msc_file_explorer/src/tusb_config.h +++ b/examples/host/msc_file_explorer/src/tusb_config.h @@ -38,9 +38,6 @@ // change to 1 if using pico-pio-usb as host controller for raspberry rp2040 #define CFG_TUH_RPI_PIO_USB 0 #define BOARD_TUH_RHPORT CFG_TUH_RPI_PIO_USB -//#elif CFG_TUSB_MCU == OPT_MCU_NRF5X -// // Use external USB controller (via SPI) MAX3421E (aka usb host shield) -// #define CFG_TUH_MAX3421 1 #endif diff --git a/examples/make.mk b/examples/make.mk index a590e34f74..8fe4a34869 100644 --- a/examples/make.mk +++ b/examples/make.mk @@ -73,7 +73,6 @@ ifeq ($(FAMILY),) else # Include Family and Board specific defs include $(TOP)/$(FAMILY_PATH)/family.mk - SRC_C += $(subst $(TOP)/,,$(wildcard $(TOP)/$(FAMILY_PATH)/*.c)) endif @@ -84,9 +83,6 @@ CROSS_COMPILE ?= arm-none-eabi- ifeq ($(TOOLCHAIN),iar) CC := iccarm -endif - -ifeq ($(CC),iccarm) USE_IAR = 1 endif @@ -105,13 +101,12 @@ endif #-------------- Source files and compiler flags -------------- # tinyusb makefile include $(TOP)/src/tinyusb.mk +SRC_C += $(TINYUSB_SRC_C) # Include all source C in family & board folder SRC_C += hw/bsp/board.c SRC_C += $(subst $(TOP)/,,$(wildcard $(TOP)/$(BOARD_PATH)/*.c)) -SRC_C += $(TINYUSB_SRC_C) - INC += \ $(TOP)/$(FAMILY_PATH) \ $(TOP)/src \ @@ -119,6 +114,12 @@ INC += \ BOARD_UPPER = $(subst a,A,$(subst b,B,$(subst c,C,$(subst d,D,$(subst e,E,$(subst f,F,$(subst g,G,$(subst h,H,$(subst i,I,$(subst j,J,$(subst k,K,$(subst l,L,$(subst m,M,$(subst n,N,$(subst o,O,$(subst p,P,$(subst q,Q,$(subst r,R,$(subst s,S,$(subst t,T,$(subst u,U,$(subst v,V,$(subst w,W,$(subst x,X,$(subst y,Y,$(subst z,Z,$(subst -,_,$(BOARD)))))))))))))))))))))))))))) CFLAGS += -DBOARD_$(BOARD_UPPER) +# use max3421 as host controller +ifeq (${MAX3421_HOST},1) + SRC_C += src/portable/analog/max3421/hcd_max3421.c + CFLAGS += -DCFG_TUH_MAX3421=1 +endif + # Log level is mapped to TUSB DEBUG option ifneq ($(LOG),) CMAKE_DEFSYM += -DLOG=$(LOG) diff --git a/examples/rules.mk b/examples/rules.mk index 44d6b84c81..227849a182 100644 --- a/examples/rules.mk +++ b/examples/rules.mk @@ -72,7 +72,7 @@ endif # get depenecies .PHONY: get-deps get-deps: - $(PYTHON) $(TOP)/tools/get_deps.py $(DEPS_SUBMODULES) + $(PYTHON) $(TOP)/tools/get_deps.py ${FAMILY} .PHONY: size size: $(BUILD)/$(PROJECT).elf diff --git a/hw/bsp/family_support.cmake b/hw/bsp/family_support.cmake index 1cbcfb2a74..642282b0e1 100644 --- a/hw/bsp/family_support.cmake +++ b/hw/bsp/family_support.cmake @@ -253,6 +253,15 @@ function(family_add_tinyusb TARGET OPT_MCU RTOS) # link tinyusb with freeRTOS kernel target_link_libraries(${TARGET}-tinyusb PUBLIC freertos_kernel) endif () + + # use max3421 as host controller + if (MAX3421_HOST STREQUAL "1") + target_compile_definitions(${TARGET}-tinyusb_config INTERFACE CFG_TUH_MAX3421=1) + target_sources(${TARGET}-tinyusb PUBLIC + ${TOP}/src/portable/analog/max3421/hcd_max3421.c + ) + endif () + endfunction() @@ -438,5 +447,10 @@ if (NOT FAMILY_MCUS) set(FAMILY_MCUS ${FAMILY}) endif() +# if use max3421 as host controller, expand FAMILY_MCUS to include max3421 +if (MAX3421_HOST STREQUAL "1") + set(FAMILY_MCUS ${FAMILY_MCUS} MAX3421) +endif () + # save it in case of re-inclusion set(FAMILY_MCUS ${FAMILY_MCUS} CACHE INTERNAL "") diff --git a/hw/bsp/nrf/family.cmake b/hw/bsp/nrf/family.cmake index ff6b882cea..99d9ac6ddc 100644 --- a/hw/bsp/nrf/family.cmake +++ b/hw/bsp/nrf/family.cmake @@ -124,7 +124,6 @@ function(family_configure_example TARGET RTOS) family_add_tinyusb(${TARGET} OPT_MCU_NRF5X ${RTOS}) target_sources(${TARGET}-tinyusb PUBLIC ${TOP}/src/portable/nordic/nrf5x/dcd_nrf5x.c - ${TOP}/src/portable/analog/max3421/hcd_max3421.c ) target_link_libraries(${TARGET}-tinyusb PUBLIC board_${BOARD}) diff --git a/hw/bsp/samd21/family.cmake b/hw/bsp/samd21/family.cmake index ffbf687a17..07186934a0 100644 --- a/hw/bsp/samd21/family.cmake +++ b/hw/bsp/samd21/family.cmake @@ -94,7 +94,6 @@ function(family_configure_example TARGET RTOS) family_add_tinyusb(${TARGET} OPT_MCU_SAMD21 ${RTOS}) target_sources(${TARGET}-tinyusb PUBLIC ${TOP}/src/portable/microchip/samd/dcd_samd.c - ${TOP}/src/portable/analog/max3421/hcd_max3421.c ) target_link_libraries(${TARGET}-tinyusb PUBLIC board_${BOARD}) diff --git a/hw/bsp/samd21/family.mk b/hw/bsp/samd21/family.mk index 49a1a781a2..79c63812de 100644 --- a/hw/bsp/samd21/family.mk +++ b/hw/bsp/samd21/family.mk @@ -1,5 +1,5 @@ UF2_FAMILY_ID = 0x68ed2b88 -DEPS_SUBMODULES += hw/mcu/microchip +SDK_DIR = hw/mcu/microchip/samd21 include $(TOP)/$(BOARD_PATH)/board.mk CPU_CORE ?= cortex-m0plus @@ -18,24 +18,24 @@ CFLAGS_SKIP += -Wcast-qual SRC_C += \ src/portable/microchip/samd/dcd_samd.c \ - hw/mcu/microchip/samd21/gcc/gcc/startup_samd21.c \ - hw/mcu/microchip/samd21/gcc/system_samd21.c \ - hw/mcu/microchip/samd21/hpl/gclk/hpl_gclk.c \ - hw/mcu/microchip/samd21/hpl/pm/hpl_pm.c \ - hw/mcu/microchip/samd21/hpl/sysctrl/hpl_sysctrl.c \ - hw/mcu/microchip/samd21/hal/src/hal_atomic.c + ${SDK_DIR}/gcc/gcc/startup_samd21.c \ + ${SDK_DIR}/gcc/system_samd21.c \ + ${SDK_DIR}/hpl/gclk/hpl_gclk.c \ + ${SDK_DIR}/hpl/pm/hpl_pm.c \ + ${SDK_DIR}/hpl/sysctrl/hpl_sysctrl.c \ + ${SDK_DIR}/hal/src/hal_atomic.c INC += \ $(TOP)/$(BOARD_PATH) \ - $(TOP)/hw/mcu/microchip/samd21/ \ - $(TOP)/hw/mcu/microchip/samd21/config \ - $(TOP)/hw/mcu/microchip/samd21/include \ - $(TOP)/hw/mcu/microchip/samd21/hal/include \ - $(TOP)/hw/mcu/microchip/samd21/hal/utils/include \ - $(TOP)/hw/mcu/microchip/samd21/hpl/pm/ \ - $(TOP)/hw/mcu/microchip/samd21/hpl/port \ - $(TOP)/hw/mcu/microchip/samd21/hri \ - $(TOP)/hw/mcu/microchip/samd21/CMSIS/Include + $(TOP)/${SDK_DIR}/ \ + $(TOP)/${SDK_DIR}/config \ + $(TOP)/${SDK_DIR}/include \ + $(TOP)/${SDK_DIR}/hal/include \ + $(TOP)/${SDK_DIR}/hal/utils/include \ + $(TOP)/${SDK_DIR}/hpl/pm/ \ + $(TOP)/${SDK_DIR}/hpl/port \ + $(TOP)/${SDK_DIR}/hri \ + $(TOP)/${SDK_DIR}/CMSIS/Include # flash using bossac at least version 1.8 # can be found in arduino15/packages/arduino/tools/bossac/ diff --git a/hw/bsp/samd51/family.cmake b/hw/bsp/samd51/family.cmake index 1dce483fdb..fa9586066a 100644 --- a/hw/bsp/samd51/family.cmake +++ b/hw/bsp/samd51/family.cmake @@ -93,7 +93,6 @@ function(family_configure_example TARGET RTOS) family_add_tinyusb(${TARGET} OPT_MCU_SAMD51 ${RTOS}) target_sources(${TARGET}-tinyusb PUBLIC ${TOP}/src/portable/microchip/samd/dcd_samd.c - ${TOP}/src/portable/analog/max3421/hcd_max3421.c ) target_link_libraries(${TARGET}-tinyusb PUBLIC board_${BOARD}) From 1eb0cb0c65077607944665013d4c60f8c8512ec5 Mon Sep 17 00:00:00 2001 From: hathach Date: Mon, 11 Sep 2023 15:45:26 +0700 Subject: [PATCH 33/34] update readme to include max3421 support --- .github/workflows/build_arm.yml | 1 - .github/workflows/cmake_arm.yml | 1 + README.rst | 8 ++++++-- hw/bsp/nrf/boards/feather_nrf52840_express/board.cmake | 3 +++ hw/bsp/nrf/boards/feather_nrf52840_express/board.mk | 3 +++ 5 files changed, 13 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build_arm.yml b/.github/workflows/build_arm.yml index 70385bc1b2..975f351a00 100644 --- a/.github/workflows/build_arm.yml +++ b/.github/workflows/build_arm.yml @@ -38,7 +38,6 @@ jobs: - 'lpc11 lpc13 lpc15 lpc17' - 'lpc51 lpc54' - 'mm32 msp432e4' - - 'nrf' - 'samd11 same5x saml2x' - 'stm32f2 stm32f3' - 'stm32l0 stm32u5 stm32wb' diff --git a/.github/workflows/cmake_arm.yml b/.github/workflows/cmake_arm.yml index e3a00f9c52..4b788a213a 100644 --- a/.github/workflows/cmake_arm.yml +++ b/.github/workflows/cmake_arm.yml @@ -38,6 +38,7 @@ jobs: - 'lpc18 lpc40 lpc43' - 'lpc55' - 'mcx' + - 'nrf' - 'ra' - 'rp2040' - 'samd21' diff --git a/README.rst b/README.rst index d72cdb1495..aef310b984 100644 --- a/README.rst +++ b/README.rst @@ -33,6 +33,7 @@ Supported MCUs The stack supports the following MCUs: - **Allwinner:** F1C100s/F1C200s +- **Analog:** MAX3421e (aka Arduino usb host shield) - **Broadcom:** BCM2837, BCM2711 - **Dialog:** DA1469x - **Espressif:** ESP32-S2, ESP32-S3 @@ -46,12 +47,13 @@ The stack supports the following MCUs: - iMX RT Series: RT10xx, RT11xx - Kinetis: KL25, K32L2 - LPC Series: 11u, 13, 15, 17, 18, 40, 43, 51u, 54, 55 + - MCX: N9x - **Raspberry Pi:** RP2040 - **Renesas:** - - RX Series: 63N, 65N, 72N - - RA Series: RA4M1, RA4M3 + - RX Series: 63n, 65n, 72n + - RA Series: 4m1, 4m3, 6m1, 6m5 - **Silabs:** EFM32GG - **Sony:** CXD56 @@ -87,6 +89,8 @@ Host Stack - Human Interface Device (HID): Keyboard, Mouse, Generic - Mass Storage Class (MSC) +- Communication Device Class: CDC-ACM +- Vendor serial over USB: FTDI, CP210x - Hub with multiple-level support Similar to the Device Stack, if you have a special requirement, `usbh_app_driver_get_cb()` can be used to write your own class driver without modifying the stack. diff --git a/hw/bsp/nrf/boards/feather_nrf52840_express/board.cmake b/hw/bsp/nrf/boards/feather_nrf52840_express/board.cmake index 78ed982252..ce6da8b43f 100644 --- a/hw/bsp/nrf/boards/feather_nrf52840_express/board.cmake +++ b/hw/bsp/nrf/boards/feather_nrf52840_express/board.cmake @@ -2,5 +2,8 @@ set(MCU_VARIANT nrf52840) #set(LD_FILE_GNU ${CMAKE_CURRENT_LIST_DIR}/../../linker/nrf52840_s140_v6.ld) set(LD_FILE_GNU ${NRFX_DIR}/mdk/nrf52840_xxaa.ld) +# enable max3421 host driver for this board +set(MAX3421_HOST 1) + function(update_board TARGET) endfunction() diff --git a/hw/bsp/nrf/boards/feather_nrf52840_express/board.mk b/hw/bsp/nrf/boards/feather_nrf52840_express/board.mk index b808079634..1f3772caf7 100644 --- a/hw/bsp/nrf/boards/feather_nrf52840_express/board.mk +++ b/hw/bsp/nrf/boards/feather_nrf52840_express/board.mk @@ -1,6 +1,9 @@ MCU_VARIANT = nrf52840 CFLAGS += -DNRF52840_XXAA +# enable max3421 host driver for this board +#MAX3421_HOST = 1 + # All source paths should be relative to the top level. LD_FILE = hw/bsp/nrf/linker/nrf52840_s140_v6.ld From f55052b61f548f0f28ec8c1b9b706f34424c58d1 Mon Sep 17 00:00:00 2001 From: hathach Date: Mon, 11 Sep 2023 16:44:06 +0700 Subject: [PATCH 34/34] enable max3421 host for feather nrf52840 with makefile --- .../boards/feather_nrf52840_express/board.mk | 2 +- hw/bsp/nrf/family.mk | 26 +++++++++++-------- 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/hw/bsp/nrf/boards/feather_nrf52840_express/board.mk b/hw/bsp/nrf/boards/feather_nrf52840_express/board.mk index 1f3772caf7..488f07b82d 100644 --- a/hw/bsp/nrf/boards/feather_nrf52840_express/board.mk +++ b/hw/bsp/nrf/boards/feather_nrf52840_express/board.mk @@ -2,7 +2,7 @@ MCU_VARIANT = nrf52840 CFLAGS += -DNRF52840_XXAA # enable max3421 host driver for this board -#MAX3421_HOST = 1 +MAX3421_HOST = 1 # All source paths should be relative to the top level. LD_FILE = hw/bsp/nrf/linker/nrf52840_s140_v6.ld diff --git a/hw/bsp/nrf/family.mk b/hw/bsp/nrf/family.mk index cdcfe39bd2..4b53b9a4f4 100644 --- a/hw/bsp/nrf/family.mk +++ b/hw/bsp/nrf/family.mk @@ -1,5 +1,6 @@ UF2_FAMILY_ID = 0xADA52840 -DEPS_SUBMODULES += lib/CMSIS_5 hw/mcu/nordic/nrfx + +NRFX_DIR = hw/mcu/nordic/nrfx include $(TOP)/$(BOARD_PATH)/board.mk @@ -14,24 +15,27 @@ CFLAGS += \ # suppress warning caused by vendor mcu driver CFLAGS += -Wno-error=undef -Wno-error=unused-parameter -Wno-error=cast-align -Wno-error=cast-qual -Wno-error=redundant-decls -LDFLAGS += -L$(TOP)/hw/mcu/nordic/nrfx/mdk +LDFLAGS += -L$(TOP)/${NRFX_DIR}/mdk SRC_C += \ src/portable/nordic/nrf5x/dcd_nrf5x.c \ - hw/mcu/nordic/nrfx/drivers/src/nrfx_power.c \ - hw/mcu/nordic/nrfx/drivers/src/nrfx_uarte.c \ - hw/mcu/nordic/nrfx/mdk/system_$(MCU_VARIANT).c + ${NRFX_DIR}/helpers/nrfx_flag32_allocator.c \ + ${NRFX_DIR}/drivers/src/nrfx_gpiote.c \ + ${NRFX_DIR}/drivers/src/nrfx_power.c \ + ${NRFX_DIR}/drivers/src/nrfx_spim.c \ + ${NRFX_DIR}/drivers/src/nrfx_uarte.c \ + ${NRFX_DIR}/mdk/system_$(MCU_VARIANT).c INC += \ $(TOP)/$(BOARD_PATH) \ $(TOP)/lib/CMSIS_5/CMSIS/Core/Include \ - $(TOP)/hw/mcu/nordic/nrfx \ - $(TOP)/hw/mcu/nordic/nrfx/mdk \ - $(TOP)/hw/mcu/nordic/nrfx/hal \ - $(TOP)/hw/mcu/nordic/nrfx/drivers/include \ - $(TOP)/hw/mcu/nordic/nrfx/drivers/src \ + $(TOP)/${NRFX_DIR} \ + $(TOP)/${NRFX_DIR}/mdk \ + $(TOP)/${NRFX_DIR}/hal \ + $(TOP)/${NRFX_DIR}/drivers/include \ + $(TOP)/${NRFX_DIR}/drivers/src \ -SRC_S += hw/mcu/nordic/nrfx/mdk/gcc_startup_$(MCU_VARIANT).S +SRC_S += ${NRFX_DIR}/mdk/gcc_startup_$(MCU_VARIANT).S ASFLAGS += -D__HEAP_SIZE=0