From 7fc99a9e1104703566945ace1b2e1ed59819ba48 Mon Sep 17 00:00:00 2001 From: HiFiPhile Date: Wed, 10 Mar 2021 10:19:45 +0100 Subject: Call One time tu_fifo_write_n on cdcd_xfer_cb Signed-off-by: HiFiPhile --- src/class/cdc/cdc_device.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/src/class/cdc/cdc_device.c b/src/class/cdc/cdc_device.c index 5a74b4876..64cb4ab2c 100644 --- a/src/class/cdc/cdc_device.c +++ b/src/class/cdc/cdc_device.c @@ -432,25 +432,25 @@ bool cdcd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_ // Received new data if ( ep_addr == p_cdc->ep_out ) { + tu_fifo_write_n(&p_cdc->rx_ff, &p_cdc->epout_buf, xferred_bytes); + // TODO search for wanted char first for better performance - for(uint32_t i=0; irx_ff, &p_cdc->epout_buf[i]); - + if (tud_cdc_rx_wanted_cb && ( ((signed char) p_cdc->wanted_char) != -1)) { // Check for wanted char and invoke callback if needed - if ( tud_cdc_rx_wanted_cb && ( ((signed char) p_cdc->wanted_char) != -1 ) && ( p_cdc->wanted_char == p_cdc->epout_buf[i] ) ) - { - tud_cdc_rx_wanted_cb(itf, p_cdc->wanted_char); + for (uint32_t i=0; iwanted_char == p_cdc->epout_buf[i] ) { + tud_cdc_rx_wanted_cb(itf, p_cdc->wanted_char); + } } } - + // invoke receive callback (if there is still data) if (tud_cdc_rx_cb && tu_fifo_count(&p_cdc->rx_ff) ) tud_cdc_rx_cb(itf); - + // prepare for OUT transaction _prep_out_transaction(p_cdc); } - + // Data sent to host, we continue to fetch from tx fifo to send. // Note: This will cause incorrect baudrate set in line coding. // Though maybe the baudrate is not really important !!! -- cgit v1.3.1 From 5caad485f199ab6acfa237d84bf3d84cf41dcfdd Mon Sep 17 00:00:00 2001 From: HiFiPhile Date: Thu, 11 Mar 2021 20:36:46 +0100 Subject: Add fifo empty check. Signed-off-by: HiFiPhile --- src/class/cdc/cdc_device.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/class/cdc/cdc_device.c b/src/class/cdc/cdc_device.c index 64cb4ab2c..d9b098bb2 100644 --- a/src/class/cdc/cdc_device.c +++ b/src/class/cdc/cdc_device.c @@ -434,11 +434,10 @@ bool cdcd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_ { tu_fifo_write_n(&p_cdc->rx_ff, &p_cdc->epout_buf, xferred_bytes); - // TODO search for wanted char first for better performance + // Check for wanted char and invoke callback if needed if (tud_cdc_rx_wanted_cb && ( ((signed char) p_cdc->wanted_char) != -1)) { - // Check for wanted char and invoke callback if needed for (uint32_t i=0; iwanted_char == p_cdc->epout_buf[i] ) { + if ( p_cdc->wanted_char == p_cdc->epout_buf[i] && tu_fifo_count(&p_cdc->rx_ff) ) { tud_cdc_rx_wanted_cb(itf, p_cdc->wanted_char); } } -- cgit v1.3.1 From 31373fd55cefced35cfaaa61fb8f9aa3e5ec0bc6 Mon Sep 17 00:00:00 2001 From: hathach Date: Fri, 12 Mar 2021 12:55:18 +0700 Subject: use !tu_fifo_empty() instead of tu_fifo_count() --- src/class/cdc/cdc_device.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/class/cdc/cdc_device.c b/src/class/cdc/cdc_device.c index d9b098bb2..c24edb757 100644 --- a/src/class/cdc/cdc_device.c +++ b/src/class/cdc/cdc_device.c @@ -95,7 +95,8 @@ static void _prep_out_transaction (cdcd_interface_t* p_cdc) // fifo can be changed before endpoint is claimed available = tu_fifo_remaining(&p_cdc->rx_ff); - if ( available >= sizeof(p_cdc->epout_buf) ) { + if ( available >= sizeof(p_cdc->epout_buf) ) + { usbd_edpt_xfer(rhport, p_cdc->ep_out, p_cdc->epout_buf, sizeof(p_cdc->epout_buf)); }else { @@ -435,16 +436,19 @@ bool cdcd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_ tu_fifo_write_n(&p_cdc->rx_ff, &p_cdc->epout_buf, xferred_bytes); // Check for wanted char and invoke callback if needed - if (tud_cdc_rx_wanted_cb && ( ((signed char) p_cdc->wanted_char) != -1)) { - for (uint32_t i=0; iwanted_char == p_cdc->epout_buf[i] && tu_fifo_count(&p_cdc->rx_ff) ) { + if ( tud_cdc_rx_wanted_cb && (((signed char) p_cdc->wanted_char) != -1) ) + { + for ( uint32_t i = 0; i < xferred_bytes; i++ ) + { + if ( (p_cdc->wanted_char == p_cdc->epout_buf[i]) && !tu_fifo_empty(&p_cdc->rx_ff) ) + { tud_cdc_rx_wanted_cb(itf, p_cdc->wanted_char); } } } // invoke receive callback (if there is still data) - if (tud_cdc_rx_cb && tu_fifo_count(&p_cdc->rx_ff) ) tud_cdc_rx_cb(itf); + if (tud_cdc_rx_cb && !tu_fifo_empty(&p_cdc->rx_ff) ) tud_cdc_rx_cb(itf); // prepare for OUT transaction _prep_out_transaction(p_cdc); -- cgit v1.3.1 From 3a27a9405f3354468c9ff8ae2ddd5d350e1ce19a Mon Sep 17 00:00:00 2001 From: Ha Thach Date: Fri, 12 Mar 2021 15:10:47 +0700 Subject: Release 0.9.0 (#716) * update change log for release * move changelog into docs/ * more changelog * increase macro version --- changelog.md | 297 ----------------------------------------- docs/changelog.md | 392 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/tusb_option.h | 2 +- 3 files changed, 393 insertions(+), 298 deletions(-) delete mode 100644 changelog.md create mode 100644 docs/changelog.md (limited to 'src') diff --git a/changelog.md b/changelog.md deleted file mode 100644 index d645b4fbf..000000000 --- a/changelog.md +++ /dev/null @@ -1,297 +0,0 @@ -# TinyUSB Changelog - -## WIP - -- Fix dropping MIDI sysex message when fifo is full -- Add DPad/Hat support for HID Gamepad -- Add tud_hid_report_complete_cb() API - -## 0.8.0 - 2021.02.05 - -### Device Controller Driver - -- Added new device support for Raspberry Pi RP2040 -- Added new device support for NXP Kinetis KL25ZXX -- Use dcd_event_bus_reset() with link speed to replace bus_signal -- ESP32-S2: - - Add bus suspend and wakeup support -- SAMD21: - - Fix (walkaround) samd21 setup_packet overflow by USB DMA -- STM32 Synopsys: - - Rework USB FIFO allocation scheme and allow RX FIFO size reduction -- Sony CXD56 - - Update Update Spresense SDK to 2.0.2 - - Fix dcd issues with setup packets - - Correct EP number for cdc_msc example - -### USB Device - -**UBSD** - -- Rework usbd control transfer to have additional stage parameter for setup, data, status -- Fix tusb_init() return true instead of TUSB_ERROR_NONE -- Added new API tud_connected() that return true after device got out of bus reset and received the very first setup packet - -**Class Driver** - -- CDC - - Allow to transmit data, even if the host does not support control line states i.e set DTR -- HID - - change default CFG_TUD_HID_EP_BUFSIZE from 16 to 64 -- MIDI - - Fix midi sysex sending bug -- MSC - - Invoke only scsi complete callback after status transaction is complete. - - Fix scsi_mode_sense6_t padding, which cause IAR compiler internal error. -- USBTMC - - Change interrupt endpoint example size to 8 instead of 2 for better compatibility with mcu - -**Example** - -- Support make from windows cmd.exe -- Add HID Consumer Control (media keys) to hid_composite & hid_composite_freertos examples - -### USB Host - -No noticeable changes to host stack - -### New Boards - -- NXP/Freescale Freedom FRDM-KL25Z -- Feather Double M33 express -- Raspberry Pi Pico -- Adafruit Feather RP2040 -- Adafruit Itsy Bitsy RP2040 -- Adafruit QT RP2040 -- Adfruit Feather ESP32-S2 -- Adafruit Magtag 29" Eink -- Adafruit Metro ESP32-S2 -- Adafruit PyBadge -- Adafruit PyPortal -- Great Scott Gadgets' LUNA D11 & D21 - -## 0.7.0 - 2020.11.08 - -### Device Controller Driver - -- Added new support for Espressif ESP32-S2 -- Added new support for Dialog DA1469x -- Enhance STM32 Synopsys - - Support bus events disconnection/suspend/resume/wakeup - - Improve transfer performance with optimizing xfer and fifo size - - Support Highspeed port (OTG_HS) with both internal and external PHY - - Support multiple usb ports with rhport=1 is highspeed on selected MCUs e.g H743, F23. It is possible to have OTG_HS to run on Fullspeed PHY (e.g lacking external PHY) - - Add ISO transfer, fix odd/even frame - - Fix FIFO flush during stall - - Implement dcd_edpt_close() API - - Support F105, F107 -- Enhance STM32 fsdev - - Improve dcd fifo allocation - - Fix ISTR race condition - - Support remap USB IRQ on supported MCUs - - Implement dcd_edpt_close() API -- Enhance NUC 505: enhance set configure behavior -- Enhance SAMD - - Fix race condition with setup packet - - Add SAMD11 option `OPT_MCU_SAMD11` - - Add SAME5x option `OPT_MCU_SAME5X` -- Fix SAMG control data toggle and stall race condition -- Enhance nRF - - Fix hanged when tud_task() is called within critical section (disabled interrupt) - - Fix disconnect bus event not submitted - - Implement ISO transfer and dcd_edpt_close() - -### USB Device - -**USBD** - -- Add new class driver for **Bluetooth HCI** class driver with example can be found in [mynewt-tinyusb-example](https://github.com/hathach/mynewt-tinyusb-example) since it needs mynewt OS to run with. -- Fix USBD endpoint usage racing condition with `usbd_edpt_claim()/usbd_edpt_release()` -- Added `tud_task_event_ready()` and `osal_queue_empty()`. This API is needed to check before enter low power mode with WFI/WFE -- Rename USB IRQ Handler to `dcd_int_handler()`. Application must define IRQ handler in which it calls this API. -- Add `dcd_connect()` and `dcd_disconnect()` to enable/disable internal pullup on D+/D- on supported MCUs. -- Add `usbd_edpt_open()` -- Remove `dcd_set_config()` -- Add *OPT_OS_CUMSTOM* as hook for application to overwrite and/or add their own OS implementation -- Support SET_INTERFACE, GET_INTERFACE request -- Add Logging for debug with optional uart/rtt/swo printf retarget or `CFG_TUSB_DEBUG_PRINTF` hook -- Add IAR compiler support -- Support multiple configuration descriptors. `TUD_CONFIG_DESCRIPTOR()` template has extra config_num as 1st argument -- Improve USB Highspeed support with actual link speed detection with `dcd_event_bus_reset()` -- Enhance class driver management - - `usbd_driver_open()` add max length argument, and return length of interface (0 for not supported). Return value is used for finding appropriate driver - - Add application implemented class driver via `usbd_app_driver_get_cb()` - - IAD is handled to assign driver id -- Added `tud_descriptor_device_qualifier_cb()` callback -- Optimize `tu_fifo` bulk write/read transfer -- Forward non-std control request to class driver -- Let application handle Microsoft OS 1.0 Descriptors (the 0xEE index string) -- Fix OSAL FreeRTOS yield from ISR - -**Class Drivers** - -- USBNET: remove ACM-EEM due to lack of support from host -- USBTMC: fix descriptors when INT EP is disabled -- CDC: - - Send zero length packet for end of data when needed - - Add `tud_cdc_tx_complete_cb()` callback - - Change tud_cdc_n_write_flush() return number of bytes forced to transfer, and flush when writing enough data to fifo -- MIDI: - - Add packet interface - - Add multiple jack descriptors - - Fix MIDI driver for sysex -- DFU Runtime: fix response to SET_INTERFACE and DFU_GETSTATUS request -- Rename some configure macro to make it clear that those are used directly for endpoint transfer - - CFG_TUD_HID_BUFSIZE to `CFG_TUD_HID_EP_BUFSIZE - - CFG_TUD_CDC_EPSIZE to CFG_TUD_CDC_EP_BUFSIZE - - CFG_TUD_MSC_BUFSIZE to CFG_TUD_MSC_EP_BUFSIZE - - CFG_TUD_MIDI_EPSIZE to CFG_TUD_MIDI_EP_BUFSIZE -- HID: - - Fix gamepad template descriptor - - Add multiple HID interface API - - Add extra comma to HID_REPORT_ID - -### USB Host - -- Rework USB host stack (still work in progress) - - Fix compile error with pipehandle - - Rework usbh control and enumeration as non-blocking -- Improve Hub, MSC, HID host driver - -### Examples - -- Add new hid_composite_freertos -- Add new dynamic_configuration to demonstrate how to switch configuration descriptors -- Add new hid_multiple_interface -- Enhance `net_lwip_webserver` example - - Add multiple configuration: RNDIS for Windows, CDC-ECM for macOS (Linux will work with both) - - Update lwip to STABLE-2_1_2_RELEASE for net_lwip_webserver -- Added new Audio example: audio_test uac2_headsest - -### New Boards - -- Espressif ESP32-S2: saola_1, kaluga_1 -- STM32: F746 Nucleo, H743 Eval, H743 Nucleo, F723 discovery, stlink v3 mini, STM32L4r5 Nucleo -- Dialog DA1469x dk pro and dk usb -- Microchip: Great Scoot Gadgets' LUNA, samd11_xplained, D5035-01, atsamd21 xplained pro -- nRF: ItsyBitsy nRF52840 - -## 0.6.0 - 2020.03.30 - -Added **CONTRIBUTORS.md** to give proper credit for contributors to the stack. Special thanks to [Nathan Conrad](https://github.com/pigrew), [Peter Lawrence](https://github.com/majbthrd) and [William D. Jones](https://github.com/cr1901) and others for spending their precious time to add lots of features and ports for this release. - -### Added - -**MCUs** - -- Added support for Microchip SAMG55 -- Added support for Nordic nRF52833 -- Added support for Nuvoton: NUC120, NUC121/NUC125, NUC126, NUC505 -- Added support for NXP LPC: 51Uxx, 54xxx, 55xx -- Added support for NXP iMXRT: RT1011, RT1015, RT1021, RT1052, RT1062, RT1064 -- Added support for Sony CXD56 (Spresense) -- Added support for STM32: L0, F0, F1, F2, F3, F4, F7, H7 -- Added support for TI MSP430 -- Added support for ValentyUSB's eptri - -**Class Driver** - -- Added DFU Runtime class driver -- Added Network class driver with RNDIS, CDC-ECM, CDC-EEM (work in progress) -- Added USBTMC class driver -- Added WebUSB class driver using vendor-specific class -- Added multiple instances support for CDC and MIDI -- Added a handful of unit test with Ceedling. -- Added LOG support for debugging with CFG_TUSB_DEBUG -- Added `tud_descriptor_bos_cb()` for BOS descriptor (required for USB 2.1) -- Added `dcd_edpt0_status_complete()` as optional API for DCD - -**Examples** - -Following examples are added: - -- board_test -- cdc_dual_ports -- dfu_rt -- hid_composite -- net_lwip_webserver -- usbtmc -- webusb_serial - -**Boards** - -Following boards are added: - -- adafruit_clue -- arduino_nano33_ble -- circuitplayground_bluefruit -- circuitplayground_express -- feather_m0_express -- feather_nrf52840_sense -- feather_stm32f405 -- fomu -- itsybitsy_m0 -- itsybitsy_m4 -- lpcxpresso11u37 -- lpcxpresso1549 -- lpcxpresso51u68 -- lpcxpresso54114 -- lpcxpresso55s69 -- mbed1768 -- mimxrt1010_evk -- mimxrt1015_evk -- mimxrt1020_evk -- mimxrt1050_evkb -- mimxrt1060_evk -- mimxrt1064_evk -- msp_exp430f5529lp -- ngx4330 -- nrf52840_mdk_dongle -- nutiny_nuc121s -- nutiny_nuc125s -- nutiny_nuc126v -- nutiny_sdk_nuc120 -- nutiny_sdk_nuc505 -- pca10059 -- pca10100 -- pyboardv11 -- raytac_mdbt50q_rx -- samg55xplained -- seeeduino_xiao -- spresense -- stm32f070rbnucleo -- stm32f072disco -- stm32f103bluepill -- stm32f207nucleo -- stm32f401blackpill -- stm32f411blackpill -- stm32f411disco -- stm32f412disco -- stm32f767nucleo -- stm32h743nucleo -- stm32l0538disco -- stm32l476disco -- teensy_40 - -### Changed - -- Changed `tud_descriptor_string_cb()` to have additional Language ID argument -- Merged hal_nrf5x.c into dcd_nrf5x.c -- Merged dcd_samd21.c and dcd_samd51.c into dcd_samd.c -- Generalized dcd_stm32f4.c to dcd_synopsys.c -- Changed cdc_msc_hid to cdc_msc (drop hid) due to limited endpoints number of some MCUs -- Improved DCD SAMD stability, fix missing setup packet occasionally -- Improved usbd/usbd_control with proper hanlding of zero-length packet (ZLP) -- Improved STM32 DCD FSDev -- Improved STM32 DCD Synopsys -- Migrated CI from Travis to Github Action -- Updated nrfx submodule to 2.1.0 -- Fixed mynewt osal queue definition -- Fixed cdc_msc_freertos example build for all MCUs - -## 0.5.0 (Initial Release) - 2019.07.10 - -First release, device stack works great, host stack works but still need improvement. -- Special thanks to @adafruit team, especially @tannewt to help out immensely to rework device stack: simplify osal & control transfer, adding SAMD21/SAMD51 ports, writing porting docs, adding MIDI class support etc... -- Thanks to @cr1901 for adding STM32F4 port. -- Thanks to @PTS93 and @todbot for HID raw API diff --git a/docs/changelog.md b/docs/changelog.md new file mode 100644 index 000000000..0e5f12e83 --- /dev/null +++ b/docs/changelog.md @@ -0,0 +1,392 @@ +# TinyUSB Changelog + +## 0.9.0 - 2021.03.12 + +### Device Stack + +#### Device Controller Driver (DCD) + +RP2040 + +- Fix endpoint buffer reallocation overrun problem +- Fix osal_pico queue overflow in initialization +- Fix Isochronous endpoint buffer size in transfer +- Optimize hardware endpoint struct to reduce RAM usage +- Fix enum walkaround forever check for SE0 when pull up is disabled + +Sony CXD56 + +- Pass the correct speed on Spresense +- Fix setup processed flag + +NXP Transdimention + +- Update dcd_init() to reset controller to device mode + +#### USB Device Driver (USBD) + +- Fix issue with status zlp (tud_control_status) is returned by class driver with SET/CLEAR_FEATURE for endpoint. +- Correct endpoint size check for fullspeed bulk, can be 8, 16, 32, 64 +- Ack SET_INTERFACE even if it is not implemented by class driver. + +#### Device Class Driver + +DFU Runtime + +- rename dfu_rt to dfu_runtime for easy reading + +CDC + +- Add tud_cdc_send_break_cb() to support break request +- Improve CDC receive, minor behavior changes: when tud_cdc_rx_wanted_cb() is invoked wanted_char may not be the last byte in the fifo + +HID + +- [Breaking] Add itf argument to hid API to support multiple instances, follow API has signature changes + - tud_hid_descriptor_report_cb() + - tud_hid_get_report_cb() + - tud_hid_set_report_cb() + - tud_hid_boot_mode_cb() + - tud_hid_set_idle_cb() +- Add report complete callback tud_hid_report_complete_cb() API +- Add DPad/Hat support for HID Gamepad + - TUD_HID_REPORT_DESC_GAMEPAD() now support 16 buttons, 2 joysticks, 1 hat/dpad + - Add hid_gamepad_report_t along with GAMEPAD_BUTTON_ and GAMEPAD_HAT_ enum + - Add Gamepad to hid_composite / hid_composite_freertos example + +MIDI + +- Fix dropping MIDI sysex message when fifo is full +- Fix typo in tud_midi_write24(), make example less ambigous for cable and channel +- Fix incorrect endpoint descriptor length, MIDI v1 use Audio v1 which has 9-byte endpoint descriptor (instead of 7) + +### Host Stack + +#### Host Controller Driver (HCD) + +- Add rhport to hcd_init() +- Improve EHCI/OHCI driver abstraction + - Move echi/ohci files to portable/ + - Rename hcd_lpc18_43 to hcd_transdimension + - Sub hcd API with hcd_ehci_init(), hcd_ehci_register_addr() +- Update NXP transdimention hcd_init() to reset controller to host mode + - Ported hcd to rt10xx + +#### USB Host Driver (USBH) + +- No noticeable changes to usbh + +#### Host Class Driver + +MSC + +- Rename tuh_msc_scsi_inquiry() to tuh_msc_inquiry() +- Rename tuh_msc_mounted_cb/tuh_msc_unmounted_cb to tuh_msc_mount_cb/tuh_msc_unmount_cb to match device stack naming +- Change tuh_msc_is_busy() to tuh_msc_ready() +- Add read10 and write10 function: tuh_msc_read10(), tuh_msc_write10() +- Read_Capacity is invoked as part of enumeration process +- Add tuh_msc_get_block_count(), tuh_msc_get_block_size() +- Add CFG_TUH_MSC_MAXLUN (default to 4) to hold lun capacities + +### Others + +- Add basic support for rt-thread OS +- Change zero bitfield length to more explicit padding +- Build example now fetch required submodules on the fly while running `make` without prio submodule init for mcu drivers +- Update pico-sdk to v1.1.0 + +**New Boards** + +- Microchip SAM E54 Xplained Pro +- LPCXpresso 55s28 +- LPCXpresso 18s37 + +## 0.8.0 - 2021.02.05 + +### Device Controller Driver + +- Added new device support for Raspberry Pi RP2040 +- Added new device support for NXP Kinetis KL25ZXX +- Use dcd_event_bus_reset() with link speed to replace bus_signal +- ESP32-S2: + - Add bus suspend and wakeup support +- SAMD21: + - Fix (walkaround) samd21 setup_packet overflow by USB DMA +- STM32 Synopsys: + - Rework USB FIFO allocation scheme and allow RX FIFO size reduction +- Sony CXD56 + - Update Update Spresense SDK to 2.0.2 + - Fix dcd issues with setup packets + - Correct EP number for cdc_msc example + +### USB Device + +**USBD** + +- Rework usbd control transfer to have additional stage parameter for setup, data, status +- Fix tusb_init() return true instead of TUSB_ERROR_NONE +- Added new API tud_connected() that return true after device got out of bus reset and received the very first setup packet + +**Class Driver** + +- CDC + - Allow to transmit data, even if the host does not support control line states i.e set DTR +- HID + - change default CFG_TUD_HID_EP_BUFSIZE from 16 to 64 +- MIDI + - Fix midi sysex sending bug +- MSC + - Invoke only scsi complete callback after status transaction is complete. + - Fix scsi_mode_sense6_t padding, which cause IAR compiler internal error. +- USBTMC + - Change interrupt endpoint example size to 8 instead of 2 for better compatibility with mcu + +**Example** + +- Support make from windows cmd.exe +- Add HID Consumer Control (media keys) to hid_composite & hid_composite_freertos examples + +### USB Host + +No noticeable changes to host stack + +### New Boards + +- NXP/Freescale Freedom FRDM-KL25Z +- Feather Double M33 express +- Raspberry Pi Pico +- Adafruit Feather RP2040 +- Adafruit Itsy Bitsy RP2040 +- Adafruit QT RP2040 +- Adfruit Feather ESP32-S2 +- Adafruit Magtag 29" Eink +- Adafruit Metro ESP32-S2 +- Adafruit PyBadge +- Adafruit PyPortal +- Great Scott Gadgets' LUNA D11 & D21 + +## 0.7.0 - 2020.11.08 + +### Device Controller Driver + +- Added new support for Espressif ESP32-S2 +- Added new support for Dialog DA1469x +- Enhance STM32 Synopsys + - Support bus events disconnection/suspend/resume/wakeup + - Improve transfer performance with optimizing xfer and fifo size + - Support Highspeed port (OTG_HS) with both internal and external PHY + - Support multiple usb ports with rhport=1 is highspeed on selected MCUs e.g H743, F23. It is possible to have OTG_HS to run on Fullspeed PHY (e.g lacking external PHY) + - Add ISO transfer, fix odd/even frame + - Fix FIFO flush during stall + - Implement dcd_edpt_close() API + - Support F105, F107 +- Enhance STM32 fsdev + - Improve dcd fifo allocation + - Fix ISTR race condition + - Support remap USB IRQ on supported MCUs + - Implement dcd_edpt_close() API +- Enhance NUC 505: enhance set configure behavior +- Enhance SAMD + - Fix race condition with setup packet + - Add SAMD11 option `OPT_MCU_SAMD11` + - Add SAME5x option `OPT_MCU_SAME5X` +- Fix SAMG control data toggle and stall race condition +- Enhance nRF + - Fix hanged when tud_task() is called within critical section (disabled interrupt) + - Fix disconnect bus event not submitted + - Implement ISO transfer and dcd_edpt_close() + +### USB Device + +**USBD** + +- Add new class driver for **Bluetooth HCI** class driver with example can be found in [mynewt-tinyusb-example](https://github.com/hathach/mynewt-tinyusb-example) since it needs mynewt OS to run with. +- Fix USBD endpoint usage racing condition with `usbd_edpt_claim()/usbd_edpt_release()` +- Added `tud_task_event_ready()` and `osal_queue_empty()`. This API is needed to check before enter low power mode with WFI/WFE +- Rename USB IRQ Handler to `dcd_int_handler()`. Application must define IRQ handler in which it calls this API. +- Add `dcd_connect()` and `dcd_disconnect()` to enable/disable internal pullup on D+/D- on supported MCUs. +- Add `usbd_edpt_open()` +- Remove `dcd_set_config()` +- Add *OPT_OS_CUMSTOM* as hook for application to overwrite and/or add their own OS implementation +- Support SET_INTERFACE, GET_INTERFACE request +- Add Logging for debug with optional uart/rtt/swo printf retarget or `CFG_TUSB_DEBUG_PRINTF` hook +- Add IAR compiler support +- Support multiple configuration descriptors. `TUD_CONFIG_DESCRIPTOR()` template has extra config_num as 1st argument +- Improve USB Highspeed support with actual link speed detection with `dcd_event_bus_reset()` +- Enhance class driver management + - `usbd_driver_open()` add max length argument, and return length of interface (0 for not supported). Return value is used for finding appropriate driver + - Add application implemented class driver via `usbd_app_driver_get_cb()` + - IAD is handled to assign driver id +- Added `tud_descriptor_device_qualifier_cb()` callback +- Optimize `tu_fifo` bulk write/read transfer +- Forward non-std control request to class driver +- Let application handle Microsoft OS 1.0 Descriptors (the 0xEE index string) +- Fix OSAL FreeRTOS yield from ISR + +**Class Drivers** + +- USBNET: remove ACM-EEM due to lack of support from host +- USBTMC: fix descriptors when INT EP is disabled +- CDC: + - Send zero length packet for end of data when needed + - Add `tud_cdc_tx_complete_cb()` callback + - Change tud_cdc_n_write_flush() return number of bytes forced to transfer, and flush when writing enough data to fifo +- MIDI: + - Add packet interface + - Add multiple jack descriptors + - Fix MIDI driver for sysex +- DFU Runtime: fix response to SET_INTERFACE and DFU_GETSTATUS request +- Rename some configure macro to make it clear that those are used directly for endpoint transfer + - CFG_TUD_HID_BUFSIZE to `CFG_TUD_HID_EP_BUFSIZE + - CFG_TUD_CDC_EPSIZE to CFG_TUD_CDC_EP_BUFSIZE + - CFG_TUD_MSC_BUFSIZE to CFG_TUD_MSC_EP_BUFSIZE + - CFG_TUD_MIDI_EPSIZE to CFG_TUD_MIDI_EP_BUFSIZE +- HID: + - Fix gamepad template descriptor + - Add multiple HID interface API + - Add extra comma to HID_REPORT_ID + +### USB Host + +- Rework USB host stack (still work in progress) + - Fix compile error with pipehandle + - Rework usbh control and enumeration as non-blocking +- Improve Hub, MSC, HID host driver + +### Examples + +- Add new hid_composite_freertos +- Add new dynamic_configuration to demonstrate how to switch configuration descriptors +- Add new hid_multiple_interface +- Enhance `net_lwip_webserver` example + - Add multiple configuration: RNDIS for Windows, CDC-ECM for macOS (Linux will work with both) + - Update lwip to STABLE-2_1_2_RELEASE for net_lwip_webserver +- Added new Audio example: audio_test uac2_headsest + +### New Boards + +- Espressif ESP32-S2: saola_1, kaluga_1 +- STM32: F746 Nucleo, H743 Eval, H743 Nucleo, F723 discovery, stlink v3 mini, STM32L4r5 Nucleo +- Dialog DA1469x dk pro and dk usb +- Microchip: Great Scoot Gadgets' LUNA, samd11_xplained, D5035-01, atsamd21 xplained pro +- nRF: ItsyBitsy nRF52840 + +## 0.6.0 - 2020.03.30 + +Added **CONTRIBUTORS.md** to give proper credit for contributors to the stack. Special thanks to [Nathan Conrad](https://github.com/pigrew), [Peter Lawrence](https://github.com/majbthrd) and [William D. Jones](https://github.com/cr1901) and others for spending their precious time to add lots of features and ports for this release. + +### Added + +**MCUs** + +- Added support for Microchip SAMG55 +- Added support for Nordic nRF52833 +- Added support for Nuvoton: NUC120, NUC121/NUC125, NUC126, NUC505 +- Added support for NXP LPC: 51Uxx, 54xxx, 55xx +- Added support for NXP iMXRT: RT1011, RT1015, RT1021, RT1052, RT1062, RT1064 +- Added support for Sony CXD56 (Spresense) +- Added support for STM32: L0, F0, F1, F2, F3, F4, F7, H7 +- Added support for TI MSP430 +- Added support for ValentyUSB's eptri + +**Class Driver** + +- Added DFU Runtime class driver +- Added Network class driver with RNDIS, CDC-ECM, CDC-EEM (work in progress) +- Added USBTMC class driver +- Added WebUSB class driver using vendor-specific class +- Added multiple instances support for CDC and MIDI +- Added a handful of unit test with Ceedling. +- Added LOG support for debugging with CFG_TUSB_DEBUG +- Added `tud_descriptor_bos_cb()` for BOS descriptor (required for USB 2.1) +- Added `dcd_edpt0_status_complete()` as optional API for DCD + +**Examples** + +Following examples are added: + +- board_test +- cdc_dual_ports +- dfu_rt +- hid_composite +- net_lwip_webserver +- usbtmc +- webusb_serial + +**Boards** + +Following boards are added: + +- adafruit_clue +- arduino_nano33_ble +- circuitplayground_bluefruit +- circuitplayground_express +- feather_m0_express +- feather_nrf52840_sense +- feather_stm32f405 +- fomu +- itsybitsy_m0 +- itsybitsy_m4 +- lpcxpresso11u37 +- lpcxpresso1549 +- lpcxpresso51u68 +- lpcxpresso54114 +- lpcxpresso55s69 +- mbed1768 +- mimxrt1010_evk +- mimxrt1015_evk +- mimxrt1020_evk +- mimxrt1050_evkb +- mimxrt1060_evk +- mimxrt1064_evk +- msp_exp430f5529lp +- ngx4330 +- nrf52840_mdk_dongle +- nutiny_nuc121s +- nutiny_nuc125s +- nutiny_nuc126v +- nutiny_sdk_nuc120 +- nutiny_sdk_nuc505 +- pca10059 +- pca10100 +- pyboardv11 +- raytac_mdbt50q_rx +- samg55xplained +- seeeduino_xiao +- spresense +- stm32f070rbnucleo +- stm32f072disco +- stm32f103bluepill +- stm32f207nucleo +- stm32f401blackpill +- stm32f411blackpill +- stm32f411disco +- stm32f412disco +- stm32f767nucleo +- stm32h743nucleo +- stm32l0538disco +- stm32l476disco +- teensy_40 + +### Changed + +- Changed `tud_descriptor_string_cb()` to have additional Language ID argument +- Merged hal_nrf5x.c into dcd_nrf5x.c +- Merged dcd_samd21.c and dcd_samd51.c into dcd_samd.c +- Generalized dcd_stm32f4.c to dcd_synopsys.c +- Changed cdc_msc_hid to cdc_msc (drop hid) due to limited endpoints number of some MCUs +- Improved DCD SAMD stability, fix missing setup packet occasionally +- Improved usbd/usbd_control with proper hanlding of zero-length packet (ZLP) +- Improved STM32 DCD FSDev +- Improved STM32 DCD Synopsys +- Migrated CI from Travis to Github Action +- Updated nrfx submodule to 2.1.0 +- Fixed mynewt osal queue definition +- Fixed cdc_msc_freertos example build for all MCUs + +## 0.5.0 (Initial Release) - 2019.07.10 + +First release, device stack works great, host stack works but still need improvement. +- Special thanks to @adafruit team, especially @tannewt to help out immensely to rework device stack: simplify osal & control transfer, adding SAMD21/SAMD51 ports, writing porting docs, adding MIDI class support etc... +- Thanks to @cr1901 for adding STM32F4 port. +- Thanks to @PTS93 and @todbot for HID raw API diff --git a/src/tusb_option.h b/src/tusb_option.h index 6cbdefbf1..cafe9e522 100644 --- a/src/tusb_option.h +++ b/src/tusb_option.h @@ -28,7 +28,7 @@ #define _TUSB_OPTION_H_ #define TUSB_VERSION_MAJOR 0 -#define TUSB_VERSION_MINOR 8 +#define TUSB_VERSION_MINOR 9 #define TUSB_VERSION_REVISION 0 #define TUSB_VERSION_STRING TU_STRING(TUSB_VERSION_MAJOR) "." TU_STRING(TUSB_VERSION_MINOR) "." TU_STRING(TUSB_VERSION_REVISION) -- cgit v1.3.1 From 82e24306e2b0588e944476d71815f83ca392d1b9 Mon Sep 17 00:00:00 2001 From: hathach Date: Tue, 16 Mar 2021 15:49:09 +0700 Subject: fix build with OPT_MCU_LPC177X_8X --- src/portable/nxp/lpc17_40/dcd_lpc17_40.c | 3 ++- src/portable/nxp/lpc17_40/dcd_lpc17_40.h | 6 +++--- src/portable/nxp/lpc17_40/hcd_lpc17_40.c | 3 ++- 3 files changed, 7 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/portable/nxp/lpc17_40/dcd_lpc17_40.c b/src/portable/nxp/lpc17_40/dcd_lpc17_40.c index 7d867aaba..519d09151 100644 --- a/src/portable/nxp/lpc17_40/dcd_lpc17_40.c +++ b/src/portable/nxp/lpc17_40/dcd_lpc17_40.c @@ -26,7 +26,8 @@ #include "tusb_option.h" -#if TUSB_OPT_DEVICE_ENABLED && (CFG_TUSB_MCU == OPT_MCU_LPC175X_6X || CFG_TUSB_MCU == OPT_MCU_LPC40XX) +#if TUSB_OPT_DEVICE_ENABLED && \ + (CFG_TUSB_MCU == OPT_MCU_LPC175X_6X || CFG_TUSB_MCU == OPT_MCU_LPC177X_8X || CFG_TUSB_MCU == OPT_MCU_LPC40XX) #include "device/dcd.h" #include "dcd_lpc17_40.h" diff --git a/src/portable/nxp/lpc17_40/dcd_lpc17_40.h b/src/portable/nxp/lpc17_40/dcd_lpc17_40.h index 1e7c0fbc0..07daa32e4 100644 --- a/src/portable/nxp/lpc17_40/dcd_lpc17_40.h +++ b/src/portable/nxp/lpc17_40/dcd_lpc17_40.h @@ -24,8 +24,8 @@ * This file is part of the TinyUSB stack. */ -#ifndef _TUSB_DCD_LPC175X_6X_H_ -#define _TUSB_DCD_LPC175X_6X_H_ +#ifndef _TUSB_DCD_LPC17_40_H_ +#define _TUSB_DCD_LPC17_40_H_ #include "common/tusb_common.h" @@ -149,4 +149,4 @@ enum { } #endif -#endif /* _TUSB_DCD_LPC175X_6X_H_ */ +#endif diff --git a/src/portable/nxp/lpc17_40/hcd_lpc17_40.c b/src/portable/nxp/lpc17_40/hcd_lpc17_40.c index 537b3daba..1c1faed94 100644 --- a/src/portable/nxp/lpc17_40/hcd_lpc17_40.c +++ b/src/portable/nxp/lpc17_40/hcd_lpc17_40.c @@ -26,7 +26,8 @@ #include "tusb_option.h" -#if (CFG_TUSB_MCU == OPT_MCU_LPC175X_6X || CFG_TUSB_MCU == OPT_MCU_LPC40XX) +#if TUSB_OPT_HOST_ENABLED && \ + (CFG_TUSB_MCU == OPT_MCU_LPC175X_6X || CFG_TUSB_MCU == OPT_MCU_LPC177X_8X || CFG_TUSB_MCU == OPT_MCU_LPC40XX) #include "chip.h" -- cgit v1.3.1 From 62d4652f86516e1fdd7fa79a29535cf39b2ab2f1 Mon Sep 17 00:00:00 2001 From: Michael Bruno Date: Tue, 16 Mar 2021 10:48:42 -0400 Subject: Update usbtmc_device.c Fix buffer alignment in TMC device class --- src/class/usbtmc/usbtmc_device.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/class/usbtmc/usbtmc_device.c b/src/class/usbtmc/usbtmc_device.c index 88776d169..6c9b42449 100644 --- a/src/class/usbtmc/usbtmc_device.c +++ b/src/class/usbtmc/usbtmc_device.c @@ -131,9 +131,9 @@ typedef struct uint8_t ep_int_in; // IN buffer is only used for first packet, not the remainder // in order to deal with prepending header - uint8_t ep_bulk_in_buf[USBTMCD_MAX_PACKET_SIZE]; + CFG_TUSB_MEM_ALIGN uint8_t ep_bulk_in_buf[USBTMCD_MAX_PACKET_SIZE]; // OUT buffer receives one packet at a time - uint8_t ep_bulk_out_buf[USBTMCD_MAX_PACKET_SIZE]; + CFG_TUSB_MEM_ALIGN uint8_t ep_bulk_out_buf[USBTMCD_MAX_PACKET_SIZE]; uint32_t transfer_size_remaining; // also used for requested length for bulk IN. uint32_t transfer_size_sent; // To keep track of data bytes that have been queued in FIFO (not header bytes) -- cgit v1.3.1 From ec08dcf61a86686da101f480565c6fae2acc3359 Mon Sep 17 00:00:00 2001 From: Jeremiah McCarthy Date: Wed, 17 Mar 2021 09:25:01 -0400 Subject: Implement requested changes for PR724 --- src/class/usbtmc/usbtmc_device.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/class/usbtmc/usbtmc_device.c b/src/class/usbtmc/usbtmc_device.c index 6c9b42449..d5f8fe41d 100644 --- a/src/class/usbtmc/usbtmc_device.c +++ b/src/class/usbtmc/usbtmc_device.c @@ -145,7 +145,7 @@ typedef struct usbtmc_capabilities_specific_t const * capabilities; } usbtmc_interface_state_t; -static usbtmc_interface_state_t usbtmc_state = +CFG_TUSB_MEM_SECTION static usbtmc_interface_state_t usbtmc_state = { .itf_id = 0xFF, }; -- cgit v1.3.1 From 64f41dea62ee48452c4b353cb34ddbd57a8fffad Mon Sep 17 00:00:00 2001 From: hathach Date: Thu, 18 Mar 2021 15:07:07 +0700 Subject: fix race condition that could cause drop packet of Bulk OUT transfer NRF_USBD->SIZE.EPOUT[epnum] only need to write once to enable Bulk/Interrupt transfer. We only need to do it in dcd_edpt_open() and dcd_edpt_clear_stall() --- src/portable/nordic/nrf5x/dcd_nrf5x.c | 131 +++++++++++++++++----------------- 1 file changed, 66 insertions(+), 65 deletions(-) (limited to 'src') diff --git a/src/portable/nordic/nrf5x/dcd_nrf5x.c b/src/portable/nordic/nrf5x/dcd_nrf5x.c index d9fe2b6ae..6b8095a00 100644 --- a/src/portable/nordic/nrf5x/dcd_nrf5x.c +++ b/src/portable/nordic/nrf5x/dcd_nrf5x.c @@ -53,13 +53,11 @@ enum enum { - // Endpoint number is fixed (8) for ISOOUT and ISOIN. - EP_ISO_NUM = 8, - // CBI endpoints count - EP_COUNT = 8 + EP_ISO_NUM = 8, // Endpoint number is fixed (8) for ISOOUT and ISOIN + EP_CBI_COUNT = 8 // Control Bulk Interrupt endpoints count }; -// Transfer descriptor +// Transfer Descriptor typedef struct { uint8_t* buffer; @@ -67,9 +65,10 @@ typedef struct volatile uint16_t actual_len; uint16_t mps; // max packet size - // nrf52840 will auto ACK OUT packet after DMA is done + // nRF will auto accept OUT packet after DMA is done // indicate packet is already ACK volatile bool data_received; + // Set to true when data was transferred from RAM to ISO IN output buffer. // New data can be put in ISO IN output buffer after SOF. bool iso_in_transfer_ready; @@ -81,7 +80,7 @@ static struct { // All 8 endpoints including control IN & OUT (offset 1) // +1 for ISO endpoints - xfer_td_t xfer[EP_COUNT + 1][2]; + xfer_td_t xfer[EP_CBI_COUNT + 1][2]; // Number of pending DMA that is started but not handled yet by dcd_int_handler(). // Since nRF can only carry one DMA can run at a time, this value is normally be either 0 or 1. @@ -133,7 +132,7 @@ static void edpt_dma_start(volatile uint32_t* reg_startep) { ended = NRF_USBD->EVENTS_ENDISOIN + NRF_USBD->EVENTS_ENDISOOUT; - for (uint8_t i=0; iEVENTS_ENDEPIN[i] + NRF_USBD->EVENTS_ENDEPOUT[i]; } @@ -166,27 +165,6 @@ static inline xfer_td_t* get_td(uint8_t epnum, uint8_t dir) return &_dcd.xfer[epnum][dir]; } -/*------------- CBI OUT Transfer -------------*/ - -// Prepare for a CBI transaction OUT, call at the start -// Allow ACK incoming data -static void xact_out_prepare(uint8_t epnum) -{ - if ( epnum == 0 ) - { - NRF_USBD->TASKS_EP0RCVOUT = 1; - } - else - { - // Write zero value to SIZE register will allow hw to ACK (accept data) - // If it is not already done by DMA - // SIZE.ISOOUT can also be accessed this way - NRF_USBD->SIZE.EPOUT[epnum] = 0; - } - - __ISB(); __DSB(); -} - // Start DMA to move data from Endpoint -> RAM static void xact_out_dma(uint8_t epnum) { @@ -217,15 +195,14 @@ static void xact_out_dma(uint8_t epnum) edpt_dma_start(&NRF_USBD->TASKS_STARTEPOUT[epnum]); } + xfer->buffer += xact_len; xfer->actual_len += xact_len; } -/*------------- CBI IN Transfer -------------*/ - // Prepare for a CBI transaction IN, call at the start // it start DMA to transfer data from RAM -> Endpoint -static void xact_in_prepare(uint8_t epnum) +static void xact_in_dma(uint8_t epnum) { xfer_td_t* xfer = get_td(epnum, TUSB_DIR_IN); @@ -327,6 +304,9 @@ bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * desc_edpt) { NRF_USBD->INTENSET = TU_BIT(USBD_INTEN_ENDEPOUT0_Pos + epnum); NRF_USBD->EPOUTEN |= TU_BIT(epnum); + + // Write any value to SIZE register will allow nRF to ACK/accept data + NRF_USBD->SIZE.EPOUT[epnum] = 0; }else { NRF_USBD->INTENSET = TU_BIT(USBD_INTEN_ENDEPIN0_Pos + epnum); @@ -438,20 +418,31 @@ bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t } else if ( dir == TUSB_DIR_OUT ) { - if ( xfer->data_received ) + if ( epnum == 0 ) { - // nrf52840 auto ACK OUT packet after DMA is done - // Data already received previously --> trigger DMA to copy to SRAM - xact_out_dma(epnum); - } - else + // Accept next Control Out packet + NRF_USBD->TASKS_EP0RCVOUT = 1; + }else { - xact_out_prepare(epnum); + if ( xfer->data_received ) + { + // Data may already be received previously + xfer->data_received = false; + + // start DMA to copy to SRAM + xact_out_dma(epnum); + } + else + { + // nRF auto accept next Bulk/Interrupt OUT packet + // nothing to do + } } } else { - xact_in_prepare(epnum); + // Start DMA to copy data from RAM -> Endpoint + xact_in_dma(epnum); } return true; @@ -477,6 +468,7 @@ void dcd_edpt_clear_stall (uint8_t rhport, uint8_t ep_addr) { (void) rhport; uint8_t const epnum = tu_edpt_number(ep_addr); + uint8_t const dir = tu_edpt_dir(ep_addr); if ( epnum != 0 && epnum != EP_ISO_NUM ) { @@ -486,6 +478,10 @@ void dcd_edpt_clear_stall (uint8_t rhport, uint8_t ep_addr) // reset data toggle to DATA0 NRF_USBD->DTOGGLE = (USBD_DTOGGLE_VALUE_Data0 << USBD_DTOGGLE_VALUE_Pos) | ep_addr; + // Write any value to SIZE register will allow nRF to ACK/accept data + // Drop any pending data + if (dir == TUSB_DIR_OUT) NRF_USBD->SIZE.EPOUT[epnum] = 0; + __ISB(); __DSB(); } } @@ -594,17 +590,18 @@ void dcd_int_handler(uint8_t rhport) // Setup tokens are specific to the Control endpoint. if ( int_status & USBD_INTEN_EP0SETUP_Msk ) { - uint8_t const setup[8] = { - NRF_USBD->BMREQUESTTYPE , NRF_USBD->BREQUEST, NRF_USBD->WVALUEL , NRF_USBD->WVALUEH, - NRF_USBD->WINDEXL , NRF_USBD->WINDEXH , NRF_USBD->WLENGTHL, NRF_USBD->WLENGTHH + uint8_t const setup[8] = + { + NRF_USBD->BMREQUESTTYPE , NRF_USBD->BREQUEST, NRF_USBD->WVALUEL , NRF_USBD->WVALUEH, + NRF_USBD->WINDEXL , NRF_USBD->WINDEXH , NRF_USBD->WLENGTHL, NRF_USBD->WLENGTHH }; // nrf5x hw auto handle set address, there is no need to inform usb stack tusb_control_request_t const * request = (tusb_control_request_t const *) setup; - if ( !(TUSB_REQ_RCPT_DEVICE == request->bmRequestType_bit.recipient && + if ( !(TUSB_REQ_RCPT_DEVICE == request->bmRequestType_bit.recipient && TUSB_REQ_TYPE_STANDARD == request->bmRequestType_bit.type && - TUSB_REQ_SET_ADDRESS == request->bRequest) ) + TUSB_REQ_SET_ADDRESS == request->bRequest) ) { dcd_event_setup_received(0, setup, true); } @@ -620,15 +617,15 @@ void dcd_int_handler(uint8_t rhport) * For CBI OUT: * - Host -> Endpoint * EPDATA (or EP0DATADONE) interrupted, check EPDATASTATUS.EPOUT[i] - * to start DMA. This step can occur automatically (without sw), - * which means data may or may not ready (data_received flag). + * to start DMA. For Bulk/Interrupt, this step can occur automatically (without sw), + * which means data may or may not be ready (data_received flag). * - Endpoint -> RAM * ENDEPOUT[i] interrupted, transaction complete, sw prepare next transaction * * For CBI IN: * - RAM -> Endpoint * ENDEPIN[i] interrupted indicate DMA is complete. HW will start - * to move daat to host + * to move data to host * - Endpoint -> Host * EPDATA (or EP0DATADONE) interrupted, check EPDATASTATUS.EPIN[i]. * Transaction is complete, sw prepare next transaction @@ -640,27 +637,31 @@ void dcd_int_handler(uint8_t rhport) /* CBI OUT: Endpoint -> SRAM (aka transaction complete) * Note: Since nRF controller auto ACK next packet without SW awareness - * We must handle this stage before Host -> Endpoint just in case - * 2 event happens at once - * ISO OUT: Transaction must fit in single packed, it can be shorter then total + * We must handle this stage before Host -> Endpoint just in case 2 event happens at once + * + * ISO OUT: Transaction must fit in single packet, it can be shorter then total * len if Host decides to sent fewer bytes, it this case transaction is also * complete and next transfer is not initiated here like for CBI. */ - for(uint8_t epnum=0; epnumEPOUT[epnum].AMOUNT; - // Data in endpoint has been consumed - xfer->data_received = false; - // Transfer complete if transaction len < Max Packet Size or total len is transferred if ( (epnum != EP_ISO_NUM) && (xact_len == xfer->mps) && (xfer->actual_len < xfer->total_len) ) { - // Prepare for next transaction - xact_out_prepare(epnum); + if ( epnum == 0 ) + { + // Accept next Control Out packet + NRF_USBD->TASKS_EP0RCVOUT = 1; + }else + { + // nRF auto accept next Bulk/Interrupt OUT packet + // nothing to do + } }else { xfer->total_len = xfer->actual_len; @@ -673,7 +674,7 @@ void dcd_int_handler(uint8_t rhport) // Ended event for CBI IN : nothing to do } - // Endpoint <-> Host + // Endpoint <-> Host ( In & OUT ) if ( int_status & (USBD_INTEN_EPDATA_Msk | USBD_INTEN_EP0DATADONE_Msk) ) { uint32_t data_status = NRF_USBD->EPDATASTATUS; @@ -687,9 +688,9 @@ void dcd_int_handler(uint8_t rhport) bool const is_control_out = (int_status & USBD_INTEN_EP0DATADONE_Msk) && !(NRF_USBD->BMREQUESTTYPE & TUSB_DIR_IN_MASK); // CBI In: Endpoint -> Host (transaction complete) - for(uint8_t epnum=0; epnum<8; epnum++) + for(uint8_t epnum=0; epnumactual_len < xfer->total_len ) { - // prepare next transaction - xact_in_prepare(epnum); + // Start DMA to copy next data packet + xact_in_dma(epnum); } else { // CBI IN complete @@ -708,9 +709,9 @@ void dcd_int_handler(uint8_t rhport) } // CBI OUT: Host -> Endpoint - for(uint8_t epnum=0; epnum<8; epnum++) + for(uint8_t epnum=0; epnumdata_received = true; } -- cgit v1.3.1 From 143582870c8a4175706109e238f4cfa814ae90bc Mon Sep 17 00:00:00 2001 From: Rafael Silva Date: Thu, 4 Mar 2021 23:00:48 +0000 Subject: add efm32gg12 family Signed-off-by: Rafael Silva --- hw/bsp/board_mcu.h | 3 +++ src/tusb_option.h | 5 +++++ 2 files changed, 8 insertions(+) (limited to 'src') diff --git a/hw/bsp/board_mcu.h b/hw/bsp/board_mcu.h index a175197e5..3c18f6d3d 100644 --- a/hw/bsp/board_mcu.h +++ b/hw/bsp/board_mcu.h @@ -119,6 +119,9 @@ #elif CFG_TUSB_MCU == OPT_MCU_RP2040 #include "pico.h" + +#elif CFG_TUSB_MCU == OPT_MCU_EFM32GG || CFG_TUSB_MCU == OPT_MCU_EFM32GG11 || CFG_TUSB_MCU == OPT_MCU_EFM32GG12 + #include "em_device.h" #else #error "Missing MCU header" diff --git a/src/tusb_option.h b/src/tusb_option.h index cafe9e522..d0ed78acd 100644 --- a/src/tusb_option.h +++ b/src/tusb_option.h @@ -103,6 +103,11 @@ // NXP Kinetis #define OPT_MCU_MKL25ZXX 1200 ///< NXP MKL25Zxx +// Silabs +#define OPT_MCU_EFM32GG 1300 ///< Silabs EFM32GG +#define OPT_MCU_EFM32GG11 1301 ///< Silabs EFM32GG11 +#define OPT_MCU_EFM32GG12 1302 ///< Silabs EFM32GG12 + /** @} */ /** \defgroup group_supported_os Supported RTOS -- cgit v1.3.1 From 2807644e7e72150b96be0f40a263f689a6de994a Mon Sep 17 00:00:00 2001 From: Rafael Silva Date: Thu, 4 Mar 2021 23:02:42 +0000 Subject: add efm32 driver Signed-off-by: Rafael Silva --- src/portable/silabs/efm32/dcd_efm32.c | 931 ++++++++++++++++++++++++++++++++++ 1 file changed, 931 insertions(+) create mode 100644 src/portable/silabs/efm32/dcd_efm32.c (limited to 'src') diff --git a/src/portable/silabs/efm32/dcd_efm32.c b/src/portable/silabs/efm32/dcd_efm32.c new file mode 100644 index 000000000..bd1f32e6b --- /dev/null +++ b/src/portable/silabs/efm32/dcd_efm32.c @@ -0,0 +1,931 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2021 Rafael Silva (@perigoso) + * Copyright (c) 2021 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 TUSB_OPT_DEVICE_ENABLED && ( \ + (CFG_TUSB_MCU == OPT_MCU_EFM32GG) || \ + (CFG_TUSB_MCU == OPT_MCU_EFM32GG11) || \ + (CFG_TUSB_MCU == OPT_MCU_EFM32GG12) ) + +/* Silabs */ +#include "em_device.h" + +#include "device/dcd.h" + +/* + * Since TinyUSB doesn't use SOF for now, and this interrupt too often (1ms interval) + * We disable SOF for now until needed later on + */ +#define USE_SOF 0 + +/* + * Number of endpoints + * 12 software-configurable endpoints (6 IN, 6 OUT) in addition to endpoint 0 + */ +#define EP_COUNT 7 + +/* FIFO size in bytes */ +#define EP_FIFO_SIZE 2048 + +/* Max number of IN EP FIFOs */ +#define EP_FIFO_NUM 7 + +/* */ +typedef struct { + uint8_t *buffer; + uint16_t total_len; + uint16_t queued_len; + uint16_t max_size; + bool short_packet; +} xfer_ctl_t; + +static uint32_t _setup_packet[2]; + +#define XFER_CTL_BASE(_ep, _dir) &xfer_status[_ep][_dir] +static xfer_ctl_t xfer_status[EP_COUNT][2]; + +/* Keep count of how many FIFOs are in use */ +static uint8_t _allocated_fifos = 1; /* FIFO0 is always in use */ + +static volatile uint32_t* tx_fifo[EP_FIFO_NUM] = { + USB->FIFO0D, + USB->FIFO1D, + USB->FIFO2D, + USB->FIFO3D, + USB->FIFO4D, + USB->FIFO5D, + USB->FIFO6D, +}; + +/* Register Helpers */ +#define DCTL_WO_BITMASK (USB_DCTL_CGOUTNAK | USB_DCTL_SGOUTNAK | USB_DCTL_CGNPINNAK | USB_DCTL_SGNPINNAK) +#define GUSBCFG_WO_BITMASK (USB_GUSBCFG_CORRUPTTXPKT) +#define DEPCTL_WO_BITMASK (USB_DIEP_CTL_CNAK | USB_DIEP_CTL_SNAK | USB_DIEP_CTL_SETD0PIDEF | USB_DIEP_CTL_SETD1PIDOF) + +/* Will either return an unused FIFO number, or 0 if all are used. */ +static uint8_t get_free_fifo(void) +{ + if(_allocated_fifos < EP_FIFO_NUM) return _allocated_fifos++; + return 0; +} + +/* +static void flush_rx_fifo(void) +{ + USB->GRSTCTL = USB_GRSTCTL_RXFFLSH; + while(USB->GRSTCTL & USB_GRSTCTL_RXFFLSH); +} +*/ + +static void flush_tx_fifo(uint8_t fifo_num) +{ + USB->GRSTCTL = USB_GRSTCTL_TXFFLSH | (fifo_num << _USB_GRSTCTL_TXFNUM_SHIFT); + while(USB->GRSTCTL & USB_GRSTCTL_TXFFLSH); +} + +/* Setup the control endpoint 0. */ +static void bus_reset(void) +{ + USB->DOEP0CTL |= USB_DIEP_CTL_SNAK; + for(uint8_t i = 0; i < EP_COUNT - 1; i++) + { + USB->DOEP[i].CTL |= USB_DIEP_CTL_SNAK; + } + + /* reset address */ + USB->DCFG &= ~_USB_DCFG_DEVADDR_MASK; + + USB->DAINTMSK |= USB_DAINTMSK_OUTEPMSK0 | USB_DAINTMSK_INEPMSK0; + USB->DOEPMSK |= USB_DOEPMSK_SETUPMSK | USB_DOEPMSK_XFERCOMPLMSK; + USB->DIEPMSK |= USB_DIEPMSK_TIMEOUTMSK | USB_DIEPMSK_XFERCOMPLMSK; + + /* + * - All EP OUT shared a unique OUT FIFO which uses + * * 10 locations in hardware for setup packets + setup control words (up to 3 setup packets). + * * 2 locations for OUT endpoint control words. + * * 16 for largest packet size of 64 bytes. ( TODO Highspeed is 512 bytes) + * * 1 location for global NAK (not required/used here). + * * It is recommended to allocate 2 times the largest packet size, therefore + * Recommended value = 10 + 1 + 2 x (16+2) = 47 --> Let's make it 52 + */ + flush_tx_fifo(_USB_GRSTCTL_TXFNUM_FALL); // Flush All + USB->GRXFSIZ = 52; + + /* Control IN uses FIFO 0 with 64 bytes ( 16 32-bit word ) */ + USB->GNPTXFSIZ = (16 << _USB_GNPTXFSIZ_NPTXFINEPTXF0DEP_SHIFT) | (USB->GRXFSIZ & _USB_GNPTXFSIZ_NPTXFSTADDR_MASK); + + /* Ready to receive SETUP packet */ + USB->DOEP0TSIZ |= (1 << _USB_DOEP0TSIZ_SUPCNT_SHIFT); + + USB->GINTMSK |= USB_GINTMSK_IEPINTMSK | USB_GINTMSK_OEPINTMSK; +} + +static void enum_done_processing(void) +{ + /* Maximum packet size for EP 0 is set for both directions by writing DIEPCTL */ + if((USB->DSTS & _USB_DSTS_ENUMSPD_MASK) == USB_DSTS_ENUMSPD_FS) + { + /* Full Speed (PHY on 48 MHz) */ + USB->DOEP0CTL = (USB->DOEP0CTL & ~_USB_DOEP0CTL_MPS_MASK) | _USB_DOEP0CTL_MPS_64B; /* Maximum Packet Size 64 bytes */ + USB->DOEP0CTL &= ~_USB_DOEP0CTL_STALL_MASK; /* clear Stall */ + xfer_status[0][TUSB_DIR_OUT].max_size = 64; + xfer_status[0][TUSB_DIR_IN].max_size = 64; + } + else + { + /* Low Speed (PHY on 6 MHz) */ + USB->DOEP0CTL = (USB->DOEP0CTL & ~_USB_DOEP0CTL_MPS_MASK) | _USB_DOEP0CTL_MPS_8B; /* Maximum Packet Size 64 bytes */ + USB->DOEP0CTL &= ~_USB_DOEP0CTL_STALL_MASK; /* clear Stall */ + xfer_status[0][TUSB_DIR_OUT].max_size = 8; + xfer_status[0][TUSB_DIR_IN].max_size = 8; + } +} + + +/*------------------------------------------------------------------*/ +/* Controller API */ +/*------------------------------------------------------------------*/ +void dcd_init(uint8_t rhport) +{ + (void) rhport; + + /* Reset Core */ + USB->PCGCCTL &= ~USB_PCGCCTL_STOPPCLK; + USB->PCGCCTL &= ~(USB_PCGCCTL_PWRCLMP | USB_PCGCCTL_RSTPDWNMODULE); + + /* Core Soft Reset */ + USB->GRSTCTL |= USB_GRSTCTL_CSFTRST; + while(USB->GRSTCTL & USB_GRSTCTL_CSFTRST); + + while(!(USB->GRSTCTL & USB_GRSTCTL_AHBIDLE)); + + /* Enable PHY pins */ + USB->ROUTE = USB_ROUTE_PHYPEN; + + dcd_disconnect(rhport); + + /* + * Set device speed (Full speed PHY) + * Stall on non-zero len status OUT packets (ctrl transfers) + * periodic frame interval to 80% + */ + USB->DCFG = (USB->DCFG & ~(_USB_DCFG_DEVSPD_MASK | _USB_DCFG_PERFRINT_MASK)) | USB_DCFG_DEVSPD_FS | USB_DCFG_NZSTSOUTHSHK; + + /* Enable Global Interrupts */ + USB->GAHBCFG = (USB->GAHBCFG & ~_USB_GAHBCFG_HBSTLEN_MASK) | USB_GAHBCFG_GLBLINTRMSK; + + /* Force Device Mode */ + USB->GUSBCFG = (USB->GUSBCFG & ~(GUSBCFG_WO_BITMASK | USB_GUSBCFG_FORCEHSTMODE)) | USB_GUSBCFG_FORCEDEVMODE; + + /* No Overrides */ + USB->GOTGCTL &= ~(USB_GOTGCTL_BVALIDOVVAL | USB_GOTGCTL_BVALIDOVEN | USB_GOTGCTL_VBVALIDOVVAL); + + /* Ignore frame numbers on ISO transfers. */ + USB->DCTL = (USB->DCTL & ~DCTL_WO_BITMASK) | USB_DCTL_IGNRFRMNUM; + + /* Setting SNAKs */ + USB->DOEP0CTL |= USB_DIEP_CTL_SNAK; + for(uint8_t i = 0; i < EP_COUNT - 1; i++) + { + USB->DOEP[i].CTL |= USB_DIEP_CTL_SNAK; + } + + /* D. Interruption masking */ + /* Disable all device interrupts */ + USB->DIEPMSK = 0; + USB->DOEPMSK = 0; + USB->DAINTMSK = 0; + USB->DIEPEMPMSK = 0; + USB->GINTMSK = 0; + USB->GOTGINT = ~0U; /* clear OTG ints */ + USB->GINTSTS = ~0U; /* clear pending ints */ + USB->GINTMSK = USB_GINTMSK_MODEMISMSK | + #if USE_SOF + USB_GINTMSK_SOFMSK | + #endif + USB_GINTMSK_ERLYSUSPMSK | + USB_GINTMSK_USBSUSPMSK | + USB_GINTMSK_USBRSTMSK | + USB_GINTMSK_ENUMDONEMSK | + USB_GINTMSK_RESETDETMSK | + USB_GINTMSK_DISCONNINTMSK; + + NVIC_ClearPendingIRQ(USB_IRQn); + + dcd_connect(rhport); +} + +void dcd_set_address(uint8_t rhport, uint8_t dev_addr) +{ + (void) rhport; + + USB->DCFG = (USB->DCFG & ~_USB_DCFG_DEVADDR_MASK) | (dev_addr << _USB_DCFG_DEVADDR_SHIFT); + + /* Response with status after changing device address */ + dcd_edpt_xfer(rhport, tu_edpt_addr(0, TUSB_DIR_IN), NULL, 0); +} + +void dcd_remote_wakeup(uint8_t rhport) +{ + (void) rhport; +} + +void dcd_connect(uint8_t rhport) +{ + (void) rhport; + + /* connect by enabling internal pull-up resistor on D+/D- */ + USB->DCTL &= ~(DCTL_WO_BITMASK | USB_DCTL_SFTDISCON); +} + +void dcd_disconnect(uint8_t rhport) +{ + (void) rhport; + + /* disconnect by disabling internal pull-up resistor on D+/D- */ + USB->DCTL = (USB->DCTL & ~(DCTL_WO_BITMASK)) | USB_DCTL_SFTDISCON; +} + +/*------------------------------------------------------------------*/ +/* DCD Endpoint Port */ +/*------------------------------------------------------------------*/ +void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr) +{ + (void) rhport; + + uint8_t const epnum = tu_edpt_number(ep_addr); + uint8_t const dir = tu_edpt_dir(ep_addr); + + if(dir == TUSB_DIR_IN) + { + if(epnum == 0) + { + USB->DIEP0CTL = (USB->DIEP0CTL & ~DEPCTL_WO_BITMASK) | USB_DIEP0CTL_SNAK | USB_DIEP0CTL_STALL; + + flush_tx_fifo(_USB_GRSTCTL_TXFNUM_F0); + } + else + { + /* Only disable currently enabled non-control endpoint */ + if(USB->DIEP[epnum - 1].CTL & USB_DIEP_CTL_EPENA) + { + USB->DIEP[epnum - 1].CTL = (USB->DIEP[epnum - 1].CTL & ~DEPCTL_WO_BITMASK) | USB_DIEP_CTL_EPDIS | USB_DIEP_CTL_SNAK | USB_DIEP_CTL_STALL; + while(!(USB->DIEP[epnum - 1].INT & USB_DIEP_INT_EPDISBLD)); + USB->DIEP[epnum - 1].INT |= USB_DIEP_INT_EPDISBLD; + } + else + { + USB->DIEP[epnum - 1].CTL = (USB->DIEP[epnum - 1].CTL & ~DEPCTL_WO_BITMASK) | USB_DIEP_CTL_SNAK | USB_DIEP_CTL_STALL; + } + + /* Flush the FIFO */ + uint8_t const fifo_num = ((USB->DIEP[epnum - 1].CTL & _USB_DIEP_CTL_TXFNUM_MASK) >> _USB_DIEP_CTL_TXFNUM_SHIFT); + flush_tx_fifo(fifo_num); + } + } + else + { + if(epnum == 0) + { + USB->DOEP0CTL = (USB->DOEP0CTL & ~DEPCTL_WO_BITMASK) | USB_DIEP0CTL_STALL; + } + else + { + /* Only disable currently enabled non-control endpoint */ + if(USB->DOEP[epnum - 1].CTL & USB_DIEP_CTL_EPENA) + { + /* Asserting GONAK is required to STALL an OUT endpoint. */ + USB->DCTL |= USB_DCTL_SGOUTNAK; + while(!(USB->GINTSTS & USB_GINTSTS_GOUTNAKEFF)); + + /* Disable the endpoint. Note that only STALL and not SNAK is set here. */ + USB->DOEP[epnum - 1].CTL = (USB->DOEP[epnum - 1].CTL & ~DEPCTL_WO_BITMASK) | USB_DIEP_CTL_EPDIS | USB_DIEP_CTL_STALL; + while(USB->DOEP[epnum - 1].INT & USB_DIEP_INT_EPDISBLD); + USB->DOEP[epnum - 1].INT |= USB_DIEP_INT_EPDISBLD; + + /* Allow other OUT endpoints to keep receiving. */ + USB->DCTL |= USB_DCTL_CGOUTNAK; + } + else + { + USB->DIEP[epnum - 1].CTL = (USB->DIEP[epnum - 1].CTL & ~DEPCTL_WO_BITMASK) | USB_DIEP_CTL_STALL; + } + } + } +} + +void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr) +{ + (void) rhport; + + uint8_t const epnum = tu_edpt_number(ep_addr); + uint8_t const dir = tu_edpt_dir(ep_addr); + + if(dir == TUSB_DIR_IN) + { + if(epnum == 0) + { + USB->DIEP0CTL &= ~(DEPCTL_WO_BITMASK | USB_DIEP0CTL_STALL); + } + else + { + USB->DIEP[epnum - 1].CTL &= ~(DEPCTL_WO_BITMASK | USB_DIEP_CTL_STALL); + + /* Required by USB spec to reset DATA toggle bit to DATA0 on interrupt and bulk endpoints. */ + uint8_t eptype = (USB->DIEP[epnum - 1].CTL & _USB_DIEP_CTL_EPTYPE_MASK) >> _USB_DIEP_CTL_EPTYPE_SHIFT; + + if((eptype == _USB_DIEP_CTL_EPTYPE_BULK) || (eptype == _USB_DIEP_CTL_EPTYPE_INT)) + { + USB->DIEP[epnum - 1].CTL |= USB_DIEP_CTL_SETD0PIDEF; + } + } + } + else + { + if(epnum == 0) + { + USB->DOEP0CTL &= ~(DEPCTL_WO_BITMASK | USB_DOEP0CTL_STALL); + } + else + { + USB->DOEP[epnum - 1].CTL &= ~(DEPCTL_WO_BITMASK | USB_DOEP_CTL_STALL); + + /* Required by USB spec to reset DATA toggle bit to DATA0 on interrupt and bulk endpoints. */ + uint8_t eptype = (USB->DOEP[epnum - 1].CTL & _USB_DOEP_CTL_EPTYPE_MASK) >> _USB_DOEP_CTL_EPTYPE_SHIFT; + + if((eptype == _USB_DOEP_CTL_EPTYPE_BULK) || (eptype == _USB_DOEP_CTL_EPTYPE_INT)) + { + USB->DOEP[epnum - 1].CTL |= USB_DOEP_CTL_SETD0PIDEF; + } + } + } +} + +bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc) +{ + (void)rhport; + + uint8_t const epnum = tu_edpt_number(p_endpoint_desc->bEndpointAddress); + uint8_t const dir = tu_edpt_dir(p_endpoint_desc->bEndpointAddress); + + TU_ASSERT(p_endpoint_desc->wMaxPacketSize.size <= 64); + TU_ASSERT(epnum < EP_COUNT); + TU_ASSERT(epnum != 0); + + xfer_ctl_t *xfer = XFER_CTL_BASE(epnum, dir); + xfer->max_size = p_endpoint_desc->wMaxPacketSize.size; + + if(dir == TUSB_DIR_OUT) + { + USB->DOEP[epnum - 1].CTL |= USB_DOEP_CTL_USBACTEP | + (p_endpoint_desc->bmAttributes.xfer << _USB_DOEP_CTL_EPTYPE_SHIFT) | + (p_endpoint_desc->wMaxPacketSize.size << _USB_DOEP_CTL_MPS_SHIFT); + USB->DAINTMSK |= (1 << (_USB_DAINTMSK_OUTEPMSK0_SHIFT + epnum)); + } + else + { + uint8_t fifo_num = get_free_fifo(); + TU_ASSERT(fifo_num != 0); + + USB->DIEP[epnum - 1].CTL &= ~(_USB_DIEP_CTL_TXFNUM_MASK | _USB_DIEP_CTL_EPTYPE_MASK | USB_DIEP_CTL_SETD0PIDEF | _USB_DIEP_CTL_MPS_MASK); + USB->DIEP[epnum - 1].CTL |= USB_DIEP_CTL_USBACTEP | + (fifo_num << _USB_DIEP_CTL_TXFNUM_SHIFT) | + (p_endpoint_desc->bmAttributes.xfer << _USB_DIEP_CTL_EPTYPE_SHIFT) | + ((p_endpoint_desc->bmAttributes.xfer != TUSB_XFER_ISOCHRONOUS) ? USB_DIEP_CTL_SETD0PIDEF : 0) | + (p_endpoint_desc->wMaxPacketSize.size << 0); + + USB->DAINTMSK |= (1 << epnum); + + /* Both TXFD and TXSA are in unit of 32-bit words. */ + /* IN FIFO 0 was configured during enumeration, hence the "+ 16". */ + uint16_t const allocated_size = (USB->GRXFSIZ & _USB_GRXFSIZ_RXFDEP_MASK) + 16; + uint16_t const fifo_size = (EP_FIFO_SIZE/4 - allocated_size) / (EP_FIFO_NUM-1); + uint32_t const fifo_offset = allocated_size + fifo_size*(fifo_num-1); + + /* DIEPTXF starts at FIFO #1. */ + volatile uint32_t* usb_dieptxf = &USB->DIEPTXF1; + usb_dieptxf[epnum - 1] = (fifo_size << _USB_DIEPTXF1_INEPNTXFDEP_SHIFT) | fifo_offset; + } + return true; +} + +bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, uint16_t total_bytes) +{ + (void)rhport; + + uint8_t const epnum = tu_edpt_number(ep_addr); + uint8_t const dir = tu_edpt_dir(ep_addr); + + xfer_ctl_t * xfer = XFER_CTL_BASE(epnum, dir); + xfer->buffer = buffer; + xfer->total_len = total_bytes; + xfer->queued_len = 0; + xfer->short_packet = false; + + uint16_t num_packets = (total_bytes / xfer->max_size); + uint8_t short_packet_size = total_bytes % xfer->max_size; + + // Zero-size packet is special case. + if(short_packet_size > 0 || (total_bytes == 0)) + { + num_packets++; + } + + // IN and OUT endpoint xfers are interrupt-driven, we just schedule them + // here. + if(dir == TUSB_DIR_IN) + { + if(epnum == 0) + { + // A full IN transfer (multiple packets, possibly) triggers XFRC. + USB->DIEP0TSIZ = (num_packets << _USB_DIEP0TSIZ_PKTCNT_SHIFT) | total_bytes; + USB->DIEP0CTL |= USB_DIEP0CTL_EPENA | USB_DIEP0CTL_CNAK; // Enable | CNAK + } + else + { + // A full IN transfer (multiple packets, possibly) triggers XFRC. + USB->DIEP[epnum - 1].TSIZ = (num_packets << _USB_DIEP_TSIZ_PKTCNT_SHIFT) | total_bytes; + USB->DIEP[epnum - 1].CTL |= USB_DIEP_CTL_EPENA | USB_DIEP_CTL_CNAK; // Enable | CNAK + } + + // Enable fifo empty interrupt only if there are something to put in the fifo. + if(total_bytes != 0) + { + USB->DIEPEMPMSK |= (1 << epnum); + } + } + else + { + if(epnum == 0) + { + // A full IN transfer (multiple packets, possibly) triggers XFRC. + USB->DOEP0TSIZ |= (1 << _USB_DOEP0TSIZ_PKTCNT_SHIFT) | ((xfer->max_size & _USB_DOEP0TSIZ_XFERSIZE_MASK) << _USB_DOEP0TSIZ_XFERSIZE_SHIFT); + USB->DOEP0CTL |= USB_DOEP0CTL_EPENA | USB_DOEP0CTL_CNAK; + } + else + { + // A full IN transfer (multiple packets, possibly) triggers XFRC. + USB->DOEP[epnum - 1].TSIZ |= (1 << _USB_DOEP_TSIZ_PKTCNT_SHIFT) | ((xfer->max_size & _USB_DOEP_TSIZ_XFERSIZE_MASK) << _USB_DOEP_TSIZ_XFERSIZE_SHIFT); + USB->DOEP[epnum - 1].CTL |= USB_DOEP_CTL_EPENA | USB_DOEP_CTL_CNAK; + } + } + return true; +} + +/*------------------------------------------------------------------*/ +/* IRQ */ +/*------------------------------------------------------------------*/ +void dcd_int_enable(uint8_t rhport) +{ + (void) rhport; + + NVIC_EnableIRQ(USB_IRQn); +} + +void dcd_int_disable(uint8_t rhport) +{ + (void) rhport; + + NVIC_DisableIRQ(USB_IRQn); +} + +static void receive_packet(xfer_ctl_t *xfer, uint16_t xfer_size) +{ + uint16_t remaining = xfer->total_len - xfer->queued_len; + uint16_t to_recv_size; + + if(remaining <= xfer->max_size) + { + /* Avoid buffer overflow. */ + to_recv_size = (xfer_size > remaining) ? remaining : xfer_size; + } + else + { + /* Room for full packet, choose recv_size based on what the microcontroller claims. */ + to_recv_size = (xfer_size > xfer->max_size) ? xfer->max_size : xfer_size; + } + + uint8_t to_recv_rem = to_recv_size % 4; + uint16_t to_recv_size_aligned = to_recv_size - to_recv_rem; + + /* Do not assume xfer buffer is aligned. */ + uint8_t *base = (xfer->buffer + xfer->queued_len); + + /* This for loop always runs at least once- skip if less than 4 bytes to collect. */ + if(to_recv_size >= 4) + { + for(uint16_t i = 0; i < to_recv_size_aligned; i += 4) + { + uint32_t tmp = (*USB->FIFO0D); + base[i] = tmp & 0x000000FF; + base[i + 1] = (tmp & 0x0000FF00) >> 8; + base[i + 2] = (tmp & 0x00FF0000) >> 16; + base[i + 3] = (tmp & 0xFF000000) >> 24; + } + } + + /* Do not read invalid bytes from RX FIFO. */ + if(to_recv_rem != 0) + { + uint32_t tmp = (*USB->FIFO0D); + uint8_t *last_32b_bound = base + to_recv_size_aligned; + + last_32b_bound[0] = tmp & 0x000000FF; + if(to_recv_rem > 1) + { + last_32b_bound[1] = (tmp & 0x0000FF00) >> 8; + } + if(to_recv_rem > 2) + { + last_32b_bound[2] = (tmp & 0x00FF0000) >> 16; + } + } + + xfer->queued_len += xfer_size; + + /* Per USB spec, a short OUT packet (including length 0) is always */ + /* indicative of the end of a transfer (at least for ctl, bulk, int). */ + xfer->short_packet = (xfer_size < xfer->max_size); +} + +static void transmit_packet(xfer_ctl_t *xfer, uint8_t fifo_num) +{ + uint16_t remaining; + if(fifo_num == 0) + { + remaining = (USB->DIEP0TSIZ & 0x7FFFFU) >> _USB_DIEP0TSIZ_XFERSIZE_SHIFT; + } + else + { + remaining = (USB->DIEP[fifo_num - 1].TSIZ & 0x7FFFFU) >> _USB_DIEP_TSIZ_XFERSIZE_SHIFT; + } + xfer->queued_len = xfer->total_len - remaining; + + uint16_t to_xfer_size = (remaining > xfer->max_size) ? xfer->max_size : remaining; + uint8_t to_xfer_rem = to_xfer_size % 4; + uint16_t to_xfer_size_aligned = to_xfer_size - to_xfer_rem; + + /* Buffer might not be aligned to 32b, so we need to force alignment by copying to a temp var. */ + uint8_t *base = (xfer->buffer + xfer->queued_len); + + /* This for loop always runs at least once- skip if less than 4 bytes to send off. */ + if(to_xfer_size >= 4) + { + for(uint16_t i = 0; i < to_xfer_size_aligned; i += 4) + { + uint32_t tmp = base[i] | (base[i + 1] << 8) | (base[i + 2] << 16) | (base[i + 3] << 24); + *tx_fifo[fifo_num] = tmp; + } + } + + /* Do not read beyond end of buffer if not divisible by 4. */ + if(to_xfer_rem != 0) + { + uint32_t tmp = 0; + uint8_t *last_32b_bound = base + to_xfer_size_aligned; + + tmp |= last_32b_bound[0]; + if(to_xfer_rem > 1) + { + tmp |= (last_32b_bound[1] << 8); + } + if(to_xfer_rem > 2) + { + tmp |= (last_32b_bound[2] << 16); + } + + *tx_fifo[fifo_num] = tmp; + } +} + +static void read_rx_fifo(void) +{ + /* + * Pop control word off FIFO (completed xfers will have 2 control words, + * we only pop one ctl word each interrupt). + */ + uint32_t const ctl_word = USB->GRXSTSP; + uint8_t const pktsts = (ctl_word & _USB_GRXSTSP_PKTSTS_MASK) >> _USB_GRXSTSP_PKTSTS_SHIFT; + uint8_t const epnum = (ctl_word & _USB_GRXSTSP_CHNUM_MASK ) >> _USB_GRXSTSP_CHNUM_SHIFT; + uint16_t const bcnt = (ctl_word & _USB_GRXSTSP_BCNT_MASK ) >> _USB_GRXSTSP_BCNT_SHIFT; + + switch(pktsts) + { + case 0x01: /* Global OUT NAK (Interrupt) */ + break; + + case 0x02: + { + /* Out packet recvd */ + xfer_ctl_t *xfer = XFER_CTL_BASE(epnum, TUSB_DIR_OUT); + receive_packet(xfer, bcnt); + } + break; + + case 0x03: + /* Out packet done (Interrupt) */ + break; + + case 0x04: + /* Step 2: Setup transaction completed (Interrupt) */ + /* After this event, OEPINT interrupt will occur with SETUP bit set */ + if(epnum == 0) + { + USB->DOEP0TSIZ |= (1 << _USB_DOEP0TSIZ_SUPCNT_SHIFT); + } + + break; + + case 0x06: + { + /* Step1: Setup data packet received */ + + /* + * We can receive up to three setup packets in succession, but + * only the last one is valid. Therefore we just overwrite it + */ + _setup_packet[0] = (*USB->FIFO0D); + _setup_packet[1] = (*USB->FIFO0D); + } + break; + + default: + /* Invalid, breakpoint. */ + TU_BREAKPOINT(); + break; + } +} + +static void handle_epout_ints(void) +{ + // GINTSTS will be cleared with DAINT == 0 + // DAINT for a given EP clears when DOEPINTx is cleared. + // DOEPINT will be cleared when DAINT's out bits are cleared. + + for(uint8_t n = 0; n < EP_COUNT; n++) + { + xfer_ctl_t *xfer = XFER_CTL_BASE(n, TUSB_DIR_OUT); + + if(n == 0) + { + if(USB->DAINT & (1 << (_USB_DAINT_OUTEPINT0_SHIFT + n))) + { + // SETUP packet Setup Phase done. + if((USB->DOEP0INT & USB_DOEP0INT_SETUP)) + { + USB->DOEP0INT = USB_DOEP0INT_STUPPKTRCVD | USB_DOEP0INT_SETUP; // clear + dcd_event_setup_received(0, (uint8_t *)&_setup_packet[0], true); + } + + // OUT XFER complete (single packet).q + if(USB->DOEP0INT & USB_DOEP0INT_XFERCOMPL) + { + USB->DOEP0INT = USB_DOEP0INT_XFERCOMPL; + + // Transfer complete if short packet or total len is transferred + if(xfer->short_packet || (xfer->queued_len == xfer->total_len)) + { + xfer->short_packet = false; + dcd_event_xfer_complete(0, n, xfer->queued_len, XFER_RESULT_SUCCESS, true); + } + else + { + // Schedule another packet to be received. + USB->DOEP0TSIZ |= (1 << _USB_DOEP0TSIZ_PKTCNT_SHIFT) | ((xfer->max_size & _USB_DOEP0TSIZ_XFERSIZE_MASK) << _USB_DOEP0TSIZ_XFERSIZE_SHIFT); + USB->DOEP0CTL |= USB_DOEP0CTL_EPENA | USB_DOEP0CTL_CNAK; + } + } + } + } + else + { + if(USB->DAINT & (1 << (_USB_DAINT_OUTEPINT0_SHIFT + n))) + { + // SETUP packet Setup Phase done. + if((USB->DOEP[n - 1].INT & USB_DOEP_INT_SETUP)) + { + USB->DOEP[n - 1].INT = USB_DOEP_INT_STUPPKTRCVD | USB_DOEP_INT_SETUP; // clear + dcd_event_setup_received(0, (uint8_t *)&_setup_packet[0], true); + } + + // OUT XFER complete (single packet).q + if(USB->DOEP[n - 1].INT & USB_DOEP_INT_XFERCOMPL) + { + USB->DOEP[n - 1].INT = USB_DOEP_INT_XFERCOMPL; + + // Transfer complete if short packet or total len is transferred + if(xfer->short_packet || (xfer->queued_len == xfer->total_len)) + { + xfer->short_packet = false; + dcd_event_xfer_complete(0, n, xfer->queued_len, XFER_RESULT_SUCCESS, true); + } + else + { + // Schedule another packet to be received. + USB->DOEP[n - 1].TSIZ |= (1 << _USB_DOEP_TSIZ_PKTCNT_SHIFT) | ((xfer->max_size & _USB_DOEP_TSIZ_XFERSIZE_MASK) << _USB_DOEP_TSIZ_XFERSIZE_SHIFT); + USB->DOEP[n - 1].CTL |= USB_DOEP_CTL_EPENA | USB_DOEP_CTL_CNAK; + } + } + } + } + } +} + +static void handle_epin_ints(void) +{ + + for(uint32_t n = 0; n < EP_COUNT; n++) + { + xfer_ctl_t *xfer = &xfer_status[n][TUSB_DIR_IN]; + + if(n == 0) + { + if(USB->DAINT & (1 << n)) + { + /* IN XFER complete (entire xfer). */ + if(USB->DIEP0INT & USB_DIEP0INT_XFERCOMPL) + { + USB->DIEP0INT = USB_DIEP0INT_XFERCOMPL; + dcd_event_xfer_complete(0, n | TUSB_DIR_IN_MASK, xfer->total_len, XFER_RESULT_SUCCESS, true); + } + + /* XFER FIFO empty */ + if(USB->DIEP0INT & USB_DIEP0INT_TXFEMP) + { + USB->DIEP0INT = USB_DIEP0INT_TXFEMP; + transmit_packet(xfer, n); + + /* Turn off TXFE if all bytes are written. */ + if(xfer->queued_len == xfer->total_len) + { + USB->DIEPEMPMSK &= ~(1 << n); + } + } + + /* XFER Timeout */ + if(USB->DIEP0INT & USB_DIEP0INT_TIMEOUT) + { + /* Clear interrupt or enpoint will hang. */ + USB->DIEP0INT = USB_DIEP0INT_TIMEOUT; + } + } + } + else + { + if(USB->DAINT & (1 << n)) + { + /* IN XFER complete (entire xfer). */ + if(USB->DIEP[n - 1].INT & USB_DIEP_INT_XFERCOMPL) + { + USB->DIEP[n - 1].INT = USB_DIEP_INT_XFERCOMPL; + dcd_event_xfer_complete(0, n | TUSB_DIR_IN_MASK, xfer->total_len, XFER_RESULT_SUCCESS, true); + } + + /* XFER FIFO empty */ + if(USB->DIEP[n - 1].INT & USB_DIEP_INT_TXFEMP) + { + USB->DIEP[n - 1].INT = USB_DIEP_INT_TXFEMP; + transmit_packet(xfer, n); + + /* Turn off TXFE if all bytes are written. */ + if(xfer->queued_len == xfer->total_len) + { + USB->DIEPEMPMSK &= ~(1 << n); + } + } + + /* XFER Timeout */ + if(USB->DIEP[n - 1].INT & USB_DIEP_INT_TIMEOUT) + { + /* Clear interrupt or enpoint will hang. */ + USB->DIEP[n - 1].INT = USB_DIEP_INT_TIMEOUT; + } + } + } + } +} + +void dcd_int_handler(uint8_t rhport) +{ + (void) rhport; + + const uint32_t int_status = USB->GINTSTS; + + /* USB Reset */ + if(int_status & USB_GINTSTS_USBRST) + { + /* start of reset */ + USB->GINTSTS = USB_GINTSTS_USBRST; + /* FIFOs will be reassigned when the endpoints are reopen */ + _allocated_fifos = 1; + bus_reset(); + } + + /* Reset detected Interrupt */ + if(int_status & USB_GINTSTS_RESETDET) + { + USB->GINTSTS = USB_GINTSTS_RESETDET; + bus_reset(); + } + + /* Enumeration Done */ + if(int_status & USB_GINTSTS_ENUMDONE) + { + /* This interrupt is considered the end of reset. */ + USB->GINTSTS = USB_GINTSTS_ENUMDONE; + enum_done_processing(); + dcd_event_bus_signal(0, DCD_EVENT_BUS_RESET, true); + } + + /* OTG Interrupt */ + if(int_status & USB_GINTSTS_OTGINT) + { + /* OTG INT bit is read-only */ + + uint32_t const otg_int = USB->GOTGINT; + + if(otg_int & USB_GOTGINT_SESENDDET) + { + dcd_event_bus_signal(0, DCD_EVENT_UNPLUGGED, true); + } + + USB->GOTGINT = otg_int; + } + + #if USE_SOF + if(int_status & USB_GINTSTS_SOF) + { + USB->GINTSTS = USB_GINTSTS_SOF; + dcd_event_bus_signal(0, DCD_EVENT_SOF, true); + } + #endif + + /* RxFIFO Non-Empty */ + if(int_status & USB_GINTSTS_RXFLVL) + { + /* RXFLVL bit is read-only */ + + /* Mask out RXFLVL while reading data from FIFO */ + USB->GINTMSK &= ~USB_GINTMSK_RXFLVLMSK; + read_rx_fifo(); + USB->GINTMSK |= USB_GINTMSK_RXFLVLMSK; + } + + /* OUT Endpoints Interrupt */ + if(int_status & USB_GINTMSK_OEPINTMSK) + { + /* OEPINT is read-only */ + handle_epout_ints(); + } + + /* IN Endpoints Interrupt */ + if(int_status & USB_GINTMSK_IEPINTMSK) + { + /* IEPINT bit read-only */ + handle_epin_ints(); + } + + /* unhandled */ + USB->GINTSTS |= USB_GINTSTS_CURMOD | + USB_GINTSTS_MODEMIS | + USB_GINTSTS_OTGINT | + USB_GINTSTS_NPTXFEMP | + USB_GINTSTS_GINNAKEFF | + USB_GINTSTS_GOUTNAKEFF | + USB_GINTSTS_ERLYSUSP | + USB_GINTSTS_USBSUSP | + USB_GINTSTS_ISOOUTDROP | + USB_GINTSTS_EOPF | + USB_GINTSTS_EPMIS | + USB_GINTSTS_INCOMPISOIN | + USB_GINTSTS_INCOMPLP | + USB_GINTSTS_FETSUSP | + USB_GINTSTS_PTXFEMP; +} + +#endif -- cgit v1.3.1 From 13735eb21de8d21a88871e69859f69db02af93c6 Mon Sep 17 00:00:00 2001 From: kkitayam <45088311+kkitayam@users.noreply.github.com> Date: Sun, 7 Mar 2021 14:53:21 +0900 Subject: added dcd for Renesas USBa --- src/portable/renesas/usba/dcd_usba.c | 755 +++++++++++++++++++++++++++++++++++ 1 file changed, 755 insertions(+) create mode 100644 src/portable/renesas/usba/dcd_usba.c (limited to 'src') diff --git a/src/portable/renesas/usba/dcd_usba.c b/src/portable/renesas/usba/dcd_usba.c new file mode 100644 index 000000000..b0fa1749d --- /dev/null +++ b/src/portable/renesas/usba/dcd_usba.c @@ -0,0 +1,755 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2020 Koji Kitayama + * + * 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 TUSB_OPT_DEVICE_ENABLED && ( CFG_TUSB_MCU == OPT_MCU_RX63X ) + +#include "device/dcd.h" +#include "iodefine.h" + +//--------------------------------------------------------------------+ +// MACRO TYPEDEF CONSTANT ENUM DECLARATION +//--------------------------------------------------------------------+ +#define SYSTEM_PRCR_PRC1 (1<<1) +#define SYSTEM_PRCR_PRKEY (0xA5u<<8) + +#define USB_FIFOSEL_TX ((uint16_t)(1u<<5)) +#define USB_FIFOSEL_MBW_8 ((uint16_t)(0u<<10)) +#define USB_FIFOSEL_MBW_16 ((uint16_t)(1u<<10)) +#define USB_IS0_CTSQ ((uint16_t)(7u)) +#define USB_IS0_DVSQ ((uint16_t)(7u<<4)) +#define USB_IS0_VALID ((uint16_t)(1u<<3)) +#define USB_IS0_BRDY ((uint16_t)(1u<<8)) +#define USB_IS0_NRDY ((uint16_t)(1u<<9)) +#define USB_IS0_BEMP ((uint16_t)(1u<<10)) +#define USB_IS0_CTRT ((uint16_t)(1u<<11)) +#define USB_IS0_DVST ((uint16_t)(1u<<12)) +#define USB_IS0_SOFR ((uint16_t)(1u<<13)) +#define USB_IS0_RESM ((uint16_t)(1u<<14)) +#define USB_IS0_VBINT ((uint16_t)(1u<<15)) +#define USB_IS1_SACK ((uint16_t)(1u<<4)) +#define USB_IS1_SIGN ((uint16_t)(1u<<5)) +#define USB_IS1_EOFERR ((uint16_t)(1u<<6)) +#define USB_IS1_ATTCH ((uint16_t)(1u<<11)) +#define USB_IS1_DTCH ((uint16_t)(1u<<12)) +#define USB_IS1_BCHG ((uint16_t)(1u<<14)) +#define USB_IS1_OVRCR ((uint16_t)(1u<<15)) + +#define USB_IS0_CTSQ_MSK (7u) +#define USB_IS0_CTSQ_SETUP (1u) +#define USB_IS0_DVSQ_DEF (1u<<4) +#define USB_IS0_DVSQ_ADDR (2u<<4) +#define USB_IS0_DVSQ_SUSP (4u<<4) + +#define USB_PIPECTR_PID_NAK (0u) +#define USB_PIPECTR_PID_BUF (1u) +#define USB_PIPECTR_PID_STALL (2u) +#define USB_PIPECTR_CCPL (1u<<2) +#define USB_PIPECTR_SQMON (1u<<6) +#define USB_PIPECTR_SQCLR (1u<<8) +#define USB_PIPECTR_ACLRM (1u<<9) +#define USB_PIPECTR_BSTS (1u<<15) + +#define USB_FIFOCTR_DTLN (0x1FF) +#define USB_FIFOCTR_FRDY (1u<<13) +#define USB_FIFOCTR_BCLR (1u<<14) +#define USB_FIFOCTR_BVAL (1u<<15) + +#define USB_PIPECFG_SHTNAK (1u<<7) +#define USB_PIPECFG_DBLB (1u<<9) +#define USB_PIPECFG_BULK (1u<<14) +#define USB_PIPECFG_ISO (3u<<14) +#define USB_PIPECFG_INT (2u<<14) + +#define FIFO_REQ_CLR (1u) +#define FIFO_COMPLETE (1u<<1) + +typedef struct { + union { + struct { + uint16_t : 8; + uint16_t TRCLR: 1; + uint16_t TRENB: 1; + uint16_t : 0; + }; + uint16_t TRE; + }; + uint16_t TRN; +} reg_pipetre_t; + +typedef union { + struct { + volatile uint16_t u8: 8; + volatile uint16_t : 0; + }; + volatile uint16_t u16; +} hw_fifo_t; + +typedef struct TU_ATTR_PACKED +{ + uintptr_t addr; + uint16_t length; + uint16_t remaining; + struct { + uint32_t ep : 8; + uint32_t data: 1; + uint32_t : 0; + }; +} pipe_state_t; + +typedef struct +{ + pipe_state_t pipe[9]; + uint8_t ep[2][16]; /* index for pipe number */ +} dcd_data_t; + +//--------------------------------------------------------------------+ +// INTERNAL OBJECT & FUNCTION DECLARATION +//--------------------------------------------------------------------+ +CFG_TUSB_MEM_SECTION static dcd_data_t _dcd; + +static uint32_t disable_interrupt(void) +{ + uint32_t pswi; + pswi = __builtin_rx_mvfc(0) & 0x010000; + __builtin_rx_clrpsw('I'); + return pswi; +} + +static void enable_interrupt(uint32_t pswi) +{ + __builtin_rx_mvtc(0, __builtin_rx_mvfc(0) | pswi); +} + +static unsigned find_pipe(unsigned xfer) +{ + switch (xfer) { + case TUSB_XFER_ISOCHRONOUS: + for (int i = 1; i <= 2; ++i) { + if (0 == _dcd.pipe[i].ep) return i; + } + break; + case TUSB_XFER_BULK: + for (int i = 3; i <= 5; ++i) { + if (0 == _dcd.pipe[i].ep) return i; + } + for (int i = 1; i <= 1; ++i) { + if (0 == _dcd.pipe[i].ep) return i; + } + break; + case TUSB_XFER_INTERRUPT: + for (int i = 6; i <= 9; ++i) { + if (0 == _dcd.pipe[i].ep) return i; + } + break; + default: + /* No support for control transfer */ + break; + } + return 0; +} + +static volatile uint16_t* get_pipectr(unsigned num) +{ + volatile uint16_t *ctr = NULL; + if (num) { + ctr = (volatile uint16_t*)&USB0.PIPE1CTR.WORD; + ctr += num - 1; + } else { + ctr = (volatile uint16_t*)&USB0.DCPCTR.WORD; + } + return ctr; +} + +static volatile reg_pipetre_t* get_pipetre(unsigned num) +{ + volatile reg_pipetre_t* tre = NULL; + if ((1 <= num) && (num <= 5)) { + tre = (volatile reg_pipetre_t*)&USB0.PIPE1TRE.WORD; + tre += num - 1; + } + return tre; +} + +static volatile uint16_t* ep_addr_to_pipectr(uint8_t rhport, unsigned ep_addr) +{ + (void)rhport; + volatile uint16_t *ctr = NULL; + const unsigned epn = ep_addr & 0xFu; + if (epn) { + const unsigned dir = (ep_addr & TUSB_DIR_IN_MASK) ? TUSB_DIR_IN : TUSB_DIR_OUT; + const unsigned num = _dcd.ep[dir][epn]; + if (num) { + ctr = (volatile uint16_t*)&USB0.PIPE1CTR.WORD; + ctr += num - 1; + } + } else { + ctr = (volatile uint16_t*)&USB0.DCPCTR.WORD; + } + return ctr; +} + + +/* 1 less than 64 bytes were written + * 2 no bytes were written + * 0 64 bytes were written */ +static int write_fifo(volatile void *fifo, pipe_state_t* pipe, unsigned mps) +{ + unsigned rem = pipe->remaining; + if (!rem) return 2; + unsigned len = (rem < mps) ? rem: mps; + + hw_fifo_t *reg = (hw_fifo_t*)fifo; + uintptr_t addr = pipe->addr + pipe->length - rem; + if (addr & 1u) { + /* addr is not 2-byte aligned */ + reg->u8 = *(const uint8_t *)addr; + ++addr; + --len; + } + while (len >= 2) { + reg->u16 = *(const uint16_t *)addr; + addr += 2; + len -= 2; + } + if (len) { + reg->u8 = *(const uint8_t *)addr; + ++addr; + } + if (rem < mps) return 1; + return 0; +} + +/* 1 if the number of bytes read is less than 64 bytes + * 0 otherwise */ +static int read_fifo(volatile void *fifo, pipe_state_t* pipe, unsigned mps, size_t len) +{ + unsigned rem = pipe->remaining; + if (!rem) return 2; + if (rem < len) len = rem; + pipe->remaining = rem - len; + + hw_fifo_t *reg = (hw_fifo_t*)fifo; + uintptr_t addr = pipe->addr; + while (len--) { + *(uint8_t *)addr = reg->u8; + ++addr; + } + pipe->addr = addr; + if (rem < mps) return 1; + return 0; +} + +static void process_setup_packet(uint8_t rhport) +{ + uint16_t setup_packet[4]; + if (0 == (USB0.INTSTS0.WORD & USB_IS0_VALID)) return; + USB0.CFIFOCTR.WORD = USB_FIFOCTR_BCLR; + setup_packet[0] = USB0.USBREQ.WORD; + setup_packet[1] = USB0.USBVAL; + setup_packet[2] = USB0.USBINDX; + setup_packet[3] = USB0.USBLENG; + USB0.INTSTS0.WORD = ~USB_IS0_VALID; + dcd_event_setup_received(rhport, (const uint8_t*)&setup_packet[0], true); + // TU_LOG1("S\r\n"); +} + +static void process_status_completion(uint8_t rhport) +{ + uint8_t ep_addr; + /* Check the data stage direction */ + if (USB0.CFIFOSEL.WORD & USB_FIFOSEL_TX) { + /* IN transfer. */ + ep_addr = tu_edpt_addr(0, TUSB_DIR_IN); + } else { + /* OUT transfer. */ + ep_addr = tu_edpt_addr(0, TUSB_DIR_OUT); + } + dcd_event_xfer_complete(rhport, ep_addr, 0, XFER_RESULT_SUCCESS, true); + // TU_LOG1("C\r\n"); +} + +static bool process_edpt0_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, uint16_t total_bytes) +{ + (void)rhport; + + pipe_state_t *pipe = &_dcd.pipe[0]; + /* set fifo direction */ + if (ep_addr) { /* IN */ + USB0.CFIFOSEL.WORD = USB_FIFOSEL_TX | USB_FIFOSEL_MBW_16; + while (!(USB0.CFIFOSEL.WORD & USB_FIFOSEL_TX)) ; + } else { /* OUT */ + USB0.CFIFOSEL.WORD = USB_FIFOSEL_MBW_8; + while (USB0.CFIFOSEL.WORD & USB_FIFOSEL_TX) ; + } + if (total_bytes) { + pipe->addr = (uintptr_t)buffer; + pipe->length = total_bytes; + pipe->remaining = total_bytes; + pipe->data = USB0.DCPCTR.BIT.SQMON; + if (ep_addr) { /* IN */ + TU_ASSERT(USB0.DCPCTR.BIT.BSTS && (USB0.USBREQ.WORD & 0x80)); + if (write_fifo(&USB0.CFIFO.WORD, pipe, 64)) { + USB0.CFIFOCTR.WORD = USB_FIFOCTR_BVAL; + } + } + USB0.DCPCTR.WORD = USB_PIPECTR_PID_BUF; + // TU_LOG1("X %x %d\r\n", ep_addr, total_bytes); + } else { + /* ZLP */ + pipe->addr = 0; + pipe->length = 0; + pipe->remaining = 0; + pipe->data = USB0.DCPCTR.BIT.SQMON; + USB0.DCPCTR.WORD = USB_PIPECTR_CCPL | USB_PIPECTR_PID_BUF; + // TU_LOG1("Z %x\r\n", USB0.DCPCTR.WORD); + } + return true; +} + +static void process_edpt0_bemp(uint8_t rhport) +{ + pipe_state_t *pipe = &_dcd.pipe[0]; + unsigned data = pipe->data; + if (USB0.DCPCTR.BIT.SQMON == data) { + TU_LOG1("W %x\r\n", USB0.DCPCTR.WORD); + /* retry transfer */ + int r = write_fifo(&USB0.CFIFO.WORD, &_dcd.pipe[0], 64); + if (r) USB0.CFIFOCTR.WORD = USB_FIFOCTR_BVAL; + return; + } + const unsigned rem = pipe->remaining; + if (rem > 64) { + pipe->remaining = rem - 64; + pipe->data = data ^ 1; + TU_LOG1("Y %d %x\r\n", rem - 64, USB0.DCPCTR.WORD); + int r = write_fifo(&USB0.CFIFO.WORD, &_dcd.pipe[0], 64); + if (r) USB0.CFIFOCTR.WORD = USB_FIFOCTR_BVAL; + return; + } + pipe->addr = 0; + pipe->remaining = 0; + dcd_event_xfer_complete(rhport, tu_edpt_addr(0, TUSB_DIR_IN), + pipe->length, XFER_RESULT_SUCCESS, true); + // TU_LOG1("c\r\n"); +} + +static void process_edpt0_brdy(uint8_t rhport) +{ + size_t len = USB0.CFIFOCTR.BIT.DTLN; + int cplt = read_fifo(&USB0.CFIFO.WORD, &_dcd.pipe[0], 64, len); + if (cplt || (len < 64)) { + if (2 != cplt) { + USB0.CFIFOCTR.WORD = USB_FIFOCTR_BCLR; + } + dcd_event_xfer_complete(rhport, tu_edpt_addr(0, TUSB_DIR_OUT), + _dcd.pipe[0].length - _dcd.pipe[0].remaining, + XFER_RESULT_SUCCESS, true); + // TU_LOG1("c\r\n"); + } +} + +static bool process_pipe_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, uint16_t total_bytes) +{ + (void)rhport; + + const unsigned epn = ep_addr & 0xFu; + const unsigned dir = (ep_addr & TUSB_DIR_IN_MASK) ? TUSB_DIR_IN : TUSB_DIR_OUT; + const unsigned num = _dcd.ep[dir][epn]; + + TU_ASSERT(num); + + pipe_state_t *pipe = &_dcd.pipe[num]; + pipe->addr = (uintptr_t)buffer; + pipe->length = total_bytes; + pipe->remaining = total_bytes; + + USB0.PIPESEL.WORD = num; + const unsigned mps = USB0.PIPEMAXP.WORD; + if (dir) { /* IN */ + USB0.D0FIFOSEL.WORD = num | USB_FIFOSEL_MBW_16; + while (!(USB0.D0FIFOSEL.BIT.CURPIPE != num)) ; + if (write_fifo(&USB0.D0FIFO.WORD, pipe, mps)) { + USB0.D0FIFOCTR.WORD = USB_FIFOCTR_BVAL; + } + USB0.D0FIFOSEL.WORD = 0; + } else { + volatile reg_pipetre_t *pt = get_pipetre(num); + if (pt) { + volatile uint16_t *ctr = get_pipectr(num); + if (*ctr & 0x3) *ctr = USB_PIPECTR_PID_NAK; + pt->TRE = 1u << 8; + pt->TRN = (total_bytes + mps - 1) / mps; + pt->TRENB = 1; + *ctr = USB_PIPECTR_PID_BUF; + } + } + TU_LOG1("X %x %d\r\n", ep_addr, total_bytes); + return true; +} + +static void process_pipe_bemp(uint8_t rhport, unsigned num) +{ + pipe_state_t *pipe = &_dcd.pipe[num]; + const unsigned rem = pipe->remaining; + if (rem > 64) { + pipe->remaining = rem - 64; + TU_LOG1("Y %d\r\n", rem - 64); + USB0.PIPESEL.WORD = num; + const unsigned mps = USB0.PIPEMAXP.WORD; + USB0.D0FIFOSEL.WORD = num | USB_FIFOSEL_MBW_16; + while (!(USB0.D0FIFOSEL.BIT.CURPIPE != num)) ; + int r = write_fifo(&USB0.D0FIFO.WORD, pipe, mps); + if (r) USB0.D0FIFOCTR.WORD = USB_FIFOCTR_BVAL; + USB0.D0FIFOSEL.WORD = 0; + return; + } + pipe->addr = 0; + pipe->remaining = 0; + dcd_event_xfer_complete(rhport, pipe->ep, pipe->length, + XFER_RESULT_SUCCESS, true); + // TU_LOG1("cE\r\n"); +} + +static void process_pipe_brdy(uint8_t rhport, unsigned num) +{ + pipe_state_t *pipe = &_dcd.pipe[num]; + USB0.PIPESEL.WORD = num; + const unsigned mps = USB0.PIPEMAXP.WORD; + USB0.D0FIFOSEL.WORD = num | USB_FIFOSEL_MBW_8; + while (!(USB0.D0FIFOSEL.BIT.CURPIPE != num)) ; + unsigned ctr; + do { + ctr = USB0.D0FIFOCTR.WORD; + } while (!(ctr & USB_FIFOCTR_FRDY)); + const unsigned len = ctr & USB_FIFOCTR_DTLN; + TU_LOG1(">> %d %x %x\r\n", num, USB0.D0FIFOSEL.WORD, ctr); + int cplt = read_fifo(&USB0.D0FIFO.WORD, pipe, mps, len); + if (cplt || (len < mps)) { + if (2 != cplt) { + USB0.D0FIFO.WORD = USB_FIFOCTR_BCLR; + } + USB0.D0FIFOSEL.WORD = 0; + dcd_event_xfer_complete(rhport, pipe->ep, + pipe->length - pipe->remaining, + XFER_RESULT_SUCCESS, true); + TU_LOG1("c\r\n"); + } else { + USB0.D0FIFOSEL.WORD = 0; + } +} + +static void process_bus_reset(uint8_t rhport) +{ + USB0.BEMPENB.WORD = 1; + USB0.BRDYENB.WORD = 1; + USB0.CFIFOCTR.WORD = USB_FIFOCTR_BCLR; + USB0.D0FIFOSEL.WORD = 0; + USB0.D1FIFOSEL.WORD = 0; + volatile uint16_t *ctr = (volatile uint16_t*)((uintptr_t)(&USB0.PIPE1CTR.WORD)); + volatile uint16_t *tre = (volatile uint16_t*)((uintptr_t)(&USB0.PIPE1TRE.WORD)); + for (int i = 1; i <= 5; ++i) { + USB0.PIPESEL.WORD = i; + USB0.PIPECFG.WORD = 0; + *ctr = USB_PIPECTR_ACLRM; + *ctr = 0; + ++ctr; + *tre = (1u<<8); + tre += 2; + } + for (int i = 6; i <= 9; ++i) { + USB0.PIPESEL.WORD = i; + USB0.PIPECFG.WORD = 0; + *ctr = USB_PIPECTR_ACLRM; + *ctr = 0; + ++ctr; + } + tu_varclr(&_dcd); + dcd_event_bus_reset(rhport, TUSB_SPEED_FULL, true); + TU_LOG1("R\r\n"); +} + +static void process_set_address(uint8_t rhport) +{ + const uint32_t addr = USB0.USBADDR.BIT.USBADDR; + if (!addr) return; + const tusb_control_request_t setup_packet = { + .bmRequestType = 0, + .bRequest = 5, + .wValue = addr, + .wIndex = 0, + .wLength = 0, + }; + dcd_event_setup_received(rhport, (const uint8_t*)&setup_packet, true); +} + +/*------------------------------------------------------------------*/ +/* Device API + *------------------------------------------------------------------*/ +void dcd_init(uint8_t rhport) +{ + (void)rhport; + /* Enable USB0 */ + uint32_t pswi = disable_interrupt(); + SYSTEM.PRCR.WORD = SYSTEM_PRCR_PRKEY | SYSTEM_PRCR_PRC1; + MSTP(USB0) = 0; + SYSTEM.PRCR.WORD = SYSTEM_PRCR_PRKEY; + enable_interrupt(pswi); + USB0.SYSCFG.BIT.SCKE = 1; + while (!USB0.SYSCFG.BIT.SCKE) ; + USB0.SYSCFG.BIT.DRPD = 0; + USB0.SYSCFG.BIT.DCFM = 0; + USB0.SYSCFG.BIT.USBE = 1; + + IR(USB0, USBI0) = 0; + + /* Setup default control pipe */ + USB0.DCPMAXP.BIT.MXPS = 64; + USB0.INTENB0.WORD = USB_IS0_VBINT | USB_IS0_BRDY | USB_IS0_BEMP | USB_IS0_DVST | USB_IS0_CTRT; + USB0.BEMPENB.WORD = 1; + USB0.BRDYENB.WORD = 1; + + TU_LOG1("INIT\r\n"); + if (USB0.INTSTS0.BIT.VBSTS) { + dcd_connect(rhport); + } +} + +void dcd_int_enable(uint8_t rhport) +{ + (void)rhport; + IEN(USB0, USBI0) = 1; +} + +void dcd_int_disable(uint8_t rhport) +{ + (void)rhport; + IEN(USB0, USBI0) = 0; +} + +void dcd_set_address(uint8_t rhport, uint8_t dev_addr) +{ + (void)rhport; + (void)dev_addr; +} + +void dcd_remote_wakeup(uint8_t rhport) +{ + (void)rhport; + /* TODO */ +} + +void dcd_connect(uint8_t rhport) +{ + (void)rhport; + USB0.SYSCFG.BIT.DPRPU = 1; +} + +void dcd_disconnect(uint8_t rhport) +{ + (void)rhport; + USB0.SYSCFG.BIT.DPRPU = 0; +} + +//--------------------------------------------------------------------+ +// Endpoint API +//--------------------------------------------------------------------+ +bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * ep_desc) +{ + (void)rhport; + + const unsigned ep_addr = ep_desc->bEndpointAddress; + const unsigned epn = ep_addr & 0xFu; + const unsigned dir = (ep_addr & TUSB_DIR_IN_MASK) ? TUSB_DIR_IN : TUSB_DIR_OUT; + const unsigned xfer = ep_desc->bmAttributes.xfer; + + const unsigned mps = ep_desc->wMaxPacketSize.size; + if (xfer == TUSB_XFER_ISOCHRONOUS && mps > 256) { + /* USBB support up to 256 bytes */ + return false; + } + + const unsigned num = find_pipe(xfer); + if (!num) return false; + _dcd.pipe[num].ep = ep_addr; + _dcd.ep[dir][epn] = num; + + /* setup pipe */ + USB0.PIPESEL.WORD = num; + USB0.PIPEMAXP.WORD = mps; + volatile uint16_t *ctr = get_pipectr(num); + *ctr = USB_PIPECTR_ACLRM; + *ctr = 0; + unsigned cfg = (dir << 4) | epn; + if (xfer == TUSB_XFER_BULK) { + cfg |= USB_PIPECFG_BULK | USB_PIPECFG_SHTNAK | USB_PIPECFG_DBLB; + } else if (xfer == TUSB_XFER_INTERRUPT) { + cfg |= USB_PIPECFG_INT; + } else { + cfg |= USB_PIPECFG_ISO | USB_PIPECFG_DBLB; + } + USB0.PIPECFG.WORD = cfg; + if (dir) { + USB0.BEMPENB.WORD |= 1u << num; + *ctr = USB_PIPECTR_PID_BUF; + } else { + USB0.BRDYENB.WORD |= 1u << num; + if (xfer != TUSB_XFER_BULK) { + *ctr = USB_PIPECTR_PID_BUF; + } + } + TU_LOG1("O %d %x %x\r\n", USB0.PIPESEL.WORD, USB0.PIPECFG.WORD, USB0.PIPEMAXP.WORD); + + return true; +} + +void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr) +{ + (void)rhport; + const unsigned epn = ep_addr & 0xFu; + const unsigned dir = (ep_addr & TUSB_DIR_IN_MASK) ? TUSB_DIR_IN : TUSB_DIR_OUT; + const unsigned num = _dcd.ep[dir][epn]; + + USB0.BEMPENB.WORD &= ~(1u << num); + USB0.BRDYENB.WORD &= ~(1u << num); + volatile uint16_t *ctr = get_pipectr(num); + *ctr = 0; + USB0.PIPESEL.WORD = num; + USB0.PIPECFG.WORD = 0; + _dcd.pipe[num].ep = 0; + _dcd.ep[dir][epn] = 0; +} + +bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, uint16_t total_bytes) +{ + bool r; + const unsigned epn = ep_addr & 0xFu; + dcd_int_disable(rhport); + if (0 == epn) { + r = process_edpt0_xfer(rhport, ep_addr, buffer, total_bytes); + } else { + r = process_pipe_xfer(rhport, ep_addr, buffer, total_bytes); + } + dcd_int_enable(rhport); + return r; +} + +void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr) +{ + volatile uint16_t *ctr = ep_addr_to_pipectr(rhport, ep_addr); + if (!ctr) return; + dcd_int_disable(rhport); + const uint32_t pid = *ctr & 0x3; + *ctr = pid | USB_PIPECTR_PID_STALL; + *ctr = USB_PIPECTR_PID_STALL; + dcd_int_enable(rhport); +} + +void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr) +{ + volatile uint16_t *ctr = ep_addr_to_pipectr(rhport, ep_addr); + if (!ctr) return; + dcd_int_disable(rhport); + *ctr = USB_PIPECTR_SQCLR; + + if (ep_addr & TUSB_DIR_IN_MASK) { + *ctr = USB_PIPECTR_PID_BUF; + } else { + /* TODO */ + } + dcd_int_enable(rhport); +} + +//--------------------------------------------------------------------+ +// ISR +//--------------------------------------------------------------------+ +void dcd_int_handler(uint8_t rhport) +{ + (void)rhport; + + unsigned is0 = USB0.INTSTS0.WORD; + /* clear bits except VALID */ + USB0.INTSTS0.WORD = USB_IS0_VALID; + if (is0 & USB_IS0_VBINT) { + if (USB0.INTSTS0.BIT.VBSTS) { + dcd_connect(rhport); + } else { + dcd_disconnect(rhport); + } + } + if (is0 & USB_IS0_DVST) { + switch (is0 & USB_IS0_DVSQ) { + case USB_IS0_DVSQ_DEF: + process_bus_reset(rhport); + break; + case USB_IS0_DVSQ_ADDR: + process_set_address(rhport); + break; + default: + break; + } + } + if (is0 & USB_IS0_CTRT) { + if (is0 & USB_IS0_CTSQ_SETUP) { + /* A setup packet has been received. */ + process_setup_packet(rhport); + } else if (0 == (is0 & USB_IS0_CTSQ_MSK)) { + /* A ZLP has been sent/received. */ + process_status_completion(rhport); + } + } + if (is0 & USB_IS0_BEMP) { + const unsigned m = USB0.BEMPENB.WORD; + unsigned s = USB0.BEMPSTS.WORD & m; + USB0.BEMPSTS.WORD = 0; + if (s & 1) { + process_edpt0_bemp(rhport); + s &= ~1; + } + while (s) { + const unsigned num = __builtin_ctz(s); + process_pipe_bemp(rhport, num); + s &= ~(1< Date: Wed, 24 Mar 2021 00:53:55 +0900 Subject: update for gr_citurs --- hw/bsp/gr_citrus/board.mk | 5 +- hw/bsp/gr_citrus/gr_citrus.c | 8 +- src/portable/renesas/usba/dcd_usba.c | 155 ++++++++++++++++++++++++++++------- src/tusb_option.h | 3 + 4 files changed, 134 insertions(+), 37 deletions(-) (limited to 'src') diff --git a/hw/bsp/gr_citrus/board.mk b/hw/bsp/gr_citrus/board.mk index 8675d8530..53f85aa74 100644 --- a/hw/bsp/gr_citrus/board.mk +++ b/hw/bsp/gr_citrus/board.mk @@ -28,6 +28,7 @@ MCU_DIR = hw/mcu/renesas/rx63n LD_FILE = hw/bsp/$(BOARD)/r5f5631fd.ld SRC_C += \ + src/portable/renesas/usba/dcd_usba.c \ $(MCU_DIR)/vects.c INC += \ @@ -36,10 +37,6 @@ INC += \ SRC_S += $(MCU_DIR)/start.S -# For TinyUSB port source -VENDOR = renesas -CHIP_FAMILY = usba - # For freeRTOS port source FREERTOS_PORT = RX600 diff --git a/hw/bsp/gr_citrus/gr_citrus.c b/hw/bsp/gr_citrus/gr_citrus.c index 3fa568cc0..f8cf8b18d 100644 --- a/hw/bsp/gr_citrus/gr_citrus.c +++ b/hw/bsp/gr_citrus/gr_citrus.c @@ -29,7 +29,7 @@ #include "interrupt_handlers.h" #define IRQ_PRIORITY_CMT0 5 -#define IRQ_PRIORITY_USBI0 5 +#define IRQ_PRIORITY_USBI0 6 #define IRQ_PRIORITY_SCI0 5 #define SYSTEM_PRCR_PRC1 (1<<1) @@ -146,13 +146,17 @@ void board_init(void) MPC.P20PFS.BYTE = 0b01010; PORT2.PMR.BIT.B1 = 1U; MPC.P21PFS.BYTE = 0b01010; - /* USB VBUS -> P16, RXD0 => P21, TXD0 => P20 */ + /* USB VBUS -> P16 DPUPE -> P14 */ + PORT1.PMR.BIT.B4 = 1U; PORT1.PMR.BIT.B6 = 1U; + MPC.P14PFS.BYTE = 0b10001; MPC.P16PFS.BYTE = MPC_PFS_ISEL | 0b10001; + MPC.PFUSB0.BIT.PUPHZS = 1; /* Lock MPC registers */ MPC.PWPR.BIT.PFSWE = 0; MPC.PWPR.BIT.B0WI = 1; + IR(USB0, USBI0) = 0; IPR(USB0, USBI0) = IRQ_PRIORITY_USBI0; /* Enable SCI0 */ diff --git a/src/portable/renesas/usba/dcd_usba.c b/src/portable/renesas/usba/dcd_usba.c index b0fa1749d..cc25a3a84 100644 --- a/src/portable/renesas/usba/dcd_usba.c +++ b/src/portable/renesas/usba/dcd_usba.c @@ -72,6 +72,7 @@ #define USB_PIPECTR_SQMON (1u<<6) #define USB_PIPECTR_SQCLR (1u<<8) #define USB_PIPECTR_ACLRM (1u<<9) +#define USB_PIPECTR_INBUFM (1u<<14) #define USB_PIPECTR_BSTS (1u<<15) #define USB_FIFOCTR_DTLN (0x1FF) @@ -213,15 +214,59 @@ static volatile uint16_t* ep_addr_to_pipectr(uint8_t rhport, unsigned ep_addr) return ctr; } +static unsigned wait_for_pipe_ready(void) +{ + unsigned ctr; + do { + ctr = USB0.D0FIFOCTR.WORD; + } while (!(ctr & USB_FIFOCTR_FRDY)); + return ctr; +} + +static unsigned select_pipe(unsigned num, unsigned attr) +{ + USB0.PIPESEL.WORD = num; + USB0.D0FIFOSEL.WORD = num | attr; + while (!(USB0.D0FIFOSEL.BIT.CURPIPE != num)) ; + return wait_for_pipe_ready(); +} /* 1 less than 64 bytes were written * 2 no bytes were written - * 0 64 bytes were written */ -static int write_fifo(volatile void *fifo, pipe_state_t* pipe, unsigned mps) + * 0 mps bytes were written */ +static int write_fifo(volatile void *fifo, pipe_state_t* pipe, unsigned mps, unsigned ofs) +{ + unsigned rem = pipe->remaining - ofs; + if (!rem) return 2; + unsigned len = (rem < mps) ? rem: mps; + + hw_fifo_t *reg = (hw_fifo_t*)fifo; + uintptr_t addr = pipe->addr + pipe->length - rem; + if (addr & 1u) { + /* addr is not 2-byte aligned */ + reg->u8 = *(const uint8_t *)addr; + ++addr; + --len; + } + while (len >= 2) { + reg->u16 = *(const uint16_t *)addr; + addr += 2; + len -= 2; + } + if (len) { + reg->u8 = *(const uint8_t *)addr; + ++addr; + } + if (rem < mps) return 1; + return 0; +} +#if 1 +static int write_fifo2(volatile void *fifo, pipe_state_t* pipe, unsigned mps) { unsigned rem = pipe->remaining; if (!rem) return 2; unsigned len = (rem < mps) ? rem: mps; + pipe->remaining = rem - len; hw_fifo_t *reg = (hw_fifo_t*)fifo; uintptr_t addr = pipe->addr + pipe->length - rem; @@ -243,6 +288,7 @@ static int write_fifo(volatile void *fifo, pipe_state_t* pipe, unsigned mps) if (rem < mps) return 1; return 0; } +#endif /* 1 if the number of bytes read is less than 64 bytes * 0 otherwise */ @@ -313,7 +359,7 @@ static bool process_edpt0_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, pipe->data = USB0.DCPCTR.BIT.SQMON; if (ep_addr) { /* IN */ TU_ASSERT(USB0.DCPCTR.BIT.BSTS && (USB0.USBREQ.WORD & 0x80)); - if (write_fifo(&USB0.CFIFO.WORD, pipe, 64)) { + if (write_fifo(&USB0.CFIFO.WORD, pipe, 64, 0)) { USB0.CFIFOCTR.WORD = USB_FIFOCTR_BVAL; } } @@ -321,11 +367,11 @@ static bool process_edpt0_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, // TU_LOG1("X %x %d\r\n", ep_addr, total_bytes); } else { /* ZLP */ - pipe->addr = 0; - pipe->length = 0; - pipe->remaining = 0; - pipe->data = USB0.DCPCTR.BIT.SQMON; - USB0.DCPCTR.WORD = USB_PIPECTR_CCPL | USB_PIPECTR_PID_BUF; + pipe->addr = 0; + pipe->length = 0; + pipe->remaining = 0; + pipe->data = USB0.DCPCTR.BIT.SQMON; + USB0.DCPCTR.WORD = USB_PIPECTR_CCPL | USB_PIPECTR_PID_BUF; // TU_LOG1("Z %x\r\n", USB0.DCPCTR.WORD); } return true; @@ -338,7 +384,7 @@ static void process_edpt0_bemp(uint8_t rhport) if (USB0.DCPCTR.BIT.SQMON == data) { TU_LOG1("W %x\r\n", USB0.DCPCTR.WORD); /* retry transfer */ - int r = write_fifo(&USB0.CFIFO.WORD, &_dcd.pipe[0], 64); + int r = write_fifo(&USB0.CFIFO.WORD, &_dcd.pipe[0], 64, 0); if (r) USB0.CFIFOCTR.WORD = USB_FIFOCTR_BVAL; return; } @@ -347,7 +393,7 @@ static void process_edpt0_bemp(uint8_t rhport) pipe->remaining = rem - 64; pipe->data = data ^ 1; TU_LOG1("Y %d %x\r\n", rem - 64, USB0.DCPCTR.WORD); - int r = write_fifo(&USB0.CFIFO.WORD, &_dcd.pipe[0], 64); + int r = write_fifo(&USB0.CFIFO.WORD, &_dcd.pipe[0], 64, 0); if (r) USB0.CFIFOCTR.WORD = USB_FIFOCTR_BVAL; return; } @@ -393,9 +439,23 @@ static bool process_pipe_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, if (dir) { /* IN */ USB0.D0FIFOSEL.WORD = num | USB_FIFOSEL_MBW_16; while (!(USB0.D0FIFOSEL.BIT.CURPIPE != num)) ; - if (write_fifo(&USB0.D0FIFO.WORD, pipe, mps)) { +#if 0 + unsigned ofs = 0; + if (USB0.PIPECFG.BIT.DBLB && (total_bytes > mps)) { + write_fifo(&USB0.D0FIFO.WORD, pipe, mps, 0); + } + if (write_fifo(&USB0.D0FIFO.WORD, pipe, mps, ofs)) { + USB0.D0FIFOCTR.WORD = USB_FIFOCTR_BVAL; + } +#else + if (USB0.PIPECFG.BIT.DBLB && (total_bytes > mps)) { + write_fifo2(&USB0.D0FIFO.WORD, pipe, mps); + wait_for_pipe_ready(); + } + if (write_fifo2(&USB0.D0FIFO.WORD, pipe, mps)) { USB0.D0FIFOCTR.WORD = USB_FIFOCTR_BVAL; } +#endif USB0.D0FIFOSEL.WORD = 0; } else { volatile reg_pipetre_t *pt = get_pipetre(num); @@ -411,43 +471,76 @@ static bool process_pipe_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, TU_LOG1("X %x %d\r\n", ep_addr, total_bytes); return true; } +#if 0 +static void process_pipe_bemp(uint8_t rhport, unsigned num) +{ + pipe_state_t *pipe = &_dcd.pipe[num]; + unsigned rem = pipe->remaining; + USB0.PIPESEL.WORD = num; + const unsigned mps = USB0.PIPEMAXP.WORD; + if (rem > mps) { + rem -= mps; + pipe->remaining = rem; + if (USB0.PIPECFG.BIT.DBLB) { + if (rem > mps) { + unsigned ctr = select_pipe(num, USB_FIFOSEL_MBW_16); + int r = write_fifo(&USB0.D0FIFO.WORD, pipe, mps, mps); + if (r) USB0.D0FIFOCTR.WORD = USB_FIFOCTR_BVAL; + USB0.D0FIFOSEL.WORD = 0; + TU_LOG1("< %d %x %x %d\r\n", rem, ctr, *get_pipectr(num), r); + } + } else { + unsigned ctr = select_pipe(num, USB_FIFOSEL_MBW_16); + int r = write_fifo(&USB0.D0FIFO.WORD, pipe, mps, 0); + if (r) USB0.D0FIFOCTR.WORD = USB_FIFOCTR_BVAL; + USB0.D0FIFOSEL.WORD = 0; + TU_LOG1("< %d %x %x %d\r\n", rem, ctr, *get_pipectr(num), r); + } + return; + } + pipe->addr = 0; + pipe->remaining = 0; + USB0.D0FIFOSEL.WORD = 0; + dcd_event_xfer_complete(rhport, pipe->ep, pipe->length, + XFER_RESULT_SUCCESS, true); + TU_LOG1("cE\r\n"); +} +#else static void process_pipe_bemp(uint8_t rhport, unsigned num) { pipe_state_t *pipe = &_dcd.pipe[num]; const unsigned rem = pipe->remaining; - if (rem > 64) { - pipe->remaining = rem - 64; - TU_LOG1("Y %d\r\n", rem - 64); + if (rem) { USB0.PIPESEL.WORD = num; const unsigned mps = USB0.PIPEMAXP.WORD; - USB0.D0FIFOSEL.WORD = num | USB_FIFOSEL_MBW_16; - while (!(USB0.D0FIFOSEL.BIT.CURPIPE != num)) ; - int r = write_fifo(&USB0.D0FIFO.WORD, pipe, mps); + unsigned ctr = select_pipe(num, USB_FIFOSEL_MBW_16); + int r = write_fifo2(&USB0.D0FIFO.WORD, pipe, mps); if (r) USB0.D0FIFOCTR.WORD = USB_FIFOCTR_BVAL; USB0.D0FIFOSEL.WORD = 0; + TU_LOG1("< %d %x %x %d\r\n", rem, ctr, *get_pipectr(num), r); + return; + } + if (*get_pipectr(num) & USB_PIPECTR_INBUFM) { + TU_LOG1("< SKIP\r\n"); return; } pipe->addr = 0; pipe->remaining = 0; + USB0.D0FIFOSEL.WORD = 0; dcd_event_xfer_complete(rhport, pipe->ep, pipe->length, XFER_RESULT_SUCCESS, true); - // TU_LOG1("cE\r\n"); + TU_LOG1("cE\r\n"); } +#endif static void process_pipe_brdy(uint8_t rhport, unsigned num) { - pipe_state_t *pipe = &_dcd.pipe[num]; - USB0.PIPESEL.WORD = num; - const unsigned mps = USB0.PIPEMAXP.WORD; - USB0.D0FIFOSEL.WORD = num | USB_FIFOSEL_MBW_8; - while (!(USB0.D0FIFOSEL.BIT.CURPIPE != num)) ; - unsigned ctr; - do { - ctr = USB0.D0FIFOCTR.WORD; - } while (!(ctr & USB_FIFOCTR_FRDY)); - const unsigned len = ctr & USB_FIFOCTR_DTLN; - TU_LOG1(">> %d %x %x\r\n", num, USB0.D0FIFOSEL.WORD, ctr); + const unsigned ctr = select_pipe(num, USB_FIFOSEL_MBW_8); + const unsigned len = ctr & USB_FIFOCTR_DTLN; + const unsigned mps = USB0.PIPEMAXP.WORD; + pipe_state_t *pipe = &_dcd.pipe[num]; + // TU_LOG1("> %d %x %x\r\n", num, USB0.D0FIFOSEL.WORD, ctr); int cplt = read_fifo(&USB0.D0FIFO.WORD, pipe, mps, len); if (cplt || (len < mps)) { if (2 != cplt) { @@ -457,7 +550,7 @@ static void process_pipe_brdy(uint8_t rhport, unsigned num) dcd_event_xfer_complete(rhport, pipe->ep, pipe->length - pipe->remaining, XFER_RESULT_SUCCESS, true); - TU_LOG1("c\r\n"); + // TU_LOG1("c\r\n"); } else { USB0.D0FIFOSEL.WORD = 0; } @@ -589,7 +682,7 @@ bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * ep_desc) const unsigned mps = ep_desc->wMaxPacketSize.size; if (xfer == TUSB_XFER_ISOCHRONOUS && mps > 256) { - /* USBB support up to 256 bytes */ + /* USBa supports up to 256 bytes */ return false; } diff --git a/src/tusb_option.h b/src/tusb_option.h index d0ed78acd..644208ab4 100644 --- a/src/tusb_option.h +++ b/src/tusb_option.h @@ -108,6 +108,9 @@ #define OPT_MCU_EFM32GG11 1301 ///< Silabs EFM32GG11 #define OPT_MCU_EFM32GG12 1302 ///< Silabs EFM32GG12 +// Renesas RX +#define OPT_MCU_RX63X 1400 ///< Renesas RX63N/631 + /** @} */ /** \defgroup group_supported_os Supported RTOS -- cgit v1.3.1 From e010ea30e57e0f8561f8aa7b66afefb01a9bc42d Mon Sep 17 00:00:00 2001 From: kkitayam <45088311+kkitayam@users.noreply.github.com> Date: Sat, 27 Mar 2021 14:42:19 +0900 Subject: using BRDY interruption for handling IN transfers. --- src/portable/renesas/usba/dcd_usba.c | 228 ++++++++++------------------------- 1 file changed, 62 insertions(+), 166 deletions(-) (limited to 'src') diff --git a/src/portable/renesas/usba/dcd_usba.c b/src/portable/renesas/usba/dcd_usba.c index cc25a3a84..e7518b01f 100644 --- a/src/portable/renesas/usba/dcd_usba.c +++ b/src/portable/renesas/usba/dcd_usba.c @@ -200,9 +200,9 @@ static volatile uint16_t* ep_addr_to_pipectr(uint8_t rhport, unsigned ep_addr) { (void)rhport; volatile uint16_t *ctr = NULL; - const unsigned epn = ep_addr & 0xFu; + const unsigned epn = tu_edpt_number(ep_addr); if (epn) { - const unsigned dir = (ep_addr & TUSB_DIR_IN_MASK) ? TUSB_DIR_IN : TUSB_DIR_OUT; + const unsigned dir = tu_edpt_dir(ep_addr); const unsigned num = _dcd.ep[dir][epn]; if (num) { ctr = (volatile uint16_t*)&USB0.PIPE1CTR.WORD; @@ -234,39 +234,11 @@ static unsigned select_pipe(unsigned num, unsigned attr) /* 1 less than 64 bytes were written * 2 no bytes were written * 0 mps bytes were written */ -static int write_fifo(volatile void *fifo, pipe_state_t* pipe, unsigned mps, unsigned ofs) -{ - unsigned rem = pipe->remaining - ofs; - if (!rem) return 2; - unsigned len = (rem < mps) ? rem: mps; - - hw_fifo_t *reg = (hw_fifo_t*)fifo; - uintptr_t addr = pipe->addr + pipe->length - rem; - if (addr & 1u) { - /* addr is not 2-byte aligned */ - reg->u8 = *(const uint8_t *)addr; - ++addr; - --len; - } - while (len >= 2) { - reg->u16 = *(const uint16_t *)addr; - addr += 2; - len -= 2; - } - if (len) { - reg->u8 = *(const uint8_t *)addr; - ++addr; - } - if (rem < mps) return 1; - return 0; -} -#if 1 -static int write_fifo2(volatile void *fifo, pipe_state_t* pipe, unsigned mps) +static int write_fifo(volatile void *fifo, pipe_state_t* pipe, unsigned mps) { unsigned rem = pipe->remaining; if (!rem) return 2; - unsigned len = (rem < mps) ? rem: mps; - pipe->remaining = rem - len; + unsigned len = TU_MIN(rem, mps); hw_fifo_t *reg = (hw_fifo_t*)fifo; uintptr_t addr = pipe->addr + pipe->length - rem; @@ -288,7 +260,6 @@ static int write_fifo2(volatile void *fifo, pipe_state_t* pipe, unsigned mps) if (rem < mps) return 1; return 0; } -#endif /* 1 if the number of bytes read is less than 64 bytes * 0 otherwise */ @@ -359,7 +330,7 @@ static bool process_edpt0_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, pipe->data = USB0.DCPCTR.BIT.SQMON; if (ep_addr) { /* IN */ TU_ASSERT(USB0.DCPCTR.BIT.BSTS && (USB0.USBREQ.WORD & 0x80)); - if (write_fifo(&USB0.CFIFO.WORD, pipe, 64, 0)) { + if (write_fifo(&USB0.CFIFO.WORD, pipe, 64)) { USB0.CFIFOCTR.WORD = USB_FIFOCTR_BVAL; } } @@ -372,7 +343,6 @@ static bool process_edpt0_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, pipe->remaining = 0; pipe->data = USB0.DCPCTR.BIT.SQMON; USB0.DCPCTR.WORD = USB_PIPECTR_CCPL | USB_PIPECTR_PID_BUF; - // TU_LOG1("Z %x\r\n", USB0.DCPCTR.WORD); } return true; } @@ -382,9 +352,8 @@ static void process_edpt0_bemp(uint8_t rhport) pipe_state_t *pipe = &_dcd.pipe[0]; unsigned data = pipe->data; if (USB0.DCPCTR.BIT.SQMON == data) { - TU_LOG1("W %x\r\n", USB0.DCPCTR.WORD); /* retry transfer */ - int r = write_fifo(&USB0.CFIFO.WORD, &_dcd.pipe[0], 64, 0); + int r = write_fifo(&USB0.CFIFO.WORD, &_dcd.pipe[0], 64); if (r) USB0.CFIFOCTR.WORD = USB_FIFOCTR_BVAL; return; } @@ -392,16 +361,14 @@ static void process_edpt0_bemp(uint8_t rhport) if (rem > 64) { pipe->remaining = rem - 64; pipe->data = data ^ 1; - TU_LOG1("Y %d %x\r\n", rem - 64, USB0.DCPCTR.WORD); - int r = write_fifo(&USB0.CFIFO.WORD, &_dcd.pipe[0], 64, 0); + int r = write_fifo(&USB0.CFIFO.WORD, &_dcd.pipe[0], 64); if (r) USB0.CFIFOCTR.WORD = USB_FIFOCTR_BVAL; return; } pipe->addr = 0; pipe->remaining = 0; dcd_event_xfer_complete(rhport, tu_edpt_addr(0, TUSB_DIR_IN), - pipe->length, XFER_RESULT_SUCCESS, true); - // TU_LOG1("c\r\n"); + pipe->length, XFER_RESULT_SUCCESS, true); } static void process_edpt0_brdy(uint8_t rhport) @@ -414,8 +381,7 @@ static void process_edpt0_brdy(uint8_t rhport) } dcd_event_xfer_complete(rhport, tu_edpt_addr(0, TUSB_DIR_OUT), _dcd.pipe[0].length - _dcd.pipe[0].remaining, - XFER_RESULT_SUCCESS, true); - // TU_LOG1("c\r\n"); + XFER_RESULT_SUCCESS, true); } } @@ -423,8 +389,8 @@ static bool process_pipe_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, { (void)rhport; - const unsigned epn = ep_addr & 0xFu; - const unsigned dir = (ep_addr & TUSB_DIR_IN_MASK) ? TUSB_DIR_IN : TUSB_DIR_OUT; + const unsigned epn = tu_edpt_number(ep_addr); + const unsigned dir = tu_edpt_dir(ep_addr); const unsigned num = _dcd.ep[dir][epn]; TU_ASSERT(num); @@ -439,120 +405,61 @@ static bool process_pipe_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, if (dir) { /* IN */ USB0.D0FIFOSEL.WORD = num | USB_FIFOSEL_MBW_16; while (!(USB0.D0FIFOSEL.BIT.CURPIPE != num)) ; -#if 0 - unsigned ofs = 0; - if (USB0.PIPECFG.BIT.DBLB && (total_bytes > mps)) { - write_fifo(&USB0.D0FIFO.WORD, pipe, mps, 0); - } - if (write_fifo(&USB0.D0FIFO.WORD, pipe, mps, ofs)) { - USB0.D0FIFOCTR.WORD = USB_FIFOCTR_BVAL; - } -#else - if (USB0.PIPECFG.BIT.DBLB && (total_bytes > mps)) { - write_fifo2(&USB0.D0FIFO.WORD, pipe, mps); - wait_for_pipe_ready(); - } - if (write_fifo2(&USB0.D0FIFO.WORD, pipe, mps)) { - USB0.D0FIFOCTR.WORD = USB_FIFOCTR_BVAL; - } -#endif + int r = write_fifo(&USB0.D0FIFO.WORD, pipe, mps); + if (r) USB0.D0FIFOCTR.WORD = USB_FIFOCTR_BVAL; USB0.D0FIFOSEL.WORD = 0; } else { volatile reg_pipetre_t *pt = get_pipetre(num); if (pt) { volatile uint16_t *ctr = get_pipectr(num); if (*ctr & 0x3) *ctr = USB_PIPECTR_PID_NAK; - pt->TRE = 1u << 8; + pt->TRE = TU_BIT(8); pt->TRN = (total_bytes + mps - 1) / mps; pt->TRENB = 1; *ctr = USB_PIPECTR_PID_BUF; } } - TU_LOG1("X %x %d\r\n", ep_addr, total_bytes); + //TU_LOG1("X %x %d\r\n", ep_addr, total_bytes); return true; } -#if 0 -static void process_pipe_bemp(uint8_t rhport, unsigned num) -{ - pipe_state_t *pipe = &_dcd.pipe[num]; - unsigned rem = pipe->remaining; - USB0.PIPESEL.WORD = num; - const unsigned mps = USB0.PIPEMAXP.WORD; - - if (rem > mps) { - rem -= mps; - pipe->remaining = rem; - if (USB0.PIPECFG.BIT.DBLB) { - if (rem > mps) { - unsigned ctr = select_pipe(num, USB_FIFOSEL_MBW_16); - int r = write_fifo(&USB0.D0FIFO.WORD, pipe, mps, mps); - if (r) USB0.D0FIFOCTR.WORD = USB_FIFOCTR_BVAL; - USB0.D0FIFOSEL.WORD = 0; - TU_LOG1("< %d %x %x %d\r\n", rem, ctr, *get_pipectr(num), r); - } - } else { - unsigned ctr = select_pipe(num, USB_FIFOSEL_MBW_16); - int r = write_fifo(&USB0.D0FIFO.WORD, pipe, mps, 0); - if (r) USB0.D0FIFOCTR.WORD = USB_FIFOCTR_BVAL; - USB0.D0FIFOSEL.WORD = 0; - TU_LOG1("< %d %x %x %d\r\n", rem, ctr, *get_pipectr(num), r); - } - return; - } - pipe->addr = 0; - pipe->remaining = 0; - USB0.D0FIFOSEL.WORD = 0; - dcd_event_xfer_complete(rhport, pipe->ep, pipe->length, - XFER_RESULT_SUCCESS, true); - TU_LOG1("cE\r\n"); -} -#else -static void process_pipe_bemp(uint8_t rhport, unsigned num) -{ - pipe_state_t *pipe = &_dcd.pipe[num]; - const unsigned rem = pipe->remaining; - if (rem) { - USB0.PIPESEL.WORD = num; - const unsigned mps = USB0.PIPEMAXP.WORD; - unsigned ctr = select_pipe(num, USB_FIFOSEL_MBW_16); - int r = write_fifo2(&USB0.D0FIFO.WORD, pipe, mps); - if (r) USB0.D0FIFOCTR.WORD = USB_FIFOCTR_BVAL; - USB0.D0FIFOSEL.WORD = 0; - TU_LOG1("< %d %x %x %d\r\n", rem, ctr, *get_pipectr(num), r); - return; - } - if (*get_pipectr(num) & USB_PIPECTR_INBUFM) { - TU_LOG1("< SKIP\r\n"); - return; - } - pipe->addr = 0; - pipe->remaining = 0; - USB0.D0FIFOSEL.WORD = 0; - dcd_event_xfer_complete(rhport, pipe->ep, pipe->length, - XFER_RESULT_SUCCESS, true); - TU_LOG1("cE\r\n"); -} -#endif static void process_pipe_brdy(uint8_t rhport, unsigned num) { - const unsigned ctr = select_pipe(num, USB_FIFOSEL_MBW_8); - const unsigned len = ctr & USB_FIFOCTR_DTLN; - const unsigned mps = USB0.PIPEMAXP.WORD; pipe_state_t *pipe = &_dcd.pipe[num]; - // TU_LOG1("> %d %x %x\r\n", num, USB0.D0FIFOSEL.WORD, ctr); - int cplt = read_fifo(&USB0.D0FIFO.WORD, pipe, mps, len); - if (cplt || (len < mps)) { - if (2 != cplt) { - USB0.D0FIFO.WORD = USB_FIFOCTR_BCLR; + if (!tu_edpt_dir(pipe->ep)) { + const unsigned ctr = select_pipe(num, USB_FIFOSEL_MBW_8); + const unsigned len = ctr & USB_FIFOCTR_DTLN; + const unsigned mps = USB0.PIPEMAXP.WORD; + int cplt = read_fifo(&USB0.D0FIFO.WORD, pipe, mps, len); + if (cplt || (len < mps)) { + if (2 != cplt) { + USB0.D0FIFO.WORD = USB_FIFOCTR_BCLR; + } + USB0.D0FIFOSEL.WORD = 0; + dcd_event_xfer_complete(rhport, pipe->ep, + pipe->length - pipe->remaining, + XFER_RESULT_SUCCESS, true); + return; } USB0.D0FIFOSEL.WORD = 0; - dcd_event_xfer_complete(rhport, pipe->ep, - pipe->length - pipe->remaining, - XFER_RESULT_SUCCESS, true); - // TU_LOG1("c\r\n"); } else { + select_pipe(num, USB_FIFOSEL_MBW_16); + const unsigned mps = USB0.PIPEMAXP.WORD; + unsigned rem = pipe->remaining; + rem -= TU_MIN(rem, mps); + pipe->remaining = rem; + if (rem) { + int r = 0; + r = write_fifo(&USB0.D0FIFO.WORD, pipe, mps); + if (r) USB0.D0FIFOCTR.WORD = USB_FIFOCTR_BVAL; + USB0.D0FIFOSEL.WORD = 0; + return; + } USB0.D0FIFOSEL.WORD = 0; + pipe->addr = 0; + pipe->remaining = 0; + dcd_event_xfer_complete(rhport, pipe->ep, pipe->length, + XFER_RESULT_SUCCESS, true); } } @@ -571,7 +478,7 @@ static void process_bus_reset(uint8_t rhport) *ctr = USB_PIPECTR_ACLRM; *ctr = 0; ++ctr; - *tre = (1u<<8); + *tre = TU_BIT(8); tre += 2; } for (int i = 6; i <= 9; ++i) { @@ -583,7 +490,7 @@ static void process_bus_reset(uint8_t rhport) } tu_varclr(&_dcd); dcd_event_bus_reset(rhport, TUSB_SPEED_FULL, true); - TU_LOG1("R\r\n"); + // TU_LOG1("R\r\n"); } static void process_set_address(uint8_t rhport) @@ -626,7 +533,6 @@ void dcd_init(uint8_t rhport) USB0.BEMPENB.WORD = 1; USB0.BRDYENB.WORD = 1; - TU_LOG1("INIT\r\n"); if (USB0.INTSTS0.BIT.VBSTS) { dcd_connect(rhport); } @@ -676,8 +582,8 @@ bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * ep_desc) (void)rhport; const unsigned ep_addr = ep_desc->bEndpointAddress; - const unsigned epn = ep_addr & 0xFu; - const unsigned dir = (ep_addr & TUSB_DIR_IN_MASK) ? TUSB_DIR_IN : TUSB_DIR_OUT; + const unsigned epn = tu_edpt_number(ep_addr); + const unsigned dir = tu_edpt_dir(ep_addr); const unsigned xfer = ep_desc->bmAttributes.xfer; const unsigned mps = ep_desc->wMaxPacketSize.size; @@ -692,6 +598,7 @@ bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * ep_desc) _dcd.ep[dir][epn] = num; /* setup pipe */ + dcd_int_disable(rhport); USB0.PIPESEL.WORD = num; USB0.PIPEMAXP.WORD = mps; volatile uint16_t *ctr = get_pipectr(num); @@ -705,17 +612,14 @@ bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * ep_desc) } else { cfg |= USB_PIPECFG_ISO | USB_PIPECFG_DBLB; } - USB0.PIPECFG.WORD = cfg; - if (dir) { - USB0.BEMPENB.WORD |= 1u << num; + USB0.PIPECFG.WORD = cfg; + USB0.BRDYSTS.WORD = 0x1FFu ^ TU_BIT(num); + USB0.BRDYENB.WORD |= TU_BIT(num); + if (dir || (xfer != TUSB_XFER_BULK)) { *ctr = USB_PIPECTR_PID_BUF; - } else { - USB0.BRDYENB.WORD |= 1u << num; - if (xfer != TUSB_XFER_BULK) { - *ctr = USB_PIPECTR_PID_BUF; - } } - TU_LOG1("O %d %x %x\r\n", USB0.PIPESEL.WORD, USB0.PIPECFG.WORD, USB0.PIPEMAXP.WORD); + // TU_LOG1("O %d %x %x\r\n", USB0.PIPESEL.WORD, USB0.PIPECFG.WORD, USB0.PIPEMAXP.WORD); + dcd_int_enable(rhport); return true; } @@ -723,12 +627,11 @@ bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * ep_desc) void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr) { (void)rhport; - const unsigned epn = ep_addr & 0xFu; - const unsigned dir = (ep_addr & TUSB_DIR_IN_MASK) ? TUSB_DIR_IN : TUSB_DIR_OUT; + const unsigned epn = tu_edpt_number(ep_addr); + const unsigned dir = tu_edpt_dir(ep_addr); const unsigned num = _dcd.ep[dir][epn]; - USB0.BEMPENB.WORD &= ~(1u << num); - USB0.BRDYENB.WORD &= ~(1u << num); + USB0.BRDYENB.WORD &= ~TU_BIT(num); volatile uint16_t *ctr = get_pipectr(num); *ctr = 0; USB0.PIPESEL.WORD = num; @@ -740,7 +643,7 @@ void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr) bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, uint16_t total_bytes) { bool r; - const unsigned epn = ep_addr & 0xFu; + const unsigned epn = tu_edpt_number(ep_addr); dcd_int_disable(rhport); if (0 == epn) { r = process_edpt0_xfer(rhport, ep_addr, buffer, total_bytes); @@ -816,17 +719,10 @@ void dcd_int_handler(uint8_t rhport) } } if (is0 & USB_IS0_BEMP) { - const unsigned m = USB0.BEMPENB.WORD; - unsigned s = USB0.BEMPSTS.WORD & m; + const unsigned s = USB0.BEMPSTS.WORD; USB0.BEMPSTS.WORD = 0; if (s & 1) { process_edpt0_bemp(rhport); - s &= ~1; - } - while (s) { - const unsigned num = __builtin_ctz(s); - process_pipe_bemp(rhport, num); - s &= ~(1< Date: Sat, 27 Mar 2021 16:03:04 +0900 Subject: fixed a OUT transfer did not completed multiple of the max packet size --- src/portable/renesas/usba/dcd_usba.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/portable/renesas/usba/dcd_usba.c b/src/portable/renesas/usba/dcd_usba.c index e7518b01f..844fa3856 100644 --- a/src/portable/renesas/usba/dcd_usba.c +++ b/src/portable/renesas/usba/dcd_usba.c @@ -261,7 +261,7 @@ static int write_fifo(volatile void *fifo, pipe_state_t* pipe, unsigned mps) return 0; } -/* 1 if the number of bytes read is less than 64 bytes +/* 1 if the number of bytes read is less than mps bytes * 0 otherwise */ static int read_fifo(volatile void *fifo, pipe_state_t* pipe, unsigned mps, size_t len) { @@ -272,12 +272,14 @@ static int read_fifo(volatile void *fifo, pipe_state_t* pipe, unsigned mps, size hw_fifo_t *reg = (hw_fifo_t*)fifo; uintptr_t addr = pipe->addr; - while (len--) { + unsigned loop = len; + while (loop--) { *(uint8_t *)addr = reg->u8; ++addr; } pipe->addr = addr; - if (rem < mps) return 1; + if (rem < mps) return 1; + if (rem == len) return 2; return 0; } @@ -419,7 +421,7 @@ static bool process_pipe_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, *ctr = USB_PIPECTR_PID_BUF; } } - //TU_LOG1("X %x %d\r\n", ep_addr, total_bytes); + // TU_LOG1("X %x %d\r\n", ep_addr, total_bytes); return true; } -- cgit v1.3.1 From 4a597c969844d9b279279db0f678aa6732bae1a5 Mon Sep 17 00:00:00 2001 From: kkitayam <45088311+kkitayam@users.noreply.github.com> Date: Sun, 28 Mar 2021 12:42:28 +0900 Subject: cleanup --- src/portable/renesas/usba/dcd_usba.c | 98 ++++++++++++++++-------------------- 1 file changed, 44 insertions(+), 54 deletions(-) (limited to 'src') diff --git a/src/portable/renesas/usba/dcd_usba.c b/src/portable/renesas/usba/dcd_usba.c index 844fa3856..06ea1a3f9 100644 --- a/src/portable/renesas/usba/dcd_usba.c +++ b/src/portable/renesas/usba/dcd_usba.c @@ -112,12 +112,11 @@ typedef union { typedef struct TU_ATTR_PACKED { - uintptr_t addr; - uint16_t length; - uint16_t remaining; + uintptr_t addr; /* the start address of a transfer data buffer */ + uint16_t length; /* the number of bytes in the buffer */ + uint16_t remaining; /* the number of bytes remaining in the buffer */ struct { - uint32_t ep : 8; - uint32_t data: 1; + uint32_t ep : 8; /* an assigned endpoint address */ uint32_t : 0; }; } pipe_state_t; @@ -125,7 +124,7 @@ typedef struct TU_ATTR_PACKED typedef struct { pipe_state_t pipe[9]; - uint8_t ep[2][16]; /* index for pipe number */ + uint8_t ep[2][16]; /* a lookup table for a pipe index from an endpoint address */ } dcd_data_t; //--------------------------------------------------------------------+ @@ -231,10 +230,10 @@ static unsigned select_pipe(unsigned num, unsigned attr) return wait_for_pipe_ready(); } -/* 1 less than 64 bytes were written - * 2 no bytes were written - * 0 mps bytes were written */ -static int write_fifo(volatile void *fifo, pipe_state_t* pipe, unsigned mps) +/* 1 less than mps bytes were written to FIFO + * 2 no bytes were written to FIFO + * 0 mps bytes were written to FIFO */ +static int fifo_write(volatile void *fifo, pipe_state_t* pipe, unsigned mps) { unsigned rem = pipe->remaining; if (!rem) return 2; @@ -261,9 +260,10 @@ static int write_fifo(volatile void *fifo, pipe_state_t* pipe, unsigned mps) return 0; } -/* 1 if the number of bytes read is less than mps bytes - * 0 otherwise */ -static int read_fifo(volatile void *fifo, pipe_state_t* pipe, unsigned mps, size_t len) +/* 1 less than mps bytes were read from FIFO + * 2 the end of the buffer reached. + * 0 mps bytes were read from FIFO */ +static int fifo_read(volatile void *fifo, pipe_state_t* pipe, unsigned mps, size_t len) { unsigned rem = pipe->remaining; if (!rem) return 2; @@ -294,7 +294,6 @@ static void process_setup_packet(uint8_t rhport) setup_packet[3] = USB0.USBLENG; USB0.INTSTS0.WORD = ~USB_IS0_VALID; dcd_event_setup_received(rhport, (const uint8_t*)&setup_packet[0], true); - // TU_LOG1("S\r\n"); } static void process_status_completion(uint8_t rhport) @@ -309,7 +308,6 @@ static void process_status_completion(uint8_t rhport) ep_addr = tu_edpt_addr(0, TUSB_DIR_OUT); } dcd_event_xfer_complete(rhport, ep_addr, 0, XFER_RESULT_SUCCESS, true); - // TU_LOG1("C\r\n"); } static bool process_edpt0_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, uint16_t total_bytes) @@ -317,11 +315,11 @@ static bool process_edpt0_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, (void)rhport; pipe_state_t *pipe = &_dcd.pipe[0]; - /* set fifo direction */ - if (ep_addr) { /* IN */ + /* configure fifo direction and access unit settings */ + if (ep_addr) { /* IN, 2 bytes */ USB0.CFIFOSEL.WORD = USB_FIFOSEL_TX | USB_FIFOSEL_MBW_16; while (!(USB0.CFIFOSEL.WORD & USB_FIFOSEL_TX)) ; - } else { /* OUT */ + } else { /* OUT, a byte */ USB0.CFIFOSEL.WORD = USB_FIFOSEL_MBW_8; while (USB0.CFIFOSEL.WORD & USB_FIFOSEL_TX) ; } @@ -329,21 +327,18 @@ static bool process_edpt0_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, pipe->addr = (uintptr_t)buffer; pipe->length = total_bytes; pipe->remaining = total_bytes; - pipe->data = USB0.DCPCTR.BIT.SQMON; if (ep_addr) { /* IN */ TU_ASSERT(USB0.DCPCTR.BIT.BSTS && (USB0.USBREQ.WORD & 0x80)); - if (write_fifo(&USB0.CFIFO.WORD, pipe, 64)) { + if (fifo_write(&USB0.CFIFO.WORD, pipe, 64)) { USB0.CFIFOCTR.WORD = USB_FIFOCTR_BVAL; } } USB0.DCPCTR.WORD = USB_PIPECTR_PID_BUF; - // TU_LOG1("X %x %d\r\n", ep_addr, total_bytes); } else { /* ZLP */ pipe->addr = 0; pipe->length = 0; pipe->remaining = 0; - pipe->data = USB0.DCPCTR.BIT.SQMON; USB0.DCPCTR.WORD = USB_PIPECTR_CCPL | USB_PIPECTR_PID_BUF; } return true; @@ -352,18 +347,10 @@ static bool process_edpt0_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, static void process_edpt0_bemp(uint8_t rhport) { pipe_state_t *pipe = &_dcd.pipe[0]; - unsigned data = pipe->data; - if (USB0.DCPCTR.BIT.SQMON == data) { - /* retry transfer */ - int r = write_fifo(&USB0.CFIFO.WORD, &_dcd.pipe[0], 64); - if (r) USB0.CFIFOCTR.WORD = USB_FIFOCTR_BVAL; - return; - } const unsigned rem = pipe->remaining; if (rem > 64) { pipe->remaining = rem - 64; - pipe->data = data ^ 1; - int r = write_fifo(&USB0.CFIFO.WORD, &_dcd.pipe[0], 64); + int r = fifo_write(&USB0.CFIFO.WORD, &_dcd.pipe[0], 64); if (r) USB0.CFIFOCTR.WORD = USB_FIFOCTR_BVAL; return; } @@ -376,7 +363,7 @@ static void process_edpt0_bemp(uint8_t rhport) static void process_edpt0_brdy(uint8_t rhport) { size_t len = USB0.CFIFOCTR.BIT.DTLN; - int cplt = read_fifo(&USB0.CFIFO.WORD, &_dcd.pipe[0], 64, len); + int cplt = fifo_read(&USB0.CFIFO.WORD, &_dcd.pipe[0], 64, len); if (cplt || (len < 64)) { if (2 != cplt) { USB0.CFIFOCTR.WORD = USB_FIFOCTR_BCLR; @@ -407,7 +394,7 @@ static bool process_pipe_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, if (dir) { /* IN */ USB0.D0FIFOSEL.WORD = num | USB_FIFOSEL_MBW_16; while (!(USB0.D0FIFOSEL.BIT.CURPIPE != num)) ; - int r = write_fifo(&USB0.D0FIFO.WORD, pipe, mps); + int r = fifo_write(&USB0.D0FIFO.WORD, pipe, mps); if (r) USB0.D0FIFOCTR.WORD = USB_FIFOCTR_BVAL; USB0.D0FIFOSEL.WORD = 0; } else { @@ -428,23 +415,7 @@ static bool process_pipe_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, static void process_pipe_brdy(uint8_t rhport, unsigned num) { pipe_state_t *pipe = &_dcd.pipe[num]; - if (!tu_edpt_dir(pipe->ep)) { - const unsigned ctr = select_pipe(num, USB_FIFOSEL_MBW_8); - const unsigned len = ctr & USB_FIFOCTR_DTLN; - const unsigned mps = USB0.PIPEMAXP.WORD; - int cplt = read_fifo(&USB0.D0FIFO.WORD, pipe, mps, len); - if (cplt || (len < mps)) { - if (2 != cplt) { - USB0.D0FIFO.WORD = USB_FIFOCTR_BCLR; - } - USB0.D0FIFOSEL.WORD = 0; - dcd_event_xfer_complete(rhport, pipe->ep, - pipe->length - pipe->remaining, - XFER_RESULT_SUCCESS, true); - return; - } - USB0.D0FIFOSEL.WORD = 0; - } else { + if (tu_edpt_dir(pipe->ep)) { /* IN */ select_pipe(num, USB_FIFOSEL_MBW_16); const unsigned mps = USB0.PIPEMAXP.WORD; unsigned rem = pipe->remaining; @@ -452,7 +423,7 @@ static void process_pipe_brdy(uint8_t rhport, unsigned num) pipe->remaining = rem; if (rem) { int r = 0; - r = write_fifo(&USB0.D0FIFO.WORD, pipe, mps); + r = fifo_write(&USB0.D0FIFO.WORD, pipe, mps); if (r) USB0.D0FIFOCTR.WORD = USB_FIFOCTR_BVAL; USB0.D0FIFOSEL.WORD = 0; return; @@ -462,6 +433,22 @@ static void process_pipe_brdy(uint8_t rhport, unsigned num) pipe->remaining = 0; dcd_event_xfer_complete(rhport, pipe->ep, pipe->length, XFER_RESULT_SUCCESS, true); + } else { + const unsigned ctr = select_pipe(num, USB_FIFOSEL_MBW_8); + const unsigned len = ctr & USB_FIFOCTR_DTLN; + const unsigned mps = USB0.PIPEMAXP.WORD; + int cplt = fifo_read(&USB0.D0FIFO.WORD, pipe, mps, len); + if (cplt || (len < mps)) { + if (2 != cplt) { + USB0.D0FIFO.WORD = USB_FIFOCTR_BCLR; + } + USB0.D0FIFOSEL.WORD = 0; + dcd_event_xfer_complete(rhport, pipe->ep, + pipe->length - pipe->remaining, + XFER_RESULT_SUCCESS, true); + return; + } + USB0.D0FIFOSEL.WORD = 0; } } @@ -492,7 +479,6 @@ static void process_bus_reset(uint8_t rhport) } tu_varclr(&_dcd); dcd_event_bus_reset(rhport, TUSB_SPEED_FULL, true); - // TU_LOG1("R\r\n"); } static void process_set_address(uint8_t rhport) @@ -674,10 +660,14 @@ void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr) dcd_int_disable(rhport); *ctr = USB_PIPECTR_SQCLR; - if (ep_addr & TUSB_DIR_IN_MASK) { + if (tu_edpt_dir(ep_addr)) { /* IN */ *ctr = USB_PIPECTR_PID_BUF; } else { - /* TODO */ + const unsigned num = _dcd.ep[0][tu_edpt_number(ep_addr)]; + USB0.PIPESEL.WORD = num; + if (USB0.PIPECFG.BIT.TYPE != 1) { + *ctr = USB_PIPECTR_PID_BUF; + } } dcd_int_enable(rhport); } -- cgit v1.3.1 From d135825e9ca36bcf50b3476e5dfdc1f74ae1c101 Mon Sep 17 00:00:00 2001 From: hathach Date: Tue, 30 Mar 2021 21:12:56 +0700 Subject: add hid keys from 0x6B to 0xA4 --- src/class/hid/hid.h | 283 +++++++++++++++++++++++++++++++--------------------- 1 file changed, 171 insertions(+), 112 deletions(-) (limited to 'src') diff --git a/src/class/hid/hid.h b/src/class/hid/hid.h index a7db087a7..79b4f48bf 100644 --- a/src/class/hid/hid.h +++ b/src/class/hid/hid.h @@ -303,118 +303,177 @@ typedef enum //--------------------------------------------------------------------+ // HID KEYCODE //--------------------------------------------------------------------+ -#define HID_KEY_NONE 0x00 -#define HID_KEY_A 0x04 -#define HID_KEY_B 0x05 -#define HID_KEY_C 0x06 -#define HID_KEY_D 0x07 -#define HID_KEY_E 0x08 -#define HID_KEY_F 0x09 -#define HID_KEY_G 0x0A -#define HID_KEY_H 0x0B -#define HID_KEY_I 0x0C -#define HID_KEY_J 0x0D -#define HID_KEY_K 0x0E -#define HID_KEY_L 0x0F -#define HID_KEY_M 0x10 -#define HID_KEY_N 0x11 -#define HID_KEY_O 0x12 -#define HID_KEY_P 0x13 -#define HID_KEY_Q 0x14 -#define HID_KEY_R 0x15 -#define HID_KEY_S 0x16 -#define HID_KEY_T 0x17 -#define HID_KEY_U 0x18 -#define HID_KEY_V 0x19 -#define HID_KEY_W 0x1A -#define HID_KEY_X 0x1B -#define HID_KEY_Y 0x1C -#define HID_KEY_Z 0x1D -#define HID_KEY_1 0x1E -#define HID_KEY_2 0x1F -#define HID_KEY_3 0x20 -#define HID_KEY_4 0x21 -#define HID_KEY_5 0x22 -#define HID_KEY_6 0x23 -#define HID_KEY_7 0x24 -#define HID_KEY_8 0x25 -#define HID_KEY_9 0x26 -#define HID_KEY_0 0x27 -#define HID_KEY_RETURN 0x28 -#define HID_KEY_ESCAPE 0x29 -#define HID_KEY_BACKSPACE 0x2A -#define HID_KEY_TAB 0x2B -#define HID_KEY_SPACE 0x2C -#define HID_KEY_MINUS 0x2D -#define HID_KEY_EQUAL 0x2E -#define HID_KEY_BRACKET_LEFT 0x2F -#define HID_KEY_BRACKET_RIGHT 0x30 -#define HID_KEY_BACKSLASH 0x31 -#define HID_KEY_EUROPE_1 0x32 -#define HID_KEY_SEMICOLON 0x33 -#define HID_KEY_APOSTROPHE 0x34 -#define HID_KEY_GRAVE 0x35 -#define HID_KEY_COMMA 0x36 -#define HID_KEY_PERIOD 0x37 -#define HID_KEY_SLASH 0x38 -#define HID_KEY_CAPS_LOCK 0x39 -#define HID_KEY_F1 0x3A -#define HID_KEY_F2 0x3B -#define HID_KEY_F3 0x3C -#define HID_KEY_F4 0x3D -#define HID_KEY_F5 0x3E -#define HID_KEY_F6 0x3F -#define HID_KEY_F7 0x40 -#define HID_KEY_F8 0x41 -#define HID_KEY_F9 0x42 -#define HID_KEY_F10 0x43 -#define HID_KEY_F11 0x44 -#define HID_KEY_F12 0x45 -#define HID_KEY_PRINT_SCREEN 0x46 -#define HID_KEY_SCROLL_LOCK 0x47 -#define HID_KEY_PAUSE 0x48 -#define HID_KEY_INSERT 0x49 -#define HID_KEY_HOME 0x4A -#define HID_KEY_PAGE_UP 0x4B -#define HID_KEY_DELETE 0x4C -#define HID_KEY_END 0x4D -#define HID_KEY_PAGE_DOWN 0x4E -#define HID_KEY_ARROW_RIGHT 0x4F -#define HID_KEY_ARROW_LEFT 0x50 -#define HID_KEY_ARROW_DOWN 0x51 -#define HID_KEY_ARROW_UP 0x52 -#define HID_KEY_NUM_LOCK 0x53 -#define HID_KEY_KEYPAD_DIVIDE 0x54 -#define HID_KEY_KEYPAD_MULTIPLY 0x55 -#define HID_KEY_KEYPAD_SUBTRACT 0x56 -#define HID_KEY_KEYPAD_ADD 0x57 -#define HID_KEY_KEYPAD_ENTER 0x58 -#define HID_KEY_KEYPAD_1 0x59 -#define HID_KEY_KEYPAD_2 0x5A -#define HID_KEY_KEYPAD_3 0x5B -#define HID_KEY_KEYPAD_4 0x5C -#define HID_KEY_KEYPAD_5 0x5D -#define HID_KEY_KEYPAD_6 0x5E -#define HID_KEY_KEYPAD_7 0x5F -#define HID_KEY_KEYPAD_8 0x60 -#define HID_KEY_KEYPAD_9 0x61 -#define HID_KEY_KEYPAD_0 0x62 -#define HID_KEY_KEYPAD_DECIMAL 0x63 -#define HID_KEY_EUROPE_2 0x64 -#define HID_KEY_APPLICATION 0x65 -#define HID_KEY_POWER 0x66 -#define HID_KEY_KEYPAD_EQUAL 0x67 -#define HID_KEY_F13 0x68 -#define HID_KEY_F14 0x69 -#define HID_KEY_F15 0x6A -#define HID_KEY_CONTROL_LEFT 0xE0 -#define HID_KEY_SHIFT_LEFT 0xE1 -#define HID_KEY_ALT_LEFT 0xE2 -#define HID_KEY_GUI_LEFT 0xE3 -#define HID_KEY_CONTROL_RIGHT 0xE4 -#define HID_KEY_SHIFT_RIGHT 0xE5 -#define HID_KEY_ALT_RIGHT 0xE6 -#define HID_KEY_GUI_RIGHT 0xE7 +#define HID_KEY_NONE 0x00 +#define HID_KEY_A 0x04 +#define HID_KEY_B 0x05 +#define HID_KEY_C 0x06 +#define HID_KEY_D 0x07 +#define HID_KEY_E 0x08 +#define HID_KEY_F 0x09 +#define HID_KEY_G 0x0A +#define HID_KEY_H 0x0B +#define HID_KEY_I 0x0C +#define HID_KEY_J 0x0D +#define HID_KEY_K 0x0E +#define HID_KEY_L 0x0F +#define HID_KEY_M 0x10 +#define HID_KEY_N 0x11 +#define HID_KEY_O 0x12 +#define HID_KEY_P 0x13 +#define HID_KEY_Q 0x14 +#define HID_KEY_R 0x15 +#define HID_KEY_S 0x16 +#define HID_KEY_T 0x17 +#define HID_KEY_U 0x18 +#define HID_KEY_V 0x19 +#define HID_KEY_W 0x1A +#define HID_KEY_X 0x1B +#define HID_KEY_Y 0x1C +#define HID_KEY_Z 0x1D +#define HID_KEY_1 0x1E +#define HID_KEY_2 0x1F +#define HID_KEY_3 0x20 +#define HID_KEY_4 0x21 +#define HID_KEY_5 0x22 +#define HID_KEY_6 0x23 +#define HID_KEY_7 0x24 +#define HID_KEY_8 0x25 +#define HID_KEY_9 0x26 +#define HID_KEY_0 0x27 +#define HID_KEY_RETURN 0x28 +#define HID_KEY_ESCAPE 0x29 +#define HID_KEY_BACKSPACE 0x2A +#define HID_KEY_TAB 0x2B +#define HID_KEY_SPACE 0x2C +#define HID_KEY_MINUS 0x2D +#define HID_KEY_EQUAL 0x2E +#define HID_KEY_BRACKET_LEFT 0x2F +#define HID_KEY_BRACKET_RIGHT 0x30 +#define HID_KEY_BACKSLASH 0x31 +#define HID_KEY_EUROPE_1 0x32 +#define HID_KEY_SEMICOLON 0x33 +#define HID_KEY_APOSTROPHE 0x34 +#define HID_KEY_GRAVE 0x35 +#define HID_KEY_COMMA 0x36 +#define HID_KEY_PERIOD 0x37 +#define HID_KEY_SLASH 0x38 +#define HID_KEY_CAPS_LOCK 0x39 +#define HID_KEY_F1 0x3A +#define HID_KEY_F2 0x3B +#define HID_KEY_F3 0x3C +#define HID_KEY_F4 0x3D +#define HID_KEY_F5 0x3E +#define HID_KEY_F6 0x3F +#define HID_KEY_F7 0x40 +#define HID_KEY_F8 0x41 +#define HID_KEY_F9 0x42 +#define HID_KEY_F10 0x43 +#define HID_KEY_F11 0x44 +#define HID_KEY_F12 0x45 +#define HID_KEY_PRINT_SCREEN 0x46 +#define HID_KEY_SCROLL_LOCK 0x47 +#define HID_KEY_PAUSE 0x48 +#define HID_KEY_INSERT 0x49 +#define HID_KEY_HOME 0x4A +#define HID_KEY_PAGE_UP 0x4B +#define HID_KEY_DELETE 0x4C +#define HID_KEY_END 0x4D +#define HID_KEY_PAGE_DOWN 0x4E +#define HID_KEY_ARROW_RIGHT 0x4F +#define HID_KEY_ARROW_LEFT 0x50 +#define HID_KEY_ARROW_DOWN 0x51 +#define HID_KEY_ARROW_UP 0x52 +#define HID_KEY_NUM_LOCK 0x53 +#define HID_KEY_KEYPAD_DIVIDE 0x54 +#define HID_KEY_KEYPAD_MULTIPLY 0x55 +#define HID_KEY_KEYPAD_SUBTRACT 0x56 +#define HID_KEY_KEYPAD_ADD 0x57 +#define HID_KEY_KEYPAD_ENTER 0x58 +#define HID_KEY_KEYPAD_1 0x59 +#define HID_KEY_KEYPAD_2 0x5A +#define HID_KEY_KEYPAD_3 0x5B +#define HID_KEY_KEYPAD_4 0x5C +#define HID_KEY_KEYPAD_5 0x5D +#define HID_KEY_KEYPAD_6 0x5E +#define HID_KEY_KEYPAD_7 0x5F +#define HID_KEY_KEYPAD_8 0x60 +#define HID_KEY_KEYPAD_9 0x61 +#define HID_KEY_KEYPAD_0 0x62 +#define HID_KEY_KEYPAD_DECIMAL 0x63 +#define HID_KEY_EUROPE_2 0x64 +#define HID_KEY_APPLICATION 0x65 +#define HID_KEY_POWER 0x66 +#define HID_KEY_KEYPAD_EQUAL 0x67 +#define HID_KEY_F13 0x68 +#define HID_KEY_F14 0x69 +#define HID_KEY_F15 0x6A +#define HID_KEY_F16 0x6B +#define HID_KEY_F17 0x6C +#define HID_KEY_F18 0x6D +#define HID_KEY_F19 0x6E +#define HID_KEY_F20 0x6F +#define HID_KEY_F21 0x70 +#define HID_KEY_F22 0x71 +#define HID_KEY_F23 0x72 +#define HID_KEY_F24 0x73 +#define HID_KEY_EXECUTE 0x74 +#define HID_KEY_HELP 0x75 +#define HID_KEY_MENU 0x76 +#define HID_KEY_SELECT 0x77 +#define HID_KEY_STOP 0x78 +#define HID_KEY_AGAIN 0x79 +#define HID_KEY_UNDO 0x7A +#define HID_KEY_CUT 0x7B +#define HID_KEY_COPY 0x7C +#define HID_KEY_PASTE 0x7D +#define HID_KEY_FIND 0x7E +#define HID_KEY_MUTE 0x7F +#define HID_KEY_VOLUME_UP 0x80 +#define HID_KEY_VOLUME_DOWN 0x81 +#define HID_KEY_LOCKING_CAPS_LOCK 0x82 +#define HID_KEY_LOCKING_NUM_LOCK 0x83 +#define HID_KEY_LOCKING_SCROLL_LOCK 0x84 +#define HID_KEY_KEYPAD_COMMA 0x85 +#define HID_KEY_KEYPAD_EQUAL_SIGN 0x86 +#define HID_KEY_KANJI1 0x87 +#define HID_KEY_KANJI2 0x88 +#define HID_KEY_KANJI3 0x89 +#define HID_KEY_KANJI4 0x8A +#define HID_KEY_KANJI5 0x8B +#define HID_KEY_KANJI6 0x8C +#define HID_KEY_KANJI7 0x8D +#define HID_KEY_KANJI8 0x8E +#define HID_KEY_KANJI9 0x8F +#define HID_KEY_LANG1 0x90 +#define HID_KEY_LANG2 0x91 +#define HID_KEY_LANG3 0x92 +#define HID_KEY_LANG4 0x93 +#define HID_KEY_LANG5 0x94 +#define HID_KEY_LANG6 0x95 +#define HID_KEY_LANG7 0x96 +#define HID_KEY_LANG8 0x97 +#define HID_KEY_LANG9 0x98 +#define HID_KEY_ALTERNATE_ERASE 0x99 +#define HID_KEY_SYSREQ_ATTENTION 0x9A +#define HID_KEY_CANCEL 0x9B +#define HID_KEY_CLEAR 0x9C +#define HID_KEY_PRIOR 0x9D +#define HID_KEY_RETURN 0x9E +#define HID_KEY_SEPARATOR 0x9F +#define HID_KEY_OUT 0xA0 +#define HID_KEY_OPER 0xA1 +#define HID_KEY_CLEAR_AGAIN 0xA2 +#define HID_KEY_CRSEL_PROPS 0xA3 +#define HID_KEY_EXSEL 0xA4 +// RESERVED 0xA5-DF +#define HID_KEY_CONTROL_LEFT 0xE0 +#define HID_KEY_SHIFT_LEFT 0xE1 +#define HID_KEY_ALT_LEFT 0xE2 +#define HID_KEY_GUI_LEFT 0xE3 +#define HID_KEY_CONTROL_RIGHT 0xE4 +#define HID_KEY_SHIFT_RIGHT 0xE5 +#define HID_KEY_ALT_RIGHT 0xE6 +#define HID_KEY_GUI_RIGHT 0xE7 //--------------------------------------------------------------------+ -- cgit v1.3.1 From 89a911ee43f2c7a17303b58739dc8b22cbd56294 Mon Sep 17 00:00:00 2001 From: hathach Date: Tue, 30 Mar 2021 21:26:35 +0700 Subject: correct hid key enter = 0x28, return = 0x9E --- src/class/hid/hid.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/class/hid/hid.h b/src/class/hid/hid.h index 79b4f48bf..351a4d600 100644 --- a/src/class/hid/hid.h +++ b/src/class/hid/hid.h @@ -340,7 +340,7 @@ typedef enum #define HID_KEY_8 0x25 #define HID_KEY_9 0x26 #define HID_KEY_0 0x27 -#define HID_KEY_RETURN 0x28 +#define HID_KEY_ENTER 0x28 #define HID_KEY_ESCAPE 0x29 #define HID_KEY_BACKSPACE 0x2A #define HID_KEY_TAB 0x2B -- cgit v1.3.1 From c5aa661c892159b2eced9b2e3c1a4a1d8f92b1f6 Mon Sep 17 00:00:00 2001 From: hathach Date: Tue, 30 Mar 2021 23:54:17 +0700 Subject: rename tud_midi_receive/send to tud_midi_packet_read/write --- src/class/midi/midi_device.c | 6 +++--- src/class/midi/midi_device.h | 17 +++++++++-------- 2 files changed, 12 insertions(+), 11 deletions(-) (limited to 'src') diff --git a/src/class/midi/midi_device.c b/src/class/midi/midi_device.c index 29019cc1d..3772c4759 100644 --- a/src/class/midi/midi_device.c +++ b/src/class/midi/midi_device.c @@ -127,7 +127,7 @@ uint32_t tud_midi_n_read(uint8_t itf, uint8_t cable_num, void* buffer, uint32_t // Fill empty buffer if (midi->read_buffer_length == 0) { - if (!tud_midi_n_receive(itf, midi->read_buffer)) return 0; + if (!tud_midi_n_packet_read(itf, midi->read_buffer)) return 0; uint8_t code_index = midi->read_buffer[0] & 0x0f; // We always copy over the first byte. @@ -166,7 +166,7 @@ void tud_midi_n_read_flush (uint8_t itf, uint8_t cable_num) _prep_out_transaction(p_midi); } -bool tud_midi_n_receive (uint8_t itf, uint8_t packet[4]) +bool tud_midi_n_packet_read (uint8_t itf, uint8_t packet[4]) { midid_interface_t* p_midi = &_midid_itf[itf]; uint32_t num_read = tu_fifo_read_n(&p_midi->rx_ff, packet, 4); @@ -278,7 +278,7 @@ uint32_t tud_midi_n_write(uint8_t itf, uint8_t cable_num, uint8_t const* buffer, return i; } -bool tud_midi_n_send (uint8_t itf, uint8_t const packet[4]) +bool tud_midi_n_packet_write (uint8_t itf, uint8_t const packet[4]) { midid_interface_t* midi = &_midid_itf[itf]; if (midi->itf_num == 0) { diff --git a/src/class/midi/midi_device.h b/src/class/midi/midi_device.h index 5e7df80ae..f76554c70 100644 --- a/src/class/midi/midi_device.h +++ b/src/class/midi/midi_device.h @@ -68,8 +68,8 @@ uint32_t tud_midi_n_write (uint8_t itf, uint8_t cable_num, uint8_t const* b static inline uint32_t tud_midi_n_write24 (uint8_t itf, uint8_t cable_num, uint8_t b1, uint8_t b2, uint8_t b3); -bool tud_midi_n_receive (uint8_t itf, uint8_t packet[4]); -bool tud_midi_n_send (uint8_t itf, uint8_t const packet[4]); +bool tud_midi_n_packet_read (uint8_t itf, uint8_t packet[4]); +bool tud_midi_n_packet_write (uint8_t itf, uint8_t const packet[4]); //--------------------------------------------------------------------+ // Application API (Single Interface) @@ -80,8 +80,9 @@ static inline uint32_t tud_midi_read (void* buffer, uint32_t bufsize); static inline void tud_midi_read_flush (void); static inline uint32_t tud_midi_write (uint8_t cable_num, uint8_t const* buffer, uint32_t bufsize); static inline uint32_t tud_midi_write24 (uint8_t cable_num, uint8_t b1, uint8_t b2, uint8_t b3); -static inline bool tud_midi_receive (uint8_t packet[4]); -static inline bool tud_midi_send (uint8_t const packet[4]); + +static inline bool tud_midi_packet_read (uint8_t packet[4]); +static inline bool tud_midi_packet_write(uint8_t const packet[4]); //--------------------------------------------------------------------+ // Application Callback API (weak is optional) @@ -129,14 +130,14 @@ static inline uint32_t tud_midi_write24 (uint8_t cable_num, uint8_t b1, uint8_t return tud_midi_write(cable_num, msg, 3); } -static inline bool tud_midi_receive (uint8_t packet[4]) +static inline bool tud_midi_packet_read (uint8_t packet[4]) { - return tud_midi_n_receive(0, packet); + return tud_midi_n_packet_read(0, packet); } -static inline bool tud_midi_send (uint8_t const packet[4]) +static inline bool tud_midi_packet_write (uint8_t const packet[4]) { - return tud_midi_n_send(0, packet); + return tud_midi_n_packet_write(0, packet); } //--------------------------------------------------------------------+ -- cgit v1.3.1 From b05084e406b50c6378572974e47d7e2ec15f2045 Mon Sep 17 00:00:00 2001 From: hathach Date: Tue, 30 Mar 2021 23:56:55 +0700 Subject: remove tud_midi_read_flush() --- src/class/midi/midi_device.c | 8 -------- src/class/midi/midi_device.h | 7 ------- 2 files changed, 15 deletions(-) (limited to 'src') diff --git a/src/class/midi/midi_device.c b/src/class/midi/midi_device.c index 3772c4759..48e5a8e68 100644 --- a/src/class/midi/midi_device.c +++ b/src/class/midi/midi_device.c @@ -158,14 +158,6 @@ uint32_t tud_midi_n_read(uint8_t itf, uint8_t cable_num, void* buffer, uint32_t return n; } -void tud_midi_n_read_flush (uint8_t itf, uint8_t cable_num) -{ - (void) cable_num; - midid_interface_t* p_midi = &_midid_itf[itf]; - tu_fifo_clear(&p_midi->rx_ff); - _prep_out_transaction(p_midi); -} - bool tud_midi_n_packet_read (uint8_t itf, uint8_t packet[4]) { midid_interface_t* p_midi = &_midid_itf[itf]; diff --git a/src/class/midi/midi_device.h b/src/class/midi/midi_device.h index f76554c70..1060fd77a 100644 --- a/src/class/midi/midi_device.h +++ b/src/class/midi/midi_device.h @@ -62,7 +62,6 @@ bool tud_midi_n_mounted (uint8_t itf); uint32_t tud_midi_n_available (uint8_t itf, uint8_t cable_num); uint32_t tud_midi_n_read (uint8_t itf, uint8_t cable_num, void* buffer, uint32_t bufsize); -void tud_midi_n_read_flush (uint8_t itf, uint8_t cable_num); uint32_t tud_midi_n_write (uint8_t itf, uint8_t cable_num, uint8_t const* buffer, uint32_t bufsize); static inline @@ -77,7 +76,6 @@ bool tud_midi_n_packet_write (uint8_t itf, uint8_t const packet[4]); static inline bool tud_midi_mounted (void); static inline uint32_t tud_midi_available (void); static inline uint32_t tud_midi_read (void* buffer, uint32_t bufsize); -static inline void tud_midi_read_flush (void); static inline uint32_t tud_midi_write (uint8_t cable_num, uint8_t const* buffer, uint32_t bufsize); static inline uint32_t tud_midi_write24 (uint8_t cable_num, uint8_t b1, uint8_t b2, uint8_t b3); @@ -114,11 +112,6 @@ static inline uint32_t tud_midi_read (void* buffer, uint32_t bufsize) return tud_midi_n_read(0, 0, buffer, bufsize); } -static inline void tud_midi_read_flush (void) -{ - tud_midi_n_read_flush(0, 0); -} - static inline uint32_t tud_midi_write (uint8_t cable_num, uint8_t const* buffer, uint32_t bufsize) { return tud_midi_n_write(0, cable_num, buffer, bufsize); -- cgit v1.3.1 From 949ff791e0222d9d89fe54b7cab036125997b66e Mon Sep 17 00:00:00 2001 From: hathach Date: Wed, 31 Mar 2021 00:34:09 +0700 Subject: code format --- src/class/midi/midi_device.c | 131 +++++++++++++++++++++++++------------------ 1 file changed, 77 insertions(+), 54 deletions(-) (limited to 'src') diff --git a/src/class/midi/midi_device.c b/src/class/midi/midi_device.c index 48e5a8e68..1ff81c39a 100644 --- a/src/class/midi/midi_device.c +++ b/src/class/midi/midi_device.c @@ -200,67 +200,90 @@ static uint32_t write_flush(midid_interface_t* midi) uint32_t tud_midi_n_write(uint8_t itf, uint8_t cable_num, uint8_t const* buffer, uint32_t bufsize) { midid_interface_t* midi = &_midid_itf[itf]; - if (midi->itf_num == 0) { - return 0; - } + TU_VERIFY(midi->itf_num, 0); uint32_t i = 0; - while (i < bufsize) { + while ( i < bufsize ) + { uint8_t data = buffer[i]; - if (midi->write_buffer_length == 0) { - uint8_t msg = data >> 4; - midi->write_buffer[1] = data; - midi->write_buffer_length = 2; - // Check to see if we're still in a SysEx transmit. - if (midi->write_buffer[0] == 0x4) { - if (data == 0xf7) { - midi->write_buffer[0] = 0x5; - midi->write_target_length = 2; - } else { - midi->write_target_length = 4; - } - } else if ((msg >= 0x8 && msg <= 0xB) || msg == 0xE) { - midi->write_buffer[0] = cable_num << 4 | msg; - midi->write_target_length = 4; - } else if (msg == 0xf) { - if (data == 0xf0) { - midi->write_buffer[0] = 0x4; - midi->write_target_length = 4; - } else if (data == 0xf1 || data == 0xf3) { - midi->write_buffer[0] = 0x2; - midi->write_target_length = 3; - } else if (data == 0xf2) { - midi->write_buffer[0] = 0x3; - midi->write_target_length = 4; - } else { - midi->write_buffer[0] = 0x5; - midi->write_target_length = 2; - } - } else { - // Pack individual bytes if we don't support packing them into words. - midi->write_buffer[0] = cable_num << 4 | 0xf; - midi->write_buffer[2] = 0; - midi->write_buffer[3] = 0; - midi->write_buffer_length = 2; - midi->write_target_length = 2; + if ( midi->write_buffer_length == 0 ) + { + uint8_t msg = data >> 4; + midi->write_buffer[1] = data; + midi->write_buffer_length = 2; + // Check to see if we're still in a SysEx transmit. + if ( midi->write_buffer[0] == 0x4 ) + { + if ( data == 0xf7 ) + { + midi->write_buffer[0] = 0x5; + midi->write_target_length = 2; } - } else { - midi->write_buffer[midi->write_buffer_length] = data; - midi->write_buffer_length += 1; - // See if this byte ends a SysEx. - if (midi->write_buffer[0] == 0x4 && data == 0xf7) { - midi->write_buffer[0] = 0x4 + (midi->write_buffer_length - 1); - midi->write_target_length = midi->write_buffer_length; + else + { + midi->write_target_length = 4; + } + } + else if ( (msg >= 0x8 && msg <= 0xB) || msg == 0xE ) + { + midi->write_buffer[0] = cable_num << 4 | msg; + midi->write_target_length = 4; + } + else if ( msg == 0xf ) + { + if ( data == 0xf0 ) + { + midi->write_buffer[0] = 0x4; + midi->write_target_length = 4; + } + else if ( data == 0xf1 || data == 0xf3 ) + { + midi->write_buffer[0] = 0x2; + midi->write_target_length = 3; } + else if ( data == 0xf2 ) + { + midi->write_buffer[0] = 0x3; + midi->write_target_length = 4; + } + else + { + midi->write_buffer[0] = 0x5; + midi->write_target_length = 2; + } + } + else + { + // Pack individual bytes if we don't support packing them into words. + midi->write_buffer[0] = cable_num << 4 | 0xf; + midi->write_buffer[2] = 0; + midi->write_buffer[3] = 0; + midi->write_buffer_length = 2; + midi->write_target_length = 2; + } + } + else + { + TU_ASSERT(midi->write_buffer_length < 4, 0); + midi->write_buffer[midi->write_buffer_length] = data; + midi->write_buffer_length += 1; + // See if this byte ends a SysEx. + if ( midi->write_buffer[0] == 0x4 && data == 0xf7 ) + { + midi->write_buffer[0] = 0x4 + (midi->write_buffer_length - 1); + midi->write_target_length = midi->write_buffer_length; + } } - if (midi->write_buffer_length == midi->write_target_length) { - uint16_t written = tu_fifo_write_n(&midi->tx_ff, midi->write_buffer, 4); - if (written < 4) { - TU_ASSERT( written == 0 ); - break; - } - midi->write_buffer_length = 0; + if ( midi->write_buffer_length == midi->write_target_length ) + { + uint16_t written = tu_fifo_write_n(&midi->tx_ff, midi->write_buffer, 4); + if ( written < 4 ) + { + TU_ASSERT(written == 0); + break; + } + midi->write_buffer_length = 0; } i++; } -- cgit v1.3.1 From 080b14b292251e46b43aac9e1cf7807dc2d3eb2c Mon Sep 17 00:00:00 2001 From: hathach Date: Fri, 2 Apr 2021 13:26:55 +0700 Subject: fix midi tx fifo overflow cause data corruption rename --- examples/device/dynamic_configuration/src/main.c | 2 +- examples/device/midi_test/src/main.c | 8 +- examples/make.mk | 2 +- src/class/midi/midi.h | 45 ++++++++++ src/class/midi/midi_device.c | 103 ++++++++++++++--------- src/class/midi/midi_device.h | 16 +++- 6 files changed, 127 insertions(+), 49 deletions(-) (limited to 'src') diff --git a/examples/device/dynamic_configuration/src/main.c b/examples/device/dynamic_configuration/src/main.c index acee295f6..ce1f752d0 100644 --- a/examples/device/dynamic_configuration/src/main.c +++ b/examples/device/dynamic_configuration/src/main.c @@ -172,7 +172,7 @@ void midi_task(void) // regardless of these being used or not. Therefore incoming traffic should be read // (possibly just discarded) to avoid the sender blocking in IO uint8_t packet[4]; - while(tud_midi_available()) tud_midi_receive(packet); + while( tud_midi_available() ) tud_midi_packet_read(packet); // send note every 1000 ms if (board_millis() - start_ms < 286) return; // not enough time diff --git a/examples/device/midi_test/src/main.c b/examples/device/midi_test/src/main.c index 858a096b6..af10350df 100644 --- a/examples/device/midi_test/src/main.c +++ b/examples/device/midi_test/src/main.c @@ -132,7 +132,7 @@ void midi_task(void) // regardless of these being used or not. Therefore incoming traffic should be read // (possibly just discarded) to avoid the sender blocking in IO uint8_t packet[4]; - while(tud_midi_available()) tud_midi_receive(packet); + while ( tud_midi_available() ) tud_midi_packet_read(packet); // send note every 1000 ms if (board_millis() - start_ms < 286) return; // not enough time @@ -146,10 +146,12 @@ void midi_task(void) if (previous < 0) previous = sizeof(note_sequence) - 1; // Send Note On for current position at full velocity (127) on channel 1. - tud_midi_write24(cable_num, 0x90 | channel, note_sequence[note_pos], 127); + uint8_t note_on[3] = { 0x90 | channel, note_sequence[note_pos], 127 }; + tud_midi_write(cable_num, note_on, 3); // Send Note Off for previous note. - tud_midi_write24(cable_num, 0x80 | channel, note_sequence[previous], 0); + uint8_t note_off[3] = { 0x80 | channel, note_sequence[previous], 0}; + tud_midi_write(cable_num, note_off, 3); // Increment position note_pos++; diff --git a/examples/make.mk b/examples/make.mk index e04a2592a..ffcb8ee5c 100644 --- a/examples/make.mk +++ b/examples/make.mk @@ -103,7 +103,7 @@ CFLAGS += \ # Debugging/Optimization ifeq ($(DEBUG), 1) - CFLAGS += -Og + CFLAGS += -O0 else CFLAGS += -Os endif diff --git a/src/class/midi/midi.h b/src/class/midi/midi.h index f758b6e1c..74dc41749 100644 --- a/src/class/midi/midi.h +++ b/src/class/midi/midi.h @@ -61,6 +61,51 @@ typedef enum MIDI_JACK_EXTERNAL = 0x02 } midi_jack_type_t; +typedef enum +{ + MIDI_CIN_MISC = 0, + MIDI_CIN_CABLE_EVENT = 1, + MIDI_CIN_SYSCOM_2BYTE = 2, // 2 byte system common message e.g MTC, SongSelect + MIDI_CIN_SYSCOM_3BYTE = 3, // 3 byte system common message e.g SPP + MIDI_CIN_SYSEX_START = 4, // SysEx starts or continue + MIDI_CIN_SYSEX_END_1BYTE = 5, // SysEx ends with 1 data, or 1 byte system common message + MIDI_CIN_SYSEX_END_2BYTE = 6, // SysEx ends with 2 data + MIDI_CIN_SYSEX_END_3BYTE = 7, // SysEx ends with 3 data + MIDI_CIN_NOTE_ON = 8, + MIDI_CIN_NOTE_OFF = 9, + MIDI_CIN_POLY_KEYPRESS = 10, + MIDI_CIN_CONTROL_CHANGE = 11, + MIDI_CIN_PROGRAM_CHANGE = 12, + MIDI_CIN_CHANNEL_PRESSURE = 13, + MIDI_CIN_PITCH_BEND_CHANGE = 14, + MIDI_CIN_1BYTE_DATA = 15 +} midi_code_index_number_t; + +// MIDI 1.0 status byte +enum +{ + //------------- System Exclusive -------------// + MIDI_STATUS_SYSEX_START = 0xF0, + MIDI_STATUS_SYSEX_END = 0xF7, + + //------------- System Common -------------// + MIDI_STATUS_SYSCOM_TIME_CODE_QUARTER_FRAME = 0xF1, + MIDI_STATUS_SYSCOM_SONG_POSITION_POINTER = 0xF2, + MIDI_STATUS_SYSCOM_SONG_SELECT = 0xF3, + // F4, F5 is undefined + MIDI_STATUS_SYSCOM_TUNE_REQUEST = 0xF6, + + //------------- System RealTime -------------// + MIDI_STATUS_SYSREAL_TIMING_CLOCK = 0xF8, + // 0xF9 is undefined + MIDI_STATUS_SYSREAL_START = 0xFA, + MIDI_STATUS_SYSREAL_CONTINUE = 0xFB, + MIDI_STATUS_SYSREAL_STOP = 0xFC, + // 0xFD is undefined + MIDI_STATUS_SYSREAL_ACTIVE_SENSING = 0xFE, + MIDI_STATUS_SYSREAL_SYSTEM_RESET = 0xFF, +}; + /// MIDI Interface Header Descriptor typedef struct TU_ATTR_PACKED { diff --git a/src/class/midi/midi_device.c b/src/class/midi/midi_device.c index 1ff81c39a..cba1dcca0 100644 --- a/src/class/midi/midi_device.c +++ b/src/class/midi/midi_device.c @@ -38,6 +38,7 @@ //--------------------------------------------------------------------+ // MACRO CONSTANT TYPEDEF //--------------------------------------------------------------------+ + typedef struct { uint8_t itf_num; @@ -126,16 +127,19 @@ uint32_t tud_midi_n_read(uint8_t itf, uint8_t cable_num, void* buffer, uint32_t midid_interface_t* midi = &_midid_itf[itf]; // Fill empty buffer - if (midi->read_buffer_length == 0) { - if (!tud_midi_n_packet_read(itf, midi->read_buffer)) return 0; + if ( midi->read_buffer_length == 0 ) + { + if ( !tud_midi_n_packet_read(itf, midi->read_buffer) ) return 0; uint8_t code_index = midi->read_buffer[0] & 0x0f; // We always copy over the first byte. uint8_t count = 1; // Ignore subsequent bytes based on the code. - if (code_index != 0x5 && code_index != 0xf) { + if ( code_index != 0x5 && code_index != 0xf ) + { count = 2; - if (code_index != 0x2 && code_index != 0x6 && code_index != 0xc && code_index != 0xd) { + if ( code_index != 0x2 && code_index != 0x6 && code_index != 0xc && code_index != 0xd ) + { count = 3; } } @@ -150,7 +154,8 @@ uint32_t tud_midi_n_read(uint8_t itf, uint8_t cable_num, void* buffer, uint32_t memcpy(buffer, midi->read_buffer + 1 + midi->read_target_length, n); midi->read_target_length += n; - if (midi->read_target_length == midi->read_buffer_length) { + if ( midi->read_target_length == midi->read_buffer_length ) + { midi->read_buffer_length = 0; midi->read_target_length = 0; } @@ -166,10 +171,6 @@ bool tud_midi_n_packet_read (uint8_t itf, uint8_t packet[4]) return (num_read == 4); } -void midi_rx_done_cb(midid_interface_t* midi, uint8_t const* buffer, uint32_t bufsize) { - tu_fifo_write_n(&midi->rx_ff, buffer, bufsize); -} - //--------------------------------------------------------------------+ // WRITE API //--------------------------------------------------------------------+ @@ -185,7 +186,8 @@ static uint32_t write_flush(midid_interface_t* midi) TU_VERIFY( usbd_edpt_claim(rhport, midi->ep_in), 0 ); uint16_t count = tu_fifo_read_n(&midi->tx_ff, midi->epin_buf, CFG_TUD_MIDI_EP_BUFSIZE); - if (count > 0) + + if (count) { TU_ASSERT( usbd_edpt_xfer(rhport, midi->ep_in, midi->epin_buf, count), 0 ); return count; @@ -202,21 +204,26 @@ uint32_t tud_midi_n_write(uint8_t itf, uint8_t cable_num, uint8_t const* buffer, midid_interface_t* midi = &_midid_itf[itf]; TU_VERIFY(midi->itf_num, 0); + uint32_t written = 0; uint32_t i = 0; while ( i < bufsize ) { - uint8_t data = buffer[i]; + uint8_t const data = buffer[i]; + if ( midi->write_buffer_length == 0 ) { - uint8_t msg = data >> 4; + // new packet + + uint8_t const msg = data >> 4; midi->write_buffer[1] = data; midi->write_buffer_length = 2; + // Check to see if we're still in a SysEx transmit. - if ( midi->write_buffer[0] == 0x4 ) + if ( midi->write_buffer[0] == MIDI_CIN_SYSEX_START ) { - if ( data == 0xf7 ) + if ( data == MIDI_STATUS_SYSEX_END ) { - midi->write_buffer[0] = 0x5; + midi->write_buffer[0] = MIDI_CIN_SYSEX_END_1BYTE; midi->write_target_length = 2; } else @@ -226,29 +233,31 @@ uint32_t tud_midi_n_write(uint8_t itf, uint8_t cable_num, uint8_t const* buffer, } else if ( (msg >= 0x8 && msg <= 0xB) || msg == 0xE ) { - midi->write_buffer[0] = cable_num << 4 | msg; + // Channel Voice Messages + midi->write_buffer[0] = (cable_num << 4) | msg; midi->write_target_length = 4; } else if ( msg == 0xf ) { - if ( data == 0xf0 ) + // System message + if ( data == MIDI_STATUS_SYSEX_START ) { - midi->write_buffer[0] = 0x4; + midi->write_buffer[0] = MIDI_CIN_SYSEX_START; midi->write_target_length = 4; } - else if ( data == 0xf1 || data == 0xf3 ) + else if ( data == MIDI_STATUS_SYSCOM_TIME_CODE_QUARTER_FRAME || data == MIDI_STATUS_SYSCOM_SONG_SELECT ) { - midi->write_buffer[0] = 0x2; + midi->write_buffer[0] = MIDI_CIN_SYSCOM_2BYTE; midi->write_target_length = 3; } - else if ( data == 0xf2 ) + else if ( data == MIDI_STATUS_SYSCOM_SONG_POSITION_POINTER ) { - midi->write_buffer[0] = 0x3; + midi->write_buffer[0] = MIDI_CIN_SYSCOM_3BYTE; midi->write_target_length = 4; } else { - midi->write_buffer[0] = 0x5; + midi->write_buffer[0] = MIDI_CIN_SYSEX_END_1BYTE; midi->write_target_length = 2; } } @@ -264,33 +273,44 @@ uint32_t tud_midi_n_write(uint8_t itf, uint8_t cable_num, uint8_t const* buffer, } else { + // On-going packet + TU_ASSERT(midi->write_buffer_length < 4, 0); midi->write_buffer[midi->write_buffer_length] = data; - midi->write_buffer_length += 1; + midi->write_buffer_length++; + // See if this byte ends a SysEx. - if ( midi->write_buffer[0] == 0x4 && data == 0xf7 ) + if ( midi->write_buffer[0] == MIDI_CIN_SYSEX_START && data == MIDI_STATUS_SYSEX_END ) { - midi->write_buffer[0] = 0x4 + (midi->write_buffer_length - 1); + midi->write_buffer[0] = MIDI_CIN_SYSEX_START + (midi->write_buffer_length - 1); midi->write_target_length = midi->write_buffer_length; } } + // Send out packet if ( midi->write_buffer_length == midi->write_target_length ) { - uint16_t written = tu_fifo_write_n(&midi->tx_ff, midi->write_buffer, 4); - if ( written < 4 ) - { - TU_ASSERT(written == 0); - break; - } - midi->write_buffer_length = 0; + // zeroes unused bytes + for(uint8_t idx = midi->write_target_length; idx < 4; idx++) midi->write_buffer[idx] = 0; + + uint16_t const count = tu_fifo_write_n(&midi->tx_ff, midi->write_buffer, 4); + + // reset buffer + midi->write_buffer_length = midi->write_target_length = 0; + + // fifo overflow, here we assume FIFO is multiple of 4 and didn't check remaining before writing + if ( count != 4 ) break; + + // updated written if succeeded + written = i; } + i++; } write_flush(midi); - return i; + return written; } bool tud_midi_n_packet_write (uint8_t itf, uint8_t const packet[4]) @@ -300,8 +320,7 @@ bool tud_midi_n_packet_write (uint8_t itf, uint8_t const packet[4]) return 0; } - if (tu_fifo_remaining(&midi->tx_ff) < 4) - return false; + if (tu_fifo_remaining(&midi->tx_ff) < 4) return false; tu_fifo_write_n(&midi->tx_ff, packet, 4); write_flush(midi); @@ -347,9 +366,9 @@ void midid_reset(uint8_t rhport) uint16_t midid_open(uint8_t rhport, tusb_desc_interface_t const * desc_itf, uint16_t max_len) { // 1st Interface is Audio Control v1 - TU_VERIFY(TUSB_CLASS_AUDIO == desc_itf->bInterfaceClass && - AUDIO_SUBCLASS_CONTROL == desc_itf->bInterfaceSubClass && - AUDIO_FUNC_PROTOCOL_CODE_UNDEF == desc_itf->bInterfaceProtocol, 0); + TU_VERIFY(TUSB_CLASS_AUDIO == desc_itf->bInterfaceClass && + AUDIO_SUBCLASS_CONTROL == desc_itf->bInterfaceSubClass && + AUDIO_FUNC_PROTOCOL_CODE_UNDEF == desc_itf->bInterfaceProtocol, 0); uint16_t drv_len = tu_desc_len(desc_itf); uint8_t const * p_desc = tu_desc_next(desc_itf); @@ -365,9 +384,9 @@ uint16_t midid_open(uint8_t rhport, tusb_desc_interface_t const * desc_itf, uint TU_VERIFY(TUSB_DESC_INTERFACE == tu_desc_type(p_desc), 0); tusb_desc_interface_t const * desc_midi = (tusb_desc_interface_t const *) p_desc; - TU_VERIFY(TUSB_CLASS_AUDIO == desc_midi->bInterfaceClass && - AUDIO_SUBCLASS_MIDI_STREAMING == desc_midi->bInterfaceSubClass && - AUDIO_FUNC_PROTOCOL_CODE_UNDEF == desc_midi->bInterfaceProtocol, 0); + TU_VERIFY(TUSB_CLASS_AUDIO == desc_midi->bInterfaceClass && + AUDIO_SUBCLASS_MIDI_STREAMING == desc_midi->bInterfaceSubClass && + AUDIO_FUNC_PROTOCOL_CODE_UNDEF == desc_midi->bInterfaceProtocol, 0); // Find available interface midid_interface_t * p_midi = NULL; diff --git a/src/class/midi/midi_device.h b/src/class/midi/midi_device.h index 1060fd77a..aaceaf62a 100644 --- a/src/class/midi/midi_device.h +++ b/src/class/midi/midi_device.h @@ -59,16 +59,28 @@ // Application API (Multiple Interfaces) // CFG_TUD_MIDI > 1 //--------------------------------------------------------------------+ + +// Check if midi interface is mounted bool tud_midi_n_mounted (uint8_t itf); + +// Get the number of bytes available for reading uint32_t tud_midi_n_available (uint8_t itf, uint8_t cable_num); + +// Read byte stream (legacy) uint32_t tud_midi_n_read (uint8_t itf, uint8_t cable_num, void* buffer, uint32_t bufsize); + +// Write byte Stream (legacy) uint32_t tud_midi_n_write (uint8_t itf, uint8_t cable_num, uint8_t const* buffer, uint32_t bufsize); +// Write good-old 3 bytes data, this use write packet static inline uint32_t tud_midi_n_write24 (uint8_t itf, uint8_t cable_num, uint8_t b1, uint8_t b2, uint8_t b3); -bool tud_midi_n_packet_read (uint8_t itf, uint8_t packet[4]); -bool tud_midi_n_packet_write (uint8_t itf, uint8_t const packet[4]); +// Read event packet (4 bytes) +bool tud_midi_n_packet_read (uint8_t itf, uint8_t packet[4]); + +// Write event packet (4 bytes) +bool tud_midi_n_packet_write (uint8_t itf, uint8_t const packet[4]); //--------------------------------------------------------------------+ // Application API (Single Interface) -- cgit v1.3.1 From 6b04efd443c3299131135849b736a2f2ce5877ac Mon Sep 17 00:00:00 2001 From: hathach Date: Fri, 2 Apr 2021 13:55:51 +0700 Subject: refactor midi stream read --- src/class/midi/midi_device.c | 51 +++++++++++++++++++++++++++++++++----------- 1 file changed, 39 insertions(+), 12 deletions(-) (limited to 'src') diff --git a/src/class/midi/midi_device.c b/src/class/midi/midi_device.c index cba1dcca0..14748f18b 100644 --- a/src/class/midi/midi_device.c +++ b/src/class/midi/midi_device.c @@ -39,6 +39,13 @@ // MACRO CONSTANT TYPEDEF //--------------------------------------------------------------------+ +typedef struct +{ + uint8_t buffer[4]; + uint8_t index; + uint8_t total; +}midid_stream_t; + typedef struct { uint8_t itf_num; @@ -57,12 +64,15 @@ typedef struct osal_mutex_def_t tx_ff_mutex; #endif + // For Stream read()/write() API // Messages are always 4 bytes long, queue them for reading and writing so the // callers can use the Stream interface with single-byte read/write calls. uint8_t write_buffer[4]; uint8_t write_buffer_length; uint8_t write_target_length; +// midid_stream_t stream_write; + uint8_t read_buffer[4]; uint8_t read_buffer_length; uint8_t read_target_length; @@ -129,26 +139,41 @@ uint32_t tud_midi_n_read(uint8_t itf, uint8_t cable_num, void* buffer, uint32_t // Fill empty buffer if ( midi->read_buffer_length == 0 ) { - if ( !tud_midi_n_packet_read(itf, midi->read_buffer) ) return 0; + TU_VERIFY(tud_midi_n_packet_read(itf, midi->read_buffer), 0); - uint8_t code_index = midi->read_buffer[0] & 0x0f; - // We always copy over the first byte. - uint8_t count = 1; - // Ignore subsequent bytes based on the code. - if ( code_index != 0x5 && code_index != 0xf ) + uint8_t const code_index = midi->read_buffer[0] & 0x0f; + uint8_t count; + + // MIDI 1.0 Table 4-1: Code Index Number Classifications + switch(code_index) { - count = 2; - if ( code_index != 0x2 && code_index != 0x6 && code_index != 0xc && code_index != 0xd ) - { + case MIDI_CIN_MISC: + case MIDI_CIN_CABLE_EVENT: + // These are reserved and unused, possibly issue somewhere, skip this packet + return 0; + break; + + case MIDI_CIN_SYSEX_END_1BYTE: + case MIDI_CIN_1BYTE_DATA: + count = 1; + break; + + case MIDI_CIN_SYSCOM_2BYTE : + case MIDI_CIN_SYSEX_END_2BYTE : + case MIDI_CIN_PROGRAM_CHANGE : + case MIDI_CIN_CHANNEL_PRESSURE : + count = 2; + break; + + default: count = 3; - } + break; } midi->read_buffer_length = count; } - uint32_t n = midi->read_buffer_length - midi->read_target_length; - if (bufsize < n) n = bufsize; + uint32_t n = tu_min32(midi->read_buffer_length - midi->read_target_length, bufsize); // Skip the header in the buffer memcpy(buffer, midi->read_buffer + 1 + midi->read_target_length, n); @@ -204,6 +229,8 @@ uint32_t tud_midi_n_write(uint8_t itf, uint8_t cable_num, uint8_t const* buffer, midid_interface_t* midi = &_midid_itf[itf]; TU_VERIFY(midi->itf_num, 0); +// midid_stream_t* stream = &midi->stream_write; + uint32_t written = 0; uint32_t i = 0; while ( i < bufsize ) -- cgit v1.3.1 From 08fe16840fcc39e4cb7c1f55fa56762427734753 Mon Sep 17 00:00:00 2001 From: hathach Date: Fri, 2 Apr 2021 14:26:55 +0700 Subject: refactor midi write into stream --- src/class/midi/midi_device.c | 77 +++++++++++++++++++++----------------------- 1 file changed, 37 insertions(+), 40 deletions(-) (limited to 'src') diff --git a/src/class/midi/midi_device.c b/src/class/midi/midi_device.c index 14748f18b..49bf2a27a 100644 --- a/src/class/midi/midi_device.c +++ b/src/class/midi/midi_device.c @@ -67,11 +67,7 @@ typedef struct // For Stream read()/write() API // Messages are always 4 bytes long, queue them for reading and writing so the // callers can use the Stream interface with single-byte read/write calls. - uint8_t write_buffer[4]; - uint8_t write_buffer_length; - uint8_t write_target_length; - -// midid_stream_t stream_write; + midid_stream_t stream_write; uint8_t read_buffer[4]; uint8_t read_buffer_length; @@ -229,7 +225,7 @@ uint32_t tud_midi_n_write(uint8_t itf, uint8_t cable_num, uint8_t const* buffer, midid_interface_t* midi = &_midid_itf[itf]; TU_VERIFY(midi->itf_num, 0); -// midid_stream_t* stream = &midi->stream_write; + midid_stream_t* stream = &midi->stream_write; uint32_t written = 0; uint32_t i = 0; @@ -237,93 +233,94 @@ uint32_t tud_midi_n_write(uint8_t itf, uint8_t cable_num, uint8_t const* buffer, { uint8_t const data = buffer[i]; - if ( midi->write_buffer_length == 0 ) + if ( stream->index == 0 ) { - // new packet + // new event packet uint8_t const msg = data >> 4; - midi->write_buffer[1] = data; - midi->write_buffer_length = 2; + + stream->index = 2; + stream->buffer[1] = data; // Check to see if we're still in a SysEx transmit. - if ( midi->write_buffer[0] == MIDI_CIN_SYSEX_START ) + if ( stream->buffer[0] == MIDI_CIN_SYSEX_START ) { if ( data == MIDI_STATUS_SYSEX_END ) { - midi->write_buffer[0] = MIDI_CIN_SYSEX_END_1BYTE; - midi->write_target_length = 2; + stream->buffer[0] = MIDI_CIN_SYSEX_END_1BYTE; + stream->total = 2; } else { - midi->write_target_length = 4; + stream->total = 4; } } else if ( (msg >= 0x8 && msg <= 0xB) || msg == 0xE ) { // Channel Voice Messages - midi->write_buffer[0] = (cable_num << 4) | msg; - midi->write_target_length = 4; + stream->buffer[0] = (cable_num << 4) | msg; + stream->total = 4; } else if ( msg == 0xf ) { // System message if ( data == MIDI_STATUS_SYSEX_START ) { - midi->write_buffer[0] = MIDI_CIN_SYSEX_START; - midi->write_target_length = 4; + stream->buffer[0] = MIDI_CIN_SYSEX_START; + stream->total = 4; } else if ( data == MIDI_STATUS_SYSCOM_TIME_CODE_QUARTER_FRAME || data == MIDI_STATUS_SYSCOM_SONG_SELECT ) { - midi->write_buffer[0] = MIDI_CIN_SYSCOM_2BYTE; - midi->write_target_length = 3; + stream->buffer[0] = MIDI_CIN_SYSCOM_2BYTE; + stream->total = 3; } else if ( data == MIDI_STATUS_SYSCOM_SONG_POSITION_POINTER ) { - midi->write_buffer[0] = MIDI_CIN_SYSCOM_3BYTE; - midi->write_target_length = 4; + stream->buffer[0] = MIDI_CIN_SYSCOM_3BYTE; + stream->total = 4; } else { - midi->write_buffer[0] = MIDI_CIN_SYSEX_END_1BYTE; - midi->write_target_length = 2; + stream->buffer[0] = MIDI_CIN_SYSEX_END_1BYTE; + stream->total = 2; } } else { // Pack individual bytes if we don't support packing them into words. - midi->write_buffer[0] = cable_num << 4 | 0xf; - midi->write_buffer[2] = 0; - midi->write_buffer[3] = 0; - midi->write_buffer_length = 2; - midi->write_target_length = 2; + stream->buffer[0] = cable_num << 4 | 0xf; + stream->buffer[2] = 0; + stream->buffer[3] = 0; + stream->index = 2; + stream->total = 2; } } else { - // On-going packet + // On-going (buffering) packet - TU_ASSERT(midi->write_buffer_length < 4, 0); - midi->write_buffer[midi->write_buffer_length] = data; - midi->write_buffer_length++; + TU_ASSERT(stream->index < 4, written); + stream->buffer[stream->index] = data; + stream->index++; // See if this byte ends a SysEx. - if ( midi->write_buffer[0] == MIDI_CIN_SYSEX_START && data == MIDI_STATUS_SYSEX_END ) + if ( stream->buffer[0] == MIDI_CIN_SYSEX_START && data == MIDI_STATUS_SYSEX_END ) { - midi->write_buffer[0] = MIDI_CIN_SYSEX_START + (midi->write_buffer_length - 1); - midi->write_target_length = midi->write_buffer_length; + stream->buffer[0] = MIDI_CIN_SYSEX_START + (stream->index - 1); + stream->total = stream->index; } } // Send out packet - if ( midi->write_buffer_length == midi->write_target_length ) + if ( stream->index == stream->total ) { // zeroes unused bytes - for(uint8_t idx = midi->write_target_length; idx < 4; idx++) midi->write_buffer[idx] = 0; + for(uint8_t idx = stream->total; idx < 4; idx++) stream->buffer[idx] = 0; - uint16_t const count = tu_fifo_write_n(&midi->tx_ff, midi->write_buffer, 4); + uint16_t const count = tu_fifo_write_n(&midi->tx_ff, stream->buffer, 4); // reset buffer - midi->write_buffer_length = midi->write_target_length = 0; + stream->index = stream->total = 0; // fifo overflow, here we assume FIFO is multiple of 4 and didn't check remaining before writing if ( count != 4 ) break; -- cgit v1.3.1 From 99b78e62f2172988ffa3835b7d6bcaaf455cef10 Mon Sep 17 00:00:00 2001 From: hathach Date: Fri, 2 Apr 2021 14:34:13 +0700 Subject: removed tud_midi_write24() --- src/class/midi/midi_device.h | 31 ++++++++++++++----------------- 1 file changed, 14 insertions(+), 17 deletions(-) (limited to 'src') diff --git a/src/class/midi/midi_device.h b/src/class/midi/midi_device.h index aaceaf62a..c875748fd 100644 --- a/src/class/midi/midi_device.h +++ b/src/class/midi/midi_device.h @@ -72,10 +72,6 @@ uint32_t tud_midi_n_read (uint8_t itf, uint8_t cable_num, void* buffer, ui // Write byte Stream (legacy) uint32_t tud_midi_n_write (uint8_t itf, uint8_t cable_num, uint8_t const* buffer, uint32_t bufsize); -// Write good-old 3 bytes data, this use write packet -static inline -uint32_t tud_midi_n_write24 (uint8_t itf, uint8_t cable_num, uint8_t b1, uint8_t b2, uint8_t b3); - // Read event packet (4 bytes) bool tud_midi_n_packet_read (uint8_t itf, uint8_t packet[4]); @@ -87,13 +83,26 @@ bool tud_midi_n_packet_write (uint8_t itf, uint8_t const packet[4]); //--------------------------------------------------------------------+ static inline bool tud_midi_mounted (void); static inline uint32_t tud_midi_available (void); + static inline uint32_t tud_midi_read (void* buffer, uint32_t bufsize); static inline uint32_t tud_midi_write (uint8_t cable_num, uint8_t const* buffer, uint32_t bufsize); -static inline uint32_t tud_midi_write24 (uint8_t cable_num, uint8_t b1, uint8_t b2, uint8_t b3); static inline bool tud_midi_packet_read (uint8_t packet[4]); static inline bool tud_midi_packet_write(uint8_t const packet[4]); +// TODO remove after 0.10.0 release +TU_ATTR_DEPRECATED("tud_midi_send() is renamed to tud_midi_packet_write()") +static inline bool tud_midi_send(uint8_t packet[4]) +{ + return tud_midi_packet_write(packet); +} + +TU_ATTR_DEPRECATED("tud_midi_receive() is renamed to tud_midi_packet_read()") +static inline bool tud_midi_receive(uint8_t packet[4]) +{ + return tud_midi_packet_read(packet); +} + //--------------------------------------------------------------------+ // Application Callback API (weak is optional) //--------------------------------------------------------------------+ @@ -103,12 +112,6 @@ TU_ATTR_WEAK void tud_midi_rx_cb(uint8_t itf); // Inline Functions //--------------------------------------------------------------------+ -static inline uint32_t tud_midi_n_write24 (uint8_t itf, uint8_t cable_num, uint8_t b1, uint8_t b2, uint8_t b3) -{ - uint8_t msg[3] = { b1, b2, b3 }; - return tud_midi_n_write(itf, cable_num, msg, 3); -} - static inline bool tud_midi_mounted (void) { return tud_midi_n_mounted(0); @@ -129,12 +132,6 @@ static inline uint32_t tud_midi_write (uint8_t cable_num, uint8_t const* buffer, return tud_midi_n_write(0, cable_num, buffer, bufsize); } -static inline uint32_t tud_midi_write24 (uint8_t cable_num, uint8_t b1, uint8_t b2, uint8_t b3) -{ - uint8_t msg[3] = { b1, b2, b3 }; - return tud_midi_write(cable_num, msg, 3); -} - static inline bool tud_midi_packet_read (uint8_t packet[4]) { return tud_midi_n_packet_read(0, packet); -- cgit v1.3.1 From da59c4ad4434b64691aa7a93e03381702633964d Mon Sep 17 00:00:00 2001 From: hathach Date: Fri, 2 Apr 2021 14:43:38 +0700 Subject: rename midi write()/read() to stream_write() stream_read() also add deprecated for warning and rename hint --- examples/device/dynamic_configuration/src/main.c | 6 ++- examples/device/midi_test/src/main.c | 4 +- src/class/midi/midi_device.c | 4 +- src/class/midi/midi_device.h | 55 +++++++++++++++--------- 4 files changed, 43 insertions(+), 26 deletions(-) (limited to 'src') diff --git a/examples/device/dynamic_configuration/src/main.c b/examples/device/dynamic_configuration/src/main.c index ce1f752d0..4c10f55b0 100644 --- a/examples/device/dynamic_configuration/src/main.c +++ b/examples/device/dynamic_configuration/src/main.c @@ -186,10 +186,12 @@ void midi_task(void) if (previous < 0) previous = sizeof(note_sequence) - 1; // Send Note On for current position at full velocity (127) on channel 1. - tud_midi_write24(cable_num, 0x90 | channel, note_sequence[note_pos], 127); + uint8_t note_on[3] = { 0x90 | channel, note_sequence[note_pos], 127 }; + tud_midi_stream_write(cable_num, note_on, 3); // Send Note Off for previous note. - tud_midi_write24(cable_num, 0x80 | channel, note_sequence[previous], 0); + uint8_t note_off[3] = { 0x80 | channel, note_sequence[previous], 0}; + tud_midi_stream_write(cable_num, note_off, 3); // Increment position note_pos++; diff --git a/examples/device/midi_test/src/main.c b/examples/device/midi_test/src/main.c index af10350df..9e0e82a10 100644 --- a/examples/device/midi_test/src/main.c +++ b/examples/device/midi_test/src/main.c @@ -147,11 +147,11 @@ void midi_task(void) // Send Note On for current position at full velocity (127) on channel 1. uint8_t note_on[3] = { 0x90 | channel, note_sequence[note_pos], 127 }; - tud_midi_write(cable_num, note_on, 3); + tud_midi_stream_write(cable_num, note_on, 3); // Send Note Off for previous note. uint8_t note_off[3] = { 0x80 | channel, note_sequence[previous], 0}; - tud_midi_write(cable_num, note_off, 3); + tud_midi_stream_write(cable_num, note_off, 3); // Increment position note_pos++; diff --git a/src/class/midi/midi_device.c b/src/class/midi/midi_device.c index 49bf2a27a..e76f01db2 100644 --- a/src/class/midi/midi_device.c +++ b/src/class/midi/midi_device.c @@ -127,7 +127,7 @@ uint32_t tud_midi_n_available(uint8_t itf, uint8_t cable_num) return tu_fifo_count(&_midid_itf[itf].rx_ff); } -uint32_t tud_midi_n_read(uint8_t itf, uint8_t cable_num, void* buffer, uint32_t bufsize) +uint32_t tud_midi_n_stream_read(uint8_t itf, uint8_t cable_num, void* buffer, uint32_t bufsize) { (void) cable_num; midid_interface_t* midi = &_midid_itf[itf]; @@ -220,7 +220,7 @@ static uint32_t write_flush(midid_interface_t* midi) } } -uint32_t tud_midi_n_write(uint8_t itf, uint8_t cable_num, uint8_t const* buffer, uint32_t bufsize) +uint32_t tud_midi_n_stream_write(uint8_t itf, uint8_t cable_num, uint8_t const* buffer, uint32_t bufsize) { midid_interface_t* midi = &_midid_itf[itf]; TU_VERIFY(midi->itf_num, 0); diff --git a/src/class/midi/midi_device.h b/src/class/midi/midi_device.h index c875748fd..67f03930c 100644 --- a/src/class/midi/midi_device.h +++ b/src/class/midi/midi_device.h @@ -61,36 +61,51 @@ //--------------------------------------------------------------------+ // Check if midi interface is mounted -bool tud_midi_n_mounted (uint8_t itf); +bool tud_midi_n_mounted (uint8_t itf); // Get the number of bytes available for reading -uint32_t tud_midi_n_available (uint8_t itf, uint8_t cable_num); +uint32_t tud_midi_n_available (uint8_t itf, uint8_t cable_num); -// Read byte stream (legacy) -uint32_t tud_midi_n_read (uint8_t itf, uint8_t cable_num, void* buffer, uint32_t bufsize); +// Read byte stream (legacy) +uint32_t tud_midi_n_stream_read (uint8_t itf, uint8_t cable_num, void* buffer, uint32_t bufsize); -// Write byte Stream (legacy) -uint32_t tud_midi_n_write (uint8_t itf, uint8_t cable_num, uint8_t const* buffer, uint32_t bufsize); +// Write byte Stream (legacy) +uint32_t tud_midi_n_stream_write (uint8_t itf, uint8_t cable_num, uint8_t const* buffer, uint32_t bufsize); -// Read event packet (4 bytes) -bool tud_midi_n_packet_read (uint8_t itf, uint8_t packet[4]); +// Read event packet (4 bytes) +bool tud_midi_n_packet_read (uint8_t itf, uint8_t packet[4]); -// Write event packet (4 bytes) -bool tud_midi_n_packet_write (uint8_t itf, uint8_t const packet[4]); +// Write event packet (4 bytes) +bool tud_midi_n_packet_write (uint8_t itf, uint8_t const packet[4]); //--------------------------------------------------------------------+ // Application API (Single Interface) //--------------------------------------------------------------------+ -static inline bool tud_midi_mounted (void); -static inline uint32_t tud_midi_available (void); +static inline bool tud_midi_mounted (void); +static inline uint32_t tud_midi_available (void); -static inline uint32_t tud_midi_read (void* buffer, uint32_t bufsize); -static inline uint32_t tud_midi_write (uint8_t cable_num, uint8_t const* buffer, uint32_t bufsize); +static inline uint32_t tud_midi_stream_read (void* buffer, uint32_t bufsize); +static inline uint32_t tud_midi_stream_write (uint8_t cable_num, uint8_t const* buffer, uint32_t bufsize); -static inline bool tud_midi_packet_read (uint8_t packet[4]); -static inline bool tud_midi_packet_write(uint8_t const packet[4]); +static inline bool tud_midi_packet_read (uint8_t packet[4]); +static inline bool tud_midi_packet_write (uint8_t const packet[4]); +//------------- Deprecated API name -------------// // TODO remove after 0.10.0 release + +TU_ATTR_DEPRECATED("tud_midi_read() is renamed to tud_midi_stream_read()") +static inline uint32_t tud_midi_read (void* buffer, uint32_t bufsize) +{ + return tud_midi_stream_read(buffer, bufsize); +} + +TU_ATTR_DEPRECATED("tud_midi_write() is renamed to tud_midi_stream_write()") +static inline uint32_t tud_midi_write(uint8_t cable_num, uint8_t const* buffer, uint32_t bufsize) +{ + return tud_midi_stream_write(cable_num, buffer, bufsize); +} + + TU_ATTR_DEPRECATED("tud_midi_send() is renamed to tud_midi_packet_write()") static inline bool tud_midi_send(uint8_t packet[4]) { @@ -122,14 +137,14 @@ static inline uint32_t tud_midi_available (void) return tud_midi_n_available(0, 0); } -static inline uint32_t tud_midi_read (void* buffer, uint32_t bufsize) +static inline uint32_t tud_midi_stream_read (void* buffer, uint32_t bufsize) { - return tud_midi_n_read(0, 0, buffer, bufsize); + return tud_midi_n_stream_read(0, 0, buffer, bufsize); } -static inline uint32_t tud_midi_write (uint8_t cable_num, uint8_t const* buffer, uint32_t bufsize) +static inline uint32_t tud_midi_stream_write (uint8_t cable_num, uint8_t const* buffer, uint32_t bufsize) { - return tud_midi_n_write(0, cable_num, buffer, bufsize); + return tud_midi_n_stream_write(0, cable_num, buffer, bufsize); } static inline bool tud_midi_packet_read (uint8_t packet[4]) -- cgit v1.3.1 From 350eb1127755f3ee0dd3dd186cc31e9492916a0c Mon Sep 17 00:00:00 2001 From: hathach Date: Fri, 2 Apr 2021 14:52:44 +0700 Subject: refactor midi read buffer to stream --- src/class/midi/midi_device.c | 39 ++++++++++++++++++--------------------- 1 file changed, 18 insertions(+), 21 deletions(-) (limited to 'src') diff --git a/src/class/midi/midi_device.c b/src/class/midi/midi_device.c index e76f01db2..a4cc104a8 100644 --- a/src/class/midi/midi_device.c +++ b/src/class/midi/midi_device.c @@ -68,10 +68,7 @@ typedef struct // Messages are always 4 bytes long, queue them for reading and writing so the // callers can use the Stream interface with single-byte read/write calls. midid_stream_t stream_write; - - uint8_t read_buffer[4]; - uint8_t read_buffer_length; - uint8_t read_target_length; + midid_stream_t stream_read; // Endpoint Transfer buffer CFG_TUSB_MEM_ALIGN uint8_t epout_buf[CFG_TUD_MIDI_EP_BUFSIZE]; @@ -131,14 +128,16 @@ uint32_t tud_midi_n_stream_read(uint8_t itf, uint8_t cable_num, void* buffer, ui { (void) cable_num; midid_interface_t* midi = &_midid_itf[itf]; + midid_stream_t* stream = &midi->stream_read; + + TU_VERIFY(bufsize, 0); - // Fill empty buffer - if ( midi->read_buffer_length == 0 ) + // Get new packet from fifo + if ( stream->total == 0 ) { - TU_VERIFY(tud_midi_n_packet_read(itf, midi->read_buffer), 0); + TU_VERIFY(tud_midi_n_packet_read(itf, stream->buffer), 0); - uint8_t const code_index = midi->read_buffer[0] & 0x0f; - uint8_t count; + uint8_t const code_index = stream->buffer[0] & 0x0f; // MIDI 1.0 Table 4-1: Code Index Number Classifications switch(code_index) @@ -151,34 +150,32 @@ uint32_t tud_midi_n_stream_read(uint8_t itf, uint8_t cable_num, void* buffer, ui case MIDI_CIN_SYSEX_END_1BYTE: case MIDI_CIN_1BYTE_DATA: - count = 1; + stream->total = 1; break; case MIDI_CIN_SYSCOM_2BYTE : case MIDI_CIN_SYSEX_END_2BYTE : case MIDI_CIN_PROGRAM_CHANGE : case MIDI_CIN_CHANNEL_PRESSURE : - count = 2; + stream->total = 2; break; default: - count = 3; + stream->total = 3; break; } - - midi->read_buffer_length = count; } - uint32_t n = tu_min32(midi->read_buffer_length - midi->read_target_length, bufsize); + uint32_t const n = tu_min32(stream->total - stream->index, bufsize); - // Skip the header in the buffer - memcpy(buffer, midi->read_buffer + 1 + midi->read_target_length, n); - midi->read_target_length += n; + // Skip the header (1st byte) in the buffer + memcpy(buffer, stream->buffer + 1 + stream->index, n); + stream->index += n; - if ( midi->read_target_length == midi->read_buffer_length ) + if ( stream->total == stream->index ) { - midi->read_buffer_length = 0; - midi->read_target_length = 0; + stream->index = 0; + stream->total = 0; } return n; -- cgit v1.3.1 From 48bb96f5072a173189d9076c5c2b1f5066327bf6 Mon Sep 17 00:00:00 2001 From: hathach Date: Fri, 2 Apr 2021 15:08:36 +0700 Subject: correct midi stream read behavior to read until user buffer is full or no more data from usb fifo --- src/class/midi/midi_device.c | 111 ++++++++++++++++++++++++------------------- 1 file changed, 62 insertions(+), 49 deletions(-) (limited to 'src') diff --git a/src/class/midi/midi_device.c b/src/class/midi/midi_device.c index a4cc104a8..9ccbb733c 100644 --- a/src/class/midi/midi_device.c +++ b/src/class/midi/midi_device.c @@ -52,6 +52,12 @@ typedef struct uint8_t ep_in; uint8_t ep_out; + // For Stream read()/write() API + // Messages are always 4 bytes long, queue them for reading and writing so the + // callers can use the Stream interface with single-byte read/write calls. + midid_stream_t stream_write; + midid_stream_t stream_read; + /*------------- From this point, data is not cleared by bus reset -------------*/ // FIFO tu_fifo_t rx_ff; @@ -64,12 +70,6 @@ typedef struct osal_mutex_def_t tx_ff_mutex; #endif - // For Stream read()/write() API - // Messages are always 4 bytes long, queue them for reading and writing so the - // callers can use the Stream interface with single-byte read/write calls. - midid_stream_t stream_write; - midid_stream_t stream_read; - // Endpoint Transfer buffer CFG_TUSB_MEM_ALIGN uint8_t epout_buf[CFG_TUD_MIDI_EP_BUFSIZE]; CFG_TUSB_MEM_ALIGN uint8_t epin_buf[CFG_TUD_MIDI_EP_BUFSIZE]; @@ -127,58 +127,71 @@ uint32_t tud_midi_n_available(uint8_t itf, uint8_t cable_num) uint32_t tud_midi_n_stream_read(uint8_t itf, uint8_t cable_num, void* buffer, uint32_t bufsize) { (void) cable_num; - midid_interface_t* midi = &_midid_itf[itf]; - midid_stream_t* stream = &midi->stream_read; - TU_VERIFY(bufsize, 0); - // Get new packet from fifo - if ( stream->total == 0 ) - { - TU_VERIFY(tud_midi_n_packet_read(itf, stream->buffer), 0); + uint8_t* buf8 = (uint8_t*) buffer; - uint8_t const code_index = stream->buffer[0] & 0x0f; + midid_interface_t* midi = &_midid_itf[itf]; + midid_stream_t* stream = &midi->stream_read; - // MIDI 1.0 Table 4-1: Code Index Number Classifications - switch(code_index) + uint32_t total_read = 0; + while( bufsize ) + { + // Get new packet from fifo, then set packet expected bytes + if ( stream->total == 0 ) { - case MIDI_CIN_MISC: - case MIDI_CIN_CABLE_EVENT: - // These are reserved and unused, possibly issue somewhere, skip this packet - return 0; - break; + // return if there is no more data from fifo + if ( !tud_midi_n_packet_read(itf, stream->buffer) ) return total_read; - case MIDI_CIN_SYSEX_END_1BYTE: - case MIDI_CIN_1BYTE_DATA: - stream->total = 1; - break; + uint8_t const code_index = stream->buffer[0] & 0x0f; - case MIDI_CIN_SYSCOM_2BYTE : - case MIDI_CIN_SYSEX_END_2BYTE : - case MIDI_CIN_PROGRAM_CHANGE : - case MIDI_CIN_CHANNEL_PRESSURE : - stream->total = 2; - break; + // MIDI 1.0 Table 4-1: Code Index Number Classifications + switch(code_index) + { + case MIDI_CIN_MISC: + case MIDI_CIN_CABLE_EVENT: + // These are reserved and unused, possibly issue somewhere, skip this packet + return 0; + break; + + case MIDI_CIN_SYSEX_END_1BYTE: + case MIDI_CIN_1BYTE_DATA: + stream->total = 1; + break; + + case MIDI_CIN_SYSCOM_2BYTE : + case MIDI_CIN_SYSEX_END_2BYTE : + case MIDI_CIN_PROGRAM_CHANGE : + case MIDI_CIN_CHANNEL_PRESSURE : + stream->total = 2; + break; - default: - stream->total = 3; - break; + default: + stream->total = 3; + break; + } } - } - uint32_t const n = tu_min32(stream->total - stream->index, bufsize); + // Copy data up to bufsize + uint32_t const count = tu_min32(stream->total - stream->index, bufsize); - // Skip the header (1st byte) in the buffer - memcpy(buffer, stream->buffer + 1 + stream->index, n); - stream->index += n; + // Skip the header (1st byte) in the buffer + memcpy(buf8, stream->buffer + 1 + stream->index, count); - if ( stream->total == stream->index ) - { - stream->index = 0; - stream->total = 0; + total_read += count; + stream->index += count; + buf8 += count; + bufsize -= count; + + // complete current event packet, reset stream + if ( stream->total == stream->index ) + { + stream->index = 0; + stream->total = 0; + } } - return n; + return total_read; } bool tud_midi_n_packet_read (uint8_t itf, uint8_t packet[4]) @@ -224,7 +237,7 @@ uint32_t tud_midi_n_stream_write(uint8_t itf, uint8_t cable_num, uint8_t const* midid_stream_t* stream = &midi->stream_write; - uint32_t written = 0; + uint32_t total_written = 0; uint32_t i = 0; while ( i < bufsize ) { @@ -296,7 +309,7 @@ uint32_t tud_midi_n_stream_write(uint8_t itf, uint8_t cable_num, uint8_t const* { // On-going (buffering) packet - TU_ASSERT(stream->index < 4, written); + TU_ASSERT(stream->index < 4, total_written); stream->buffer[stream->index] = data; stream->index++; @@ -316,14 +329,14 @@ uint32_t tud_midi_n_stream_write(uint8_t itf, uint8_t cable_num, uint8_t const* uint16_t const count = tu_fifo_write_n(&midi->tx_ff, stream->buffer, 4); - // reset buffer + // complete current event packet, reset stream stream->index = stream->total = 0; // fifo overflow, here we assume FIFO is multiple of 4 and didn't check remaining before writing if ( count != 4 ) break; // updated written if succeeded - written = i; + total_written = i; } i++; @@ -331,7 +344,7 @@ uint32_t tud_midi_n_stream_write(uint8_t itf, uint8_t cable_num, uint8_t const* write_flush(midi); - return written; + return total_written; } bool tud_midi_n_packet_write (uint8_t itf, uint8_t const packet[4]) -- cgit v1.3.1