You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

508 lines
14 KiB

#include "gd32f10x.h"
#include "usbd_core.h"
#include "tusb.h"
#include "usbd.h"
static uint32_t g_interrupt_mask = 0U;
static const usbd_epkind_enum buf_kind = ENDP_SNG_BUF; /*!< single buffer endpoint type value */
/* device endpoints */
static usb_ep_struct in_ep[EP_COUNT]; /*!< the in direction endpoints */
static usb_ep_struct out_ep[EP_COUNT]; /*!< the out direction endpoints */
static void rcu_config(void)
{
/* enable USB pull-up pin clock */
rcu_periph_clock_enable(RCU_GPIO_PULLUP);
rcu_periph_clock_enable(RCU_PMU);
/* configure USB model clock from PLL clock */
rcu_usb_clock_config(RCU_CKUSB_CKPLL_DIV2);
/* enable USB APB1 clock */
rcu_periph_clock_enable(RCU_USBD);
}
static void gpio_config(void)
{
/* configure usb pull-up pin */
gpio_init(USB_PULLUP, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, USB_PULLUP_PIN);
}
void dcd_init(uint8_t rhport)
{
rcu_config();
gpio_config();
/* just reset the CLOSE bit */
USBD_REG_SET(USBD_CTL, CTL_SETRST);
/* may be need wait some time(tSTARTUP) ... */
/* clear SETRST bit in USBD_CTL register */
USBD_REG_SET(USBD_CTL, 0U);
/* clear all pending interrupts */
USBD_REG_SET(USBD_INTF, 0U);
/* set allocation buffer address */
USBD_REG_SET(USBD_BADDR, BUFFER_ADDRESS & 0xFFF8U);
g_interrupt_mask = IER_MASK;
#ifdef LPM_ENABLED
/* enable L1REQ interrupt */
USBD_REG_SET(USBD_LPMCS, LPMCS_LPMACK | LPMCS_LPMEN);
#endif /* LPM_ENABLED */
/* enable all interrupts mask bits */
USBD_REG_SET(USBD_CTL, g_interrupt_mask);
}
void dcd_int_enable(uint8_t rhport)
{
/* enable the USB low priority interrupt */
nvic_irq_enable(USBD_LP_CAN0_RX0_IRQn, 1, 0);
}
void dcd_int_disable(uint8_t rhport)
{
/* enable the USB low priority interrupt */
nvic_irq_disable(USBD_LP_CAN0_RX0_IRQn);
}
void dcd_set_address(uint8_t rhport, uint8_t dev_addr)
{
USBD_REG_SET(USBD_DADDR, DADDR_USBEN | dev_addr);
}
void dcd_remote_wakeup(uint8_t rhport)
{
}
void dcd_connect(uint8_t rhport)
{
gpio_bit_set(USB_PULLUP, USB_PULLUP_PIN);
}
void dcd_disconnect(uint8_t rhport)
{
gpio_bit_reset(USB_PULLUP, USB_PULLUP_PIN);
}
bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * desc_ep)
{
uint8_t ep_num = desc_ep->bEndpointAddress & 0x0FU;
uint32_t reg_value = 0;
/* set the endpoint type */
switch (desc_ep->bmAttributes.xfer) {
case TUSB_XFER_CONTROL:
reg_value = EP_CONTROL;
break;
case TUSB_XFER_BULK:
reg_value = EP_BULK;
break;
case TUSB_XFER_INTERRUPT:
reg_value = EP_INTERRUPT;
break;
case TUSB_XFER_ISOCHRONOUS:
reg_value = EP_ISO;
break;
default:
break;
}
USBD_REG_SET(USBD_EPxCS(ep_num), reg_value | ep_num);
reg_value = desc_ep->wMaxPacketSize.size;
if (desc_ep->bEndpointAddress >> 7U) {
usb_ep_struct *ep = &in_ep[ep_num];
ep->maxpacket = reg_value;
/* set the endpoint transmit buffer address */
(pbuf_reg + ep_num)->tx_addr = (uint16_t)g_free_buf_addr;
reg_value = (reg_value + 1U) & ~1U;
g_free_buf_addr += reg_value;
if (ENDP_DBL_BUF == buf_kind) {
USBD_ENDP_DOUBLE_BUF_SET(ep_num);
(pbuf_reg + ep_num)->rx_addr = (uint16_t)g_free_buf_addr;
g_free_buf_addr += reg_value;
USBD_ENDP_TX_STATUS_SET(ep_num, EPTX_VALID);
USBD_ENDP_RX_STATUS_SET(ep_num, EPRX_DISABLED);
} else {
/* configure the endpoint status as NAK status */
USBD_ENDP_TX_STATUS_SET(ep_num, EPTX_NAK);
}
} else {
usb_ep_struct *ep = &out_ep[ep_num];
ep->maxpacket = reg_value;
if (ENDP_DBL_BUF == buf_kind) {
USBD_ENDP_DOUBLE_BUF_SET(ep_num);
USBD_DTG_TX_TOGGLE(ep_num);
/* set the endpoint transmit buffer address */
(pbuf_reg + ep_num)->tx_addr = (uint16_t)g_free_buf_addr;
if (reg_value > 62U) {
reg_value = (reg_value + 31U) & ~31U;
(pbuf_reg + ep_num)->tx_count = (uint16_t)(((reg_value << 5U) - 1U) | 0x8000U);
} else {
reg_value = (reg_value + 1U) & ~1U;
(pbuf_reg + ep_num)->tx_count = (uint16_t)(reg_value << 9U);
}
g_free_buf_addr += reg_value;
}
reg_value = desc_ep->wMaxPacketSize.size;
/* set the endpoint receive buffer address */
(pbuf_reg + ep_num)->rx_addr = (uint16_t)g_free_buf_addr;
if (reg_value > 62U) {
reg_value = (reg_value + 31U) & ~31U;
(pbuf_reg + ep_num)->rx_count = (uint16_t)(((reg_value << 5U) - 1U) | 0x8000U);
} else {
reg_value = (reg_value + 1U) & ~1U;
(pbuf_reg + ep_num)->rx_count = (uint16_t)(reg_value << 9U);
}
if (ENDP_DBL_BUF == buf_kind) {
USBD_ENDP_RX_STATUS_SET(ep_num, EPRX_DISABLED);
USBD_ENDP_TX_STATUS_SET(ep_num, EPTX_NAK);
} else {
/* configure the endpoint status as NAK status */
USBD_ENDP_RX_STATUS_SET(ep_num, EPRX_NAK);
}
}
return true;
}
static void __ep_rx (uint8_t ep_addr, uint8_t *pbuf, uint16_t buf_len)
{
usb_ep_struct *ep;
uint8_t ep_num = tu_edpt_number(ep_addr);
ep = &out_ep[ep_num];
/* configure the transaction level parameters */
ep->trs_buf = pbuf;
ep->trs_len = buf_len;
/* enable endpoint to receive */
USBD_ENDP_RX_STATUS_SET(ep_num, EPRX_VALID);
}
static void __ep_tx (uint8_t ep_addr, uint8_t *pbuf, uint16_t buf_len)
{
__IO uint32_t len = 0U;
uint8_t ep_num = tu_edpt_number(ep_addr);
usb_ep_struct *ep = &in_ep[ep_num];
/* configure the transaction level parameters */
ep->trs_buf = pbuf;
ep->trs_len = buf_len;
ep->trs_count = 0U;
/* transmit length is more than one packet */
if (ep->trs_len > ep->maxpacket) {
len = ep->maxpacket;
} else {
len = ep->trs_len;
}
usbd_ep_data_write(ep->trs_buf, (pbuf_reg + ep_num)->tx_addr, (uint16_t)len);
(pbuf_reg + ep_num)->tx_count = (uint16_t)len;
/* enable endpoint to transmit */
USBD_ENDP_TX_STATUS_SET(ep_num, EPTX_VALID);
}
bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes)
{
uint8_t const dir = tu_edpt_dir(ep_addr);
if (dir == TUSB_DIR_IN) {
__ep_tx(ep_addr, buffer, total_bytes);
} else {
__ep_rx(ep_addr, buffer, total_bytes);
}
return true;
}
void dcd_edpt_stall (uint8_t rhport, uint8_t ep_addr)
{
uint8_t ep_num = tu_edpt_number(ep_addr);
usb_ep_struct *ep;
if (ep_addr >> 7U) {
ep = &in_ep[ep_num];
USBD_ENDP_TX_STATUS_SET(ep_num, EPTX_STALL);
} else {
ep = &out_ep[ep_num];
USBD_ENDP_RX_STATUS_SET(ep_num, EPRX_STALL);
}
ep->stall = 1U;
if (0U == ep_num) {
/* control endpoint need to be stalled in two directions */
USBD_ENDP_RX_TX_STATUS_SET(ep_num, EPRX_STALL, EPTX_STALL);
}
}
void dcd_edpt_clear_stall (uint8_t rhport, uint8_t ep_addr)
{
uint8_t ep_num = tu_edpt_number(ep_addr);
usb_ep_struct *ep;
if (ep_addr >> 7U) {
ep = &in_ep[ep_num];
/* clear endpoint data toggle bit */
USBD_DTG_TX_CLEAR(ep_num);
/* clear endpoint stall status */
USBD_ENDP_TX_STATUS_SET(ep_num, EPTX_VALID);
} else {
ep = &out_ep[ep_num];
/* clear endpoint data toggle bit */
USBD_DTG_RX_CLEAR(ep_num);
/* clear endpoint stall status */
USBD_ENDP_RX_STATUS_SET(ep_num, EPRX_VALID);
}
ep->stall = 0U;
}
static uint8_t __in_transaction (uint8_t ep_num)
{
usb_ep_struct *ep = &in_ep[ep_num];
if (0U == ep_num) {
if (0U != pudev->ctl_count) {
if (ep->trs_len > ep->maxpacket) {
/* one data packet has been transmited, update trs_len */
ep->trs_len -= ep->maxpacket;
/* continue to transmit remain data */
usbd_ep_tx (pudev, EP0_IN, ep->trs_buf, (uint16_t)ep->trs_len);
usbd_ep_rx (pudev, 0U, NULL, 0U);
} else {
#ifndef USB_DFU
/* transmit length is maxpacket multiple, so send zero length packet */
if ((0U == (ep->trs_len % ep->maxpacket)) && (ep->trs_len < pudev->ctl_count)) {
usbd_ep_tx (pudev, EP0_IN, NULL, 0U);
pudev->ctl_count = 0U;
usbd_ep_rx (pudev, 0U, NULL, 0U);
} else
#endif /* USB_DFU */
{
ep->trs_len = 0U;
if (USBD_CONFIGURED == pudev->status) {
pudev->class_data_handler(pudev, USBD_TX, EP0);
}
USBD_CONTRL_STATUS_RX();
pudev->ctl_count = 0U;
}
}
} else {
if (0U != g_device_address) {
USBD_REG_SET(USBD_DADDR, DADDR_USBEN | g_device_address);
g_device_address = 0U;
}
}
} else {
ep->trs_len -= ep->trs_count;
if (0U == ep->trs_len) {
if (USBD_CONFIGURED == pudev->status) {
pudev->class_data_handler(pudev, USBD_TX, ep_num);
}
} else {
usbd_ep_tx(pudev, ep_num, ep->trs_buf, (uint16_t)ep->trs_len);
}
}
return USBD_OK;
}
static uint8_t usbd_intf_lpst ()
{
uint8_t ep_num = 0U;
__IO uint16_t int_status = 0U;
__IO uint16_t ep_value = 0U;
usb_ep_struct *ep = NULL;
/* wait till interrupts are not pending */
while (0U != ((int_status = USBD_REG_GET(USBD_INTF)) & (uint16_t)INTF_STIF)) {
/* get endpoint number and the value of control and state register */
ep_num = (uint8_t)(int_status & INTF_EPNUM);
ep_value = USBD_REG_GET(USBD_EPxCS(ep_num));
if (0U == (int_status & INTF_DIR)) {
/* handle the in direction transaction */
ep = &in_ep[ep_num];
if (0U != (ep_value & EPxCS_TX_ST)) {
/* clear successful transmit interrupt flag */
USBD_ENDP_TX_STAT_CLEAR(ep_num);
/* just handle single buffer situation */
ep->trs_count = (pbuf_reg + ep_num)->tx_count & EPTCNT_CNT;
/* maybe mutiple packets */
ep->trs_buf += ep->trs_count;
__in_transaction(ep_num);
}
} else {
/* handle the out direction transaction */
uint16_t count = 0U;
ep = &(pudev->out_ep[ep_num]);
if (0U != (ep_value & EPxCS_RX_ST)) {
/* clear successful receive interrupt flag */
USBD_ENDP_RX_STAT_CLEAR(ep_num);
count = (pbuf_reg + ep_num)->rx_count & (uint16_t)EPRCNT_CNT;
if (0U != count) {
if (0U != (ep_value & EPxCS_SETUP)) {
/* handle setup packet */
usbd_ep_data_read(&(pudev->setup_packet[0]), pbuf_reg->rx_addr, count);
/* enter setup status */
usbd_setup_transaction(pudev);
return USBD_OK;
} else {
usbd_ep_data_read(ep->trs_buf, (pbuf_reg + ep_num)->rx_addr, count);
}
}
/* maybe mutiple packets */
ep->trs_count += count;
ep->trs_buf += count;
ep->trs_len -= count;
if ((0U == ep->trs_len) || (count < ep->maxpacket)) {
/* enter data OUT status */
usbd_out_transaction(pudev, ep_num);
ep->trs_count = 0U;
} else {
usbd_ep_rx(pudev, ep_num, ep->trs_buf, (uint16_t)ep->trs_len);
}
}
}
}
return USBD_OK;
}
void dcd_int_handler(uint8_t rhport)
{
__IO uint16_t interrupt_flag = 0U;
__IO uint16_t ctlr = 0U;
interrupt_flag = USBD_REG_GET(USBD_INTF);
if (g_interrupt_mask & INTF_STIF & interrupt_flag) {
/* the endpoint successful transfer interrupt service */
usbd_intf_lpst();
}
if (g_interrupt_mask & INTF_WKUPIF & interrupt_flag) {
/* clear wakeup interrupt flag in INTF */
USBD_REG_SET(USBD_INTF, (uint16_t)CLR_WKUPIF);
/* USB wakeup interrupt handle */
usbd_intf_wakeup(usb_device_dev);
#ifdef LPM_ENABLED
/* clear L1 remote wakeup flag */
L1_remote_wakeup = 0;
#endif /* LPM_ENABLED */
}
if (g_interrupt_mask & INTF_SPSIF & interrupt_flag) {
if(!(USBD_REG_GET(USBD_CTL) & CTL_RSREQ)) {
/* process library core layer suspend routine*/
usbd_intf_suspend(usb_device_dev);
/* clear of suspend interrupt flag bit must be done after setting of CTLR_SETSPS */
USBD_REG_SET(USBD_INTF, (uint16_t)CLR_SPSIF);
}
}
if (g_interrupt_mask & INTF_SOFIF & interrupt_flag) {
/* clear SOF interrupt flag in INTF */
USBD_REG_SET(USBD_INTF, (uint16_t)CLR_SOFIF);
/* USB SOF interrupt handle */
usbd_intf_sof(usb_device_dev);
}
if (g_interrupt_mask & INTF_ESOFIF & interrupt_flag) {
/* clear ESOF interrupt flag in INTF */
USBD_REG_SET(USBD_INTF, (uint16_t)CLR_ESOFIF);
/* USB ESOF interrupt handle */
usbd_intf_esof(usb_device_dev);
}
if (g_interrupt_mask & INTF_RSTIF & interrupt_flag) {
/* clear reset interrupt flag in INTF */
USBD_REG_SET(USBD_INTF, (uint16_t)CLR_RSTIF);
/* USB reset interrupt handle */
usbd_intf_reset(usb_device_dev);
}
#ifdef LPM_ENABLED
if (g_interrupt_mask & INTF_L1REQ & interrupt_flag) {
/* clear L1 ST bit in LPM INTF */
USBD_REG_SET(USBD_INTF, CLR_L1REQ);
/* read BESL field from subendpoint0 register which coressponds to HIRD parameter in LPM spec */
besl = (USBD_REG_GET(USBD_LPMCS) & LPMCS_BLSTAT) >> 4;
/* read BREMOTEWAKE bit from subendpoint0 register which corresponding to bRemoteWake bit in LPM request */
L1_remote_wakeup = (USBD_REG_GET(USBD_LPMCS) & LPMCS_REMWK) >> 8;
/* process USB device core layer suspend routine */
/* enter USB model in suspend and system in low power mode (DEEP_SLEEP mode) */
usbd_intf_suspend(usb_device_dev);
}
#endif /* LPM_ENABLED */
}