From ae521bf95cd3949e9b7d7e83a1f4051c9c21a7c1 Mon Sep 17 00:00:00 2001 From: Yang Xijing <814370731@qq.com> Date: Sat, 4 Nov 2023 23:31:14 +0800 Subject: [PATCH] add nuvoton port(not release) --- port/nuvoton/README.md | 14 ++ port/nuvoton/usb_dc_usbfs.c | 454 ++++++++++++++++++++++++++++++++++++ 2 files changed, 468 insertions(+) create mode 100644 port/nuvoton/README.md create mode 100644 port/nuvoton/usb_dc_usbfs.c diff --git a/port/nuvoton/README.md b/port/nuvoton/README.md new file mode 100644 index 00000000..1198c574 --- /dev/null +++ b/port/nuvoton/README.md @@ -0,0 +1,14 @@ +# Note + +## Support Chip List + +- M032 Series +- M480 Series + +## Before Use + +Configure USBD_EPNUM. +Your should implement `usb_dc_low_level_init` and `usb_dc_low_level_deinit`. +- Enable or disable USB clock and set USB clock for 48M. +- Enable or disable gpio and gpio clk for usb dp and dm. +- Enable or disable usb irq diff --git a/port/nuvoton/usb_dc_usbfs.c b/port/nuvoton/usb_dc_usbfs.c new file mode 100644 index 00000000..cb2b5975 --- /dev/null +++ b/port/nuvoton/usb_dc_usbfs.c @@ -0,0 +1,454 @@ +#include +#include "NuMicro.h" +#include "usbd_core.h" + +#ifndef USBD_IRQHandler +#define USBD_IRQHandler USBD_IRQHandler +#endif + +#ifndef USBD_EPNUM +#define USBD_EPNUM 8 +#endif +#define USB_NUM_BIDIR_ENDPOINTS (USBD_EPNUM >> 1) + +#define USBD_EP_GET_CONFIG(ep) (*((__IO uint32_t *)((uint32_t)&USBD->EP[0].CFG + (uint32_t)((ep) << 4)))) + +/* Define EP maximum packet size */ +#define DEFAULT_EP_MAX_PKT_SIZE 64 + +#define EP0_MAX_PKT_SIZE DEFAULT_EP_MAX_PKT_SIZE +#define EP1_MAX_PKT_SIZE DEFAULT_EP_MAX_PKT_SIZE +#define EP2_MAX_PKT_SIZE DEFAULT_EP_MAX_PKT_SIZE +#define EP3_MAX_PKT_SIZE DEFAULT_EP_MAX_PKT_SIZE +#define EP4_MAX_PKT_SIZE DEFAULT_EP_MAX_PKT_SIZE +#define EP5_MAX_PKT_SIZE DEFAULT_EP_MAX_PKT_SIZE +#define EP6_MAX_PKT_SIZE DEFAULT_EP_MAX_PKT_SIZE +#define EP7_MAX_PKT_SIZE DEFAULT_EP_MAX_PKT_SIZE +#define EP8_MAX_PKT_SIZE DEFAULT_EP_MAX_PKT_SIZE +#define EP9_MAX_PKT_SIZE DEFAULT_EP_MAX_PKT_SIZE +#define EP10_MAX_PKT_SIZE DEFAULT_EP_MAX_PKT_SIZE +#define EP11_MAX_PKT_SIZE DEFAULT_EP_MAX_PKT_SIZE + +#define SETUP_BUF_BASE 0 +#define SETUP_BUF_LEN 8 +#define EP0_BUF_BASE (SETUP_BUF_BASE + SETUP_BUF_LEN) +#define EP0_BUF_LEN EP0_MAX_PKT_SIZE +#define EP1_BUF_BASE (SETUP_BUF_BASE + SETUP_BUF_LEN) +#define EP1_BUF_LEN EP1_MAX_PKT_SIZE +#define EP2_BUF_BASE (EP1_BUF_BASE + EP1_BUF_LEN) +#define EP2_BUF_LEN EP2_MAX_PKT_SIZE +#define EP3_BUF_BASE (EP2_BUF_BASE + EP2_BUF_LEN) +#define EP3_BUF_LEN EP3_MAX_PKT_SIZE +#define EP4_BUF_BASE (EP3_BUF_BASE + EP3_BUF_LEN) +#define EP4_BUF_LEN EP4_MAX_PKT_SIZE +#define EP5_BUF_BASE (EP4_BUF_BASE + EP4_BUF_LEN) +#define EP5_BUF_LEN EP5_MAX_PKT_SIZE +#if USBD_EPNUM >= 8 +#define EP6_BUF_BASE (EP5_BUF_BASE + EP5_BUF_LEN) +#define EP6_BUF_LEN EP6_MAX_PKT_SIZE +#define EP7_BUF_BASE (EP6_BUF_BASE + EP6_BUF_LEN) +#define EP7_BUF_LEN EP7_MAX_PKT_SIZE +#if USBD_EPNUM >= 10 +#define EP8_BUF_BASE (EP7_BUF_BASE + EP7_BUF_LEN) +#define EP8_BUF_LEN EP8_MAX_PKT_SIZE +#define EP9_BUF_BASE (EP8_BUF_BASE + EP8_BUF_LEN) +#define EP9_BUF_LEN EP9_MAX_PKT_SIZE +#if USBD_EPNUM >= 12 +#define EP10_BUF_BASE (EP9_BUF_BASE + EP9_BUF_LEN) +#define EP10_BUF_LEN EP10_MAX_PKT_SIZE +#define EP11_BUF_BASE (EP10_BUF_BASE + EP10_BUF_LEN) +#define EP11_BUF_LEN EP11_MAX_PKT_SIZE +#endif +#endif +#endif + +#define USBD_EPNUM_FROM_IN_EPIDX(ep_idx) ((ep_idx) << 1) +#define USBD_EPNUM_FROM_OUT_EPIDX(ep_idx) (((ep_idx) << 1) + 1) +#define USBD_EPNUM_FROM_EPADDR(ep_addr) \ + (USB_EP_DIR_IS_IN(ep_addr) ? USBD_EPNUM_FROM_IN_EPIDX(USB_EP_GET_IDX(ep_addr)) : USBD_EPNUM_FROM_OUT_EPIDX(USB_EP_GET_IDX(ep_addr))) + +/* Endpoint state */ +struct usb_dc_ep_state { + uint16_t ep_mps; /* Endpoint max packet size */ + uint8_t ep_type; /* Endpoint type */ + uint8_t ep_stalled; /* Endpoint stall flag */ + uint8_t ep_enable; /* Endpoint enable */ + uint8_t *xfer_buf; + uint32_t xfer_len; + uint32_t actual_xfer_len; + uint32_t mps_xfer_len; +}; + +/* Driver state */ +struct usb_dc_config_priv { + volatile uint8_t dev_addr; + struct usb_dc_ep_state in_ep[USB_NUM_BIDIR_ENDPOINTS]; /*!< IN endpoint parameters*/ + struct usb_dc_ep_state out_ep[USB_NUM_BIDIR_ENDPOINTS]; /*!< OUT endpoint parameters */ +} g_nuvoton_udc; + +static uint8_t usdb_set_address_flag = 0; +static uint8_t usbd_out_toggle[USB_NUM_BIDIR_ENDPOINTS] = { 0 }; + +__WEAK void usb_dc_low_level_init(void) +{ +} + +__WEAK void usb_dc_low_level_deinit(void) +{ +} + +int usb_dc_init(void) +{ + memset(&g_nuvoton_udc, 0, sizeof(g_nuvoton_udc)); + + usb_dc_low_level_init(); + + /*****************************************************/ + /* Initial USB engine */ + USBD->ATTR = 0x6D0ul; + /* Force SE0 */ + USBD_SET_SE0(); + + /*****************************************************/ + /* Init setup packet buffer */ + /* Buffer for setup packet -> [0 ~ 0x7] */ + USBD->STBUFSEG = SETUP_BUF_BASE; + + USBD_SET_EP_BUF_ADDR(EP0, EP0_BUF_BASE); + USBD_SET_EP_BUF_ADDR(EP1, EP1_BUF_BASE); + USBD_SET_EP_BUF_ADDR(EP2, EP2_BUF_BASE); + USBD_SET_EP_BUF_ADDR(EP3, EP3_BUF_BASE); + USBD_SET_EP_BUF_ADDR(EP4, EP4_BUF_BASE); + USBD_SET_EP_BUF_ADDR(EP5, EP5_BUF_BASE); +#if USBD_EPNUM >= 8 + USBD_SET_EP_BUF_ADDR(EP6, EP6_BUF_BASE); + USBD_SET_EP_BUF_ADDR(EP7, EP7_BUF_BASE); +#if USBD_EPNUM >= 10 + USBD_SET_EP_BUF_ADDR(EP8, EP8_BUF_BASE); + USBD_SET_EP_BUF_ADDR(EP9, EP9_BUF_BASE); + USBD_SET_EP_BUF_ADDR(EP10, EP10_BUF_BASE); +#if USBD_EPNUM >= 12 + USBD_SET_EP_BUF_ADDR(EP11, EP11_BUF_BASE); +#endif +#endif +#endif + + /*****************************************************/ + /* USB start */ + /* Disable software-disconnect function */ + USBD_CLR_SE0(); + USBD->ATTR = 0x7D0ul; + + /* Clear USB-related interrupts before enable interrupt */ + USBD_CLR_INT_FLAG(USBD_INT_BUS | USBD_INT_USB | USBD_INT_FLDET | USBD_INT_WAKEUP); + + /* Enable USB-related interrupts. */ + USBD_ENABLE_INT(USBD_INT_BUS | USBD_INT_USB | USBD_INT_FLDET | USBD_INT_WAKEUP); + /*****************************************************/ + + return 0; +} + +int usb_dc_deinit(void) +{ + USBD->ATTR = 0x00000040; + /* Force SE0 */ + USBD_SET_SE0(); + + return 0; +} + +int usbd_set_address(const uint8_t addr) +{ + uint8_t usbd_addr = USBD_GET_ADDR(); + if ((usbd_addr == 0) && (usbd_addr != addr)) { + g_nuvoton_udc.dev_addr = addr; + usdb_set_address_flag = 1; + } + + return 0; +} + +uint8_t usbd_get_port_speed(const uint8_t port) +{ + return USB_SPEED_FULL; +} + +int usbd_ep_open(const struct usbd_endpoint_cfg *ep_cfg) +{ + uint8_t ep_idx = USB_EP_GET_IDX(ep_cfg->ep_addr); + + if (USB_EP_DIR_IS_IN(ep_cfg->ep_addr)) { + uint8_t epnum = USBD_EPNUM_FROM_IN_EPIDX(ep_idx); + + g_nuvoton_udc.in_ep[ep_idx].ep_mps = ep_cfg->ep_mps; + g_nuvoton_udc.in_ep[ep_idx].ep_type = ep_cfg->ep_type; + g_nuvoton_udc.in_ep[ep_idx].ep_enable = true; + if (ep_idx == 0) { + /* EP0 ==> control IN endpoint, address 0 */ + USBD_CONFIG_EP(EP0, USBD_CFG_CSTALL | USBD_CFG_EPMODE_IN | 0); + } else { + USBD_CONFIG_EP(epnum, USBD_CFG_EPMODE_IN | ep_idx); + USBD_STOP_TRANSACTION(epnum); + } + } else { + uint8_t epnum = USBD_EPNUM_FROM_OUT_EPIDX(ep_idx); + + g_nuvoton_udc.out_ep[ep_idx].ep_mps = ep_cfg->ep_mps; + g_nuvoton_udc.out_ep[ep_idx].ep_type = ep_cfg->ep_type; + g_nuvoton_udc.out_ep[ep_idx].ep_enable = true; + if (ep_idx == 0) { + /* EP1 ==> control OUT endpoint, address 0 */ + USBD_CONFIG_EP(EP1, USBD_CFG_CSTALL | USBD_CFG_EPMODE_OUT | 0); + } else { + USBD_CONFIG_EP(epnum, USBD_CFG_EPMODE_OUT | ep_idx); + USBD_STOP_TRANSACTION(epnum); + } + } + + return 0; +} + +int usbd_ep_close(const uint8_t ep) +{ + USBD->EP[USBD_EPNUM_FROM_EPADDR(ep)].CFG &= ~USBD_CFG_STATE_Msk; // disable endpoint + return 0; +} + +int usbd_ep_set_stall(const uint8_t ep) +{ + USBD_SET_EP_STALL(USBD_EPNUM_FROM_EPADDR(ep)); + return 0; +} + +int usbd_ep_clear_stall(const uint8_t ep) +{ + USBD_CLR_EP_STALL(USBD_EPNUM_FROM_EPADDR(ep)); + return 0; +} + +int usbd_ep_is_stalled(const uint8_t ep, uint8_t *stalled) +{ + *stalled = USBD_GET_EP_STALL(USBD_EPNUM_FROM_EPADDR(ep)) > 0 ? 1 : 0; + return 0; +} + +int usbd_ep_start_write(const uint8_t ep, const uint8_t *data, uint32_t data_len) +{ + uint8_t ep_idx = USB_EP_GET_IDX(ep); + + if (!data && data_len) { + return -1; + } + if (!g_nuvoton_udc.in_ep[ep_idx].ep_enable) { + return -2; + } + + uint8_t epnum = USBD_EPNUM_FROM_IN_EPIDX(ep); + + g_nuvoton_udc.in_ep[ep_idx].xfer_buf = (uint8_t *)data; + g_nuvoton_udc.in_ep[ep_idx].xfer_len = data_len; + g_nuvoton_udc.in_ep[ep_idx].actual_xfer_len = 0; + + if (data_len > g_nuvoton_udc.in_ep[ep_idx].ep_mps) { + data_len = g_nuvoton_udc.in_ep[ep_idx].ep_mps; + } + + if (epnum == 0) { + USBD_SET_DATA1(epnum); + } + + USBD_MemCopy((uint8_t *)(USBD_BUF_BASE + USBD_GET_EP_BUF_ADDR(epnum)), (uint8_t *)data, data_len); + USBD_SET_PAYLOAD_LEN(epnum, data_len); + + return 0; +} + +int usbd_ep_start_read(const uint8_t ep, uint8_t *data, uint32_t data_len) +{ + uint8_t ep_idx = USB_EP_GET_IDX(ep); + + if (!data && data_len) { + return -1; + } + if (!g_nuvoton_udc.out_ep[ep_idx].ep_enable) { + return -2; + } + + uint8_t epnum = USBD_EPNUM_FROM_OUT_EPIDX(ep); + + g_nuvoton_udc.out_ep[ep_idx].xfer_buf = (uint8_t *)data; + g_nuvoton_udc.out_ep[ep_idx].xfer_len = data_len; + g_nuvoton_udc.out_ep[ep_idx].actual_xfer_len = 0; + + if (g_nuvoton_udc.out_ep[ep_idx].xfer_len < g_nuvoton_udc.out_ep[ep_idx].ep_mps) { + g_nuvoton_udc.out_ep[ep_idx].mps_xfer_len = g_nuvoton_udc.out_ep[ep_idx].xfer_len; + } else { + g_nuvoton_udc.out_ep[ep_idx].mps_xfer_len = g_nuvoton_udc.out_ep[ep_idx].ep_mps; + } + + USBD_SET_PAYLOAD_LEN(epnum, g_nuvoton_udc.out_ep[ep_idx].mps_xfer_len); + + return 0; +} + +void USBD_IRQHandler(void) +{ + uint32_t int_flag = USBD_GET_INT_FLAG(); + uint32_t bus_state = USBD_GET_BUS_STATE(); + + if (int_flag & USBD_INTSTS_FLDET) { + // Floating detect + USBD_CLR_INT_FLAG(USBD_INTSTS_FLDET); + + if (USBD_IS_ATTACHED()) { + /* USB Plug In */ + USBD_ENABLE_USB(); + usbd_event_connect_handler(); + } else { + /* USB Un-plug */ + USBD_DISABLE_USB(); + usbd_event_disconnect_handler(); + } + } + + //------------------------------------------------------------------ + if (int_flag & USBD_INTSTS_BUS) { + /* Clear event flag */ + USBD_CLR_INT_FLAG(USBD_INTSTS_BUS); + + if (bus_state & USBD_STATE_USBRST) { + /* Bus reset */ + USBD_ENABLE_USB(); + + memset((usbd_out_toggle + 1), 0, (USB_NUM_BIDIR_ENDPOINTS - 1)); + + for (uint8_t i = 0; i < USBD_MAX_EP; i++) { + USBD->EP[i].CFG = 0; // default value + } + + USBD_SET_ADDR(0ul); + g_nuvoton_udc.dev_addr = 0; + + usbd_event_reset_handler(); + } + + if (bus_state & USBD_STATE_SUSPEND) { + /* Enable USB but disable PHY */ + USBD_DISABLE_PHY(); + usbd_event_suspend_handler(); + } + if (bus_state & USBD_STATE_RESUME) { + /* Enable USB and enable PHY */ + USBD_ENABLE_USB(); + usbd_event_resume_handler(); + } + } + + //------------------------------------------------------------------ + if (int_flag & USBD_INTSTS_WAKEUP) { + /* Clear event flag */ + USBD_CLR_INT_FLAG(USBD_INTSTS_WAKEUP); + } + + if (int_flag & USBD_INTSTS_USB) { + // USB event + if (int_flag & USBD_INTSTS_SETUP) { + // Setup packet + /* Clear event flag */ + USBD_CLR_INT_FLAG(USBD_INTSTS_SETUP); + + /* Clear the data IN/OUT ready flag of control end-points */ + USBD_STOP_TRANSACTION(EP0); + USBD_STOP_TRANSACTION(EP1); + + usbd_out_toggle[0] = 0; + usbd_event_ep0_setup_complete_handler((uint8_t *)(USBD_BUF_BASE)); + } + + if (int_flag & USBD_INTSTS_EP0) { + /* In ACK for Set address */ + if (usdb_set_address_flag == 1) { + USBD_SET_ADDR(g_nuvoton_udc.dev_addr); + usdb_set_address_flag = 0; + } + } + + // if (int_flag & USBD_INTSTS_EP1) + // { + // } + + for (uint8_t epnum = 0; epnum < USBD_EPNUM; epnum++) { + if (int_flag & (USBD_INTSTS_EP0 << epnum)) { + USBD_CLR_INT_FLAG((USBD_INTSTS_EP0 << epnum)); + + uint8_t ep_cfg = USBD_EP_GET_CONFIG(epnum); + + uint8_t ep_state = 0; +#if USBD_EPNUM >= 10 + if (epnum > 7) { + ep_state = (USBD->EPSTS1 >> ((epnum - 8) * 4)) & 0x0f; + } else +#endif + { + ep_state = (USBD->EPSTS0 >> (epnum * 4)) & 0x0f; + } + + uint8_t ep_cfg_state = (ep_cfg & USBD_CFG_STATE_Msk) >> USBD_CFG_STATE_Pos; + + if (ep_cfg_state == 0x01) { + // OUT + uint8_t ep_idx = ep_cfg & USBD_CFG_EPNUM_Msk; + + if (ep_state == usbd_out_toggle[ep_idx]) { + USBD_SET_PAYLOAD_LEN(epnum, g_nuvoton_udc.out_ep[ep_idx].ep_mps); + } else { + uint32_t recv_count = USBD_GET_PAYLOAD_LEN(epnum); + + USBD_MemCopy((uint8_t *)g_nuvoton_udc.out_ep[ep_idx].xfer_buf, + (uint8_t *)(USBD_BUF_BASE + USBD_GET_EP_BUF_ADDR(epnum)), recv_count); + + g_nuvoton_udc.out_ep[ep_idx].xfer_buf += recv_count; + g_nuvoton_udc.out_ep[ep_idx].xfer_len -= recv_count; + g_nuvoton_udc.out_ep[ep_idx].actual_xfer_len += recv_count; + + usbd_out_toggle[ep_idx] = ep_state; + + if ((recv_count < g_nuvoton_udc.out_ep[ep_idx].ep_mps) || + (g_nuvoton_udc.out_ep[ep_idx].xfer_len == 0)) { + usbd_event_ep_out_complete_handler(ep_idx, g_nuvoton_udc.out_ep[ep_idx].actual_xfer_len); + } else { + if (g_nuvoton_udc.out_ep[ep_idx].xfer_len < g_nuvoton_udc.out_ep[ep_idx].ep_mps) { + g_nuvoton_udc.out_ep[ep_idx].mps_xfer_len = g_nuvoton_udc.out_ep[ep_idx].xfer_len; + } else { + g_nuvoton_udc.out_ep[ep_idx].mps_xfer_len = g_nuvoton_udc.out_ep[ep_idx].ep_mps; + } + + USBD_SET_PAYLOAD_LEN(epnum, g_nuvoton_udc.out_ep[ep_idx].mps_xfer_len); + } + } + } else if (ep_cfg_state == 0x02) { + uint8_t ep_idx = ep_cfg & USBD_CFG_EPNUM_Msk; + // In Ack + + if (g_nuvoton_udc.in_ep[ep_idx].xfer_len > g_nuvoton_udc.in_ep[ep_idx].ep_mps) { + g_nuvoton_udc.in_ep[ep_idx].xfer_buf += g_nuvoton_udc.in_ep[ep_idx].ep_mps; + g_nuvoton_udc.in_ep[ep_idx].xfer_len -= g_nuvoton_udc.in_ep[ep_idx].ep_mps; + g_nuvoton_udc.in_ep[ep_idx].actual_xfer_len += g_nuvoton_udc.in_ep[ep_idx].ep_mps; + + uint16_t min_len = MIN(g_nuvoton_udc.in_ep[ep_idx].xfer_len, g_nuvoton_udc.in_ep[ep_idx].ep_mps); + + uint8_t *usbd_ep_buf_addr = (uint8_t *)(USBD_BUF_BASE + USBD_GET_EP_BUF_ADDR(epnum)); + USBD_MemCopy(usbd_ep_buf_addr, g_nuvoton_udc.in_ep[ep_idx].xfer_buf, min_len); + USBD_SET_PAYLOAD_LEN(epnum, min_len); + } else { + g_nuvoton_udc.in_ep[ep_idx].actual_xfer_len += g_nuvoton_udc.in_ep[ep_idx].xfer_len; + g_nuvoton_udc.in_ep[ep_idx].xfer_len = 0; + + usbd_event_ep_in_complete_handler(ep_idx | 0x80, g_nuvoton_udc.in_ep[ep_idx].actual_xfer_len); + } + } + } + } + } +}