How to Use USB HAL
- group HAL_Usage_Chapter
This section provides a detailed explanation on utilizing USB HAL, accompanied by sample code for better understanding.
Hardware Setup
Call hal_usb_speed_set to set the target speed for USB.
Call hal_usb_init to initialize HAL software resources.
Call hal_usb_phy_power_on to power on the USB PHY.
Call hal_usb_mac_init to initialize the USB MAC.
- Example
void usb_hw_init(void) { hal_usb_speed_set(HAL_USB_SPEED_HIGH); hal_usb_init(); hal_usb_phy_power_on(); hal_usb_mac_init(); }
Prepare to Enumerate
Set up the hardware as required above.
Implement the HAL USB composite driver.
Create task to handle interrupts.
Initialize the interrupts.
USB soft connect.
- Example
uint8_t isr_pending = 0; void usb_common_isr_handler(T_HAL_USB_COMMON_ISR isr, T_HAL_USB_ISR_PARAM *param) { if process in task { isr_pending++; //send message to USB irq task } } void usb_common_isr_enter(void) { NVIC_DisableIRQ(USB_IP_IRQn); } void usb_common_isr_exit(void) { if(isr_pending == 0) { NVIC_EnableIRQ(USB_IP_IRQn); } } HAL_USB_COMMON_ISR_HOOKS common_isr_hooks = { .enter = usb_common_isr_enter, .handler = usb_common_isr_handler, .exit = usb_common_isr_exit, } void usb_isr_proc_task(void *) { while(1) { if receive msg from USB common ISR { //process common ISR } isr_pending--; if(isr_pending == 0) { NVIC_EnableIRQ(USB_IP_IRQn); } } } void usb_isr_proc_task_create(void) { //create task usb_isr_proc_task } void usb_isr_init(void) { RamVectorTableUpdate(USB_IP_VECTORn, usb_common_isr_handler); NVIC_SetPriority(USB_IP_IRQn, 4); NVIC_EnableIRQ(USB_IP_IRQn); } void usb_start(void) { usb_hw_init();//Setup hardware usb_isr_proc_task_create();//Create task to handle interrupts usb_isr_init();//Initialize interrupts hal_usb_soft_attach();//USB soft connect //os scheduler start }
Endpoint Setup
The endpoint should be enabled when receiving
set_altrequest and the alternate setting contains the endpoint. Please refer toPrepare to Enumerateto know how to receive setup packets.- Example
int setup_cb(uint8_t *data) { if setup request is set_alt { void *ep_handle = hal_usb_ep_handle_get(ep addr); if alternate value is m and the alternate setting m contains the endpoint epN { hal_usb_ep_enable(ep_handle , ep desc); // bulk & interrupt endpoints //if endpoint direction is OUT, allocate URB T_HAL_USB_REQUEST_BLOCK *ep_urb = hal_usb_urb_alloc(len); ...initialize URB...(refer to Data Transfer) //prepare to receive data hal_usb_ep_rx(ep_handle, ep_urb); // isochronous endpoints //allocate URB T_HAL_USB_ISO_REQUEST_BLOCK *ep_urb = hal_usb_iso_urb_alloc(len); ...initialize URB...(refer to Data Transfer) //start transfer--For both send and receive hal_usb_iso_ep_start(ep_handle, ep_urb); } else { // isochronous endpoints hal_usb_iso_ep_stop(ep_handle, ep_urb); // all endpoints hal_usb_ep_disable(ep_handle); } } }
Data Transfer
Data transfer entity is defined in T_HAL_USB_REQUEST_BLOCK for control/interrupt/bulk transfers and T_HAL_USB_ISO_REQUEST_BLOCK for isochronous transfer.
To setup data transfer:
Setup endpoint, refer to
Endpoint Setupin How to Use USB HAL.Allocate URB.
Start transfer.
- Example
// Control transfer //enable endpoint 0 void *ep0_handle = hal_usb_ep_handle_get(0); hal_usb_ep_enable(ep0_handle , NULL); int ep0_request_complete(T_HAL_USB_REQUEST_BLOCK *urb) { //for OUT data stage process data in urb->buf } //allocate URB T_HAL_USB_REQUEST_BLOCK *ep0_urb = hal_usb_urb_alloc(len); ep0_urb->length = length of data to transfer memcpy(ep0_urb->buf, data, ep0_urb->length) ep0_urb->complete = ep0_request_complete; ep0_urb->ep_handle = ep0_handle; //start transfer--For both send and receive //hal_usb_ep0_trx MUST be called in setup callback in \ref T_HAL_USB_DRIVER //for TX, if ep0_urb->length is 0, it means send ACK to host hal_usb_ep0_trx(ep0_handle, ep0_urb); // \b bulk \b & \b interrupt \b transfer //enable ep void *ep_handle = hal_usb_ep_handle_get(ep addr); hal_usb_ep_enable(ep_handle , ep desc); int ep_request_complete(T_HAL_USB_REQUEST_BLOCK *urb) { //for OUT data stage process data in urb->buf ...reinit urb if needed... hal_usb_ep_rx(ep_handle, ep_urb); } //allocate URB T_HAL_USB_REQUEST_BLOCK *ep_urb = hal_usb_urb_alloc(len); ep_urb->complete = ep_request_complete; ep_urb->ep_handle = ep_handle; ep_urb->buf_proc_intrvl = process interval; ep_urb->data_per_frame = data length per host polling; //start transfer //send if support zero length packet { ep_urb->zlp = (ep max packet size == ep_urb->length); } else { ep_urb->zlp = 0; } hal_usb_ep_tx(ep_handle, ep_urb); //Receive hal_usb_ep_rx(ep_handle, ep_urb); // \b isochronous \b transfer int iso_ep_request_complete(T_HAL_USB_ISO_REQUEST_BLOCK *urb, uint8_t proc_buf_num) { T_HAL_USB_ISO_PKT_INFO *iso_pkt = NULL; uint8_t *buf = NULL; uint8_t pkt_cnt = 0; if(proc_buf_num == 0) { iso_pkt = urb->iso_pkt0; buf = urb->buf0; } else { iso_pkt = urb->iso_pkt1; buf = urb->buf1; } pkt_cnt = iso_pkt->pkt_cnt; for(uint8_t i = 0; i < pkt_cnt; i++) { if(iso_pkt[i].status == 0) { //process data store in buf + iso_pkt[i].offset, and data length is iso_pkt[i].actual } } return 0; } //enable ep void *ep_handle = hal_usb_ep_handle_get(ep addr); hal_usb_ep_enable(ep_handle , ep desc); //allocate URB T_HAL_USB_ISO_REQUEST_BLOCK *iso_ep_urb = hal_usb_iso_urb_alloc(len); iso_ep_urb->length = length of data to transfer memcpy(iso_ep_urb->buf, data, iso_ep_urb->length) iso_ep_urb->complete = iso_ep_request_complete; iso_ep_urb->ep_handle = ep_handle; //start transfer--For both send and receive hal_usb_iso_ep_start(ep_handle, iso_ep_urb);
Power Manager
To limit power consumption, the USB PHY will partially power down when the device suspends by calling hal_usb_suspend_enter in HAL_USB_COMMON_ISR_SUSPEND. If you quit the suspend state, a suspendn interrupt will be triggered, and hal_usb_suspend_exit should be called in the suspendn interrupt, followed by HAL_USB_COMMON_ISR_RESUME.
- Example
void usb_common_isr_handler(T_HAL_USB_COMMON_ISR isr, T_HAL_USB_ISR_PARAM *param) { if (isr == HAL_USB_COMMON_ISR_SUSPEND) { hal_usb_suspend_enter(); } } void usb_suspendn_isr_handler(void) { hal_usb_suspend_exit(); } HAL_USB_SUSPENDN_ISR_HOOKS usb_suspendn_isr_hooks = { .enter = NULL, .handler = usb_suspendn_isr_handler, .exit = NULL, }; //enable suspendn interrupt hal_usb_suspendn_isr_handler_update(&usb_suspendn_isr_hooks);