/* VBUS Change interrupt handler */ void intp_vbus_change() { usb_pcb_t *pcb = usb_pcb_get(); VBUS_INT_CLR(); if (!pcb->connected) { pcb->connected = true; /* enabled the USB voltage regulator */ UHWCON |= (1 << UVREGE); /* unfreeze the clock and attach to the bus */ USBCON &= ~(1 << FRZCLK); UDCON &= ~(1 << DETACH); } else { /* if we're connected, but VBUS is gone, then detach */ if (!(USBSTA & (1 << VBUS))) { /* detach from the bus */ UDCON |= (1 << DETACH); /* freeze the clock and turn off the USB PLL */ USBCON |= (1 << FRZCLK); PLLCSR = 0; /* disable the USB voltage regulator */ UHWCON &= ~(1 << UVREGE); pcb->connected = false; pcb->flags = 0; } } }
void cdc_req_handler(req_t *req) { U8 i; usb_pcb_t *pcb = usb_pcb_get(); switch (req->req) { case GET_LINE_CODING: if (req->type & (DEVICE_TO_HOST | TYPE_CLASS | RECIPIENT_INTF)) { // send the line coding to the host for (i=0; i<LINE_CODE_SZ; i++) { usb_buf_write(EP_CTRL, line_code[i]); } ep_write(EP_CTRL); } break; case SET_LINE_CODING: if (req->type & (HOST_TO_DEVICE | TYPE_CLASS | RECIPIENT_INTF)) { // wait for the setup data to be sent to the control endpoint while (pcb->fifo[EP_CTRL].len == 0) { // keep the nop for a place to set a breakpoint on and to make it obvious we're // waiting for something. asm("nop"); } // clear the setup flag if needed pcb->flags &= ~(1<<SETUP_DATA_AVAIL); // send out a zero-length packet to ack to the host that we received // the new line coding ep_send_zlp(EP_CTRL); // set the new line code. the first 8 bytes in the fifo are just // for the setup packet so we want to write the next 7 bytes for the // line code. for (i=0; i<LINE_CODE_SZ; i++) { line_code[i] = usb_buf_read(EP_CTRL); } } break; case SET_CTRL_LINE_STATE: if (req->type & (HOST_TO_DEVICE | TYPE_CLASS | RECIPIENT_INTF)) { ep_send_zlp(EP_CTRL); } break; default: ep_set_stall(EP_CTRL); break; } }
void ep_clear_stall(U8 ep_num) { usb_pcb_t *pcb = usb_pcb_get(); pcb->ep_stall &= ~(1 << ep_num); ep_select(ep_num); UECONX |= (1<<STALLRQC); }
void ep_set_stall(U8 ep_num) { usb_pcb_t *pcb = usb_pcb_get(); pcb->ep_stall |= (1 << ep_num); ep_select(ep_num); UECONX |= (1 << STALLRQ); }
void ep_read(U8 ep_num) { U8 i, len; usb_pcb_t *pcb = usb_pcb_get(); if( ep_num == 0 ) { len = SI32_USB_A_read_ep0_count( SI32_USB_0 ); for (i=0; i<len; i++) { usb_buf_write( ep_num, SI32_USB_A_read_ep0_fifo_u8( SI32_USB_0 ) ); } //if( len == 8 ) // if( 0==SI32_USB_A_read_ep0_count( SI32_USB_0 ) ) { //SI32_USB_A_set_data_end_ep0(SI32_USB_0); } } else if( ep_num > 0 ) { if( ep_dir_get( ep_num ) == DIR_IN ) return; len = SI32_USBEP_A_read_data_count( usb_ep[ ep_num - 1 ] ); if( pcb->fifo[ ep_num ].len + len > MAX_BUF_SZ ) { pcb->pending_data |= ( 1 << ep_num ); return; } for (i=0; i<len; i++) { usb_buf_write(ep_num, SI32_USBEP_A_read_fifo_u8( usb_ep[ ep_num - 1 ] )); } //if ( 0==SI32_USBEP_A_read_data_count( usb_ep[ ep_num - 1 ] )) //{ // Clear overrun out overrun if it has occured if ( SI32_USBEP_A_has_out_data_overrun_occurred( usb_ep[ ep_num - 1 ] ) ) SI32_USBEP_A_clear_out_data_overrun( usb_ep[ ep_num - 1 ] ); SI32_USBEP_A_clear_outpacket_ready( usb_ep[ ep_num - 1 ] ); pcb->pending_data &= ~(1<<ep_num); //} } if (len > 0) { pcb->flags |= ( ep_num == 0 ) ? ( 1 << SETUP_DATA_AVAIL ) : ( 1 << RX_DATA_AVAIL ); } //cdc_demo_putchar("a", NULL); }
void ep_drain_fifo(U8 ep) { U8 byte_cnt; usb_pcb_t *pcb = usb_pcb_get(); ep_select(ep); byte_cnt = UEBCX; if (byte_cnt <= (MAX_BUF_SZ - pcb->fifo[ep].len)) { ep_read(ep); pcb->pending_data &= ~(1<<ep); FIFOCON_INT_CLR(); } }
/* * This is the putchar function that is used by avr-libc's printf. We need * to hook this function into the stdout file stream using the FDEV_SETUP_STREAM * macro in avr-libc. Once the stream is set up, we hook the stream to stdout * and we can do printfs via USB. */ int freakusb_putchar(char c, FILE *unused) { usb_pcb_t *pcb = usb_pcb_get(); if (!(pcb->flags & (1 << ENUMERATED))) return 0; if (c == '\n') { usb_buf_write(EP_1, '\n'); usb_buf_write(EP_1, '\r'); } else { usb_buf_write(EP_1, (U8)c); } ep_write(EP_1); return 0; }
void ep_read(U8 ep_num) { U8 i, len; usb_pcb_t *pcb = usb_pcb_get(); len = FIFO_BYTE_CNT; for (i=0; i<len; i++) { usb_buf_write(ep_num, UEDATX); } if (len > 0) { pcb->flags |= (ep_num == 0) ? (1<<SETUP_DATA_AVAIL) : (1<<RX_DATA_AVAIL); } }
void rx() { U8 i, c, ep_num, len; usb_pcb_t *pcb = usb_pcb_get(); // get the ep number of any endpoint with pending rx data if ((ep_num = usb_buf_data_pending(DIR_OUT)) != 0xFF) { // get the length of data in the OUT buffer len = pcb->fifo[ep_num].len; // read out the data in the buffer and echo it back to the host. for (i=0; i<len; i++) { c = usb_buf_read(ep_num); switch (c) { case '\r': // terminate the msg and reset the msg ptr. then send // it to the handler for processing. *msg_ptr = '\0'; printf_P(PSTR("\n\r")); cmd_parse((char *)msg); msg_ptr = msg; break; case '\b': usb_buf_write(EP_1, c); if (msg_ptr > msg) { msg_ptr--; } break; default: usb_buf_write(EP_1, c); *msg_ptr++ = c; break; } } pcb->flags |= (1 << TX_DATA_AVAIL); } }
void ep_set_stall(U8 ep_num) { usb_pcb_t *pcb = usb_pcb_get(); pcb->ep_stall |= (1 << ep_num); if( ep_num == 0 ) SI32_USB_A_send_stall_ep0( SI32_USB_0 ); else { if( ep_dir_get( ep_num ) == DIR_IN ) { SI32_USBEP_A_clear_in_stall_sent( usb_ep[ ep_num - 1 ] ); SI32_USBEP_A_send_in_stall( usb_ep[ ep_num - 1 ] ); } else { SI32_USBEP_A_clear_out_stall_sent( usb_ep[ ep_num - 1 ] ); SI32_USBEP_A_send_out_stall( usb_ep[ ep_num - 1 ] ); } } }
void ep_write(U8 ep_num) { U8 i, ep_size, len; usb_pcb_t *pcb = usb_pcb_get(); ep_select(ep_num); ep_size = ep_size_get(); len = pcb->fifo[ep_num].len; // make sure that the tx fifo is ready to receive the out data if (ep_num == EP_CTRL) { while (!TX_FIFO_READY); } else { while (!RWAL_INT); } for (i=0; i<len; i++) { // check if we've reached the max packet size for the endpoint if (i == ep_size) { // we've filled the max packet size so break and send the data break; } UEDATX = usb_buf_read(ep_num); } if (ep_num == EP_CTRL) { while (!TX_FIFO_READY); } // clearing these two will send the data out TX_IN_INT_CLR(); FIFOCON_INT_CLR(); }
void ep_clear_stall(U8 ep_num) { usb_pcb_t *pcb = usb_pcb_get(); pcb->ep_stall &= ~(1 << ep_num); if( ep_num == 0 ) SI32_USB_A_clear_stall_sent_ep0( SI32_USB_0 ); else { if( ep_dir_get( ep_num ) == DIR_IN ) { SI32_USBEP_A_reset_in_data_toggle( usb_ep[ ep_num - 1 ] ); SI32_USBEP_A_stop_in_stall( usb_ep[ ep_num - 1 ] ); } else { SI32_USBEP_A_reset_out_data_toggle( usb_ep[ ep_num - 1 ] ); SI32_USBEP_A_stop_out_stall( usb_ep[ ep_num - 1 ] ); } } }
void dfu_req_handler(req_t *req) { U8 i; usb_pcb_t *pcb = usb_pcb_get(); switch (req->req) { case DFU_DETACH: if (req->type & (HOST_TO_DEVICE | TYPE_CLASS | RECIPIENT_INTF)) { // wvalue is wTimeout // wLength is zero // data is none dfu_status.bState = appDETACH; dfu_status.bStatus = OK; } break; case DFU_DNLOAD: if (req->type & (HOST_TO_DEVICE | TYPE_CLASS | RECIPIENT_INTF)) { // wvalue is wBlockNum // wlength is Length // data is firmware if( dfu_status.bState == dfuIDLE ) { if( req->len > 0 ) { hw_state_indicator( HW_STATE_TRANSFER ); dfu_status.bState = dfuDNLOAD_SYNC; } else { dfu_status.bState = dfuERROR; dfu_status.bStatus = errNOTDONE; hw_state_indicator( HW_STATE_ERROR ); ep_send_zlp(EP_CTRL); return; } } i = req->val; if( dfu_status.bState == dfuDNLOAD_IDLE ) { if( req->len > 0 ) { dfu_status.bState = dfuDNLOAD_SYNC; } else { if( flash_buffer_ptr > flash_buffer ) { need_to_write = 1; //flash_buffer_ptr = flash_buffer; } dfu_status.bState = dfuMANIFEST_SYNC; ep_send_zlp(EP_CTRL); return; } } SI32_USB_A_clear_out_packet_ready_ep0(SI32_USB_0); while(pcb->fifo[EP_CTRL].len < req->len) { //ep_read(EP_CTRL); i = pcb->fifo[EP_CTRL].len; } // clear the setup flag if needed pcb->flags &= ~(1<<SETUP_DATA_AVAIL); // send out a zero-length packet to ack to the host that we received // the new line coding U8* byte_buf_ptr = ( U8* )flash_buffer_ptr; U8 tmp_len = pcb->fifo[EP_CTRL].len; for(i = 0; i < tmp_len; i++) { *byte_buf_ptr = usb_buf_read(EP_CTRL); byte_buf_ptr++; } flash_buffer_ptr += i/4; if( flash_buffer_ptr == flash_buffer + BLOCK_SIZE_U32 ) { // Reset buffer pointer //flash_buffer_ptr = flash_buffer; need_to_write = 1; } if( flash_buffer_ptr > flash_buffer + BLOCK_SIZE_U32) { dfu_status.bState = dfuERROR; hw_state_indicator( HW_STATE_ERROR ); } ep_send_zlp(EP_CTRL); } break; case DFU_UPLOAD: if (req->type & (DEVICE_TO_HOST | TYPE_CLASS | RECIPIENT_INTF)) { // wvalue is zero // wlength is length // data is firmware // NOT SUPPORTED ep_set_stall(EP_CTRL); } break; case DFU_GETSTATUS: if (req->type & (DEVICE_TO_HOST | TYPE_CLASS | RECIPIENT_INTF)) { if( dfu_communication_started == 0 ) hw_state_indicator( HW_STATE_CONNECTED ); dfu_communication_started = 1; // If we're still transmitting blocks if( dfu_status.bState == dfuDNLOAD_SYNC ) { if( need_to_write == 0 ) { dfu_status.bState=dfuDNLOAD_IDLE; dfu_status.bwPollTimeout0 = 0x00; } else { dfu_status.bState=dfuDNBUSY; dfu_status.bwPollTimeout0 = 0x3F; } } else if( dfu_status.bState == dfuDNBUSY ) { if( need_to_write == 0) dfu_status.bState=dfuDNLOAD_SYNC; } else if( dfu_status.bState == dfuMANIFEST_SYNC) { dfu_status.bState=dfuMANIFEST; dfu_status.bwPollTimeout0 = 0xFF; hw_state_indicator( HW_STATE_DONE ); } else if( dfu_status.bState == dfuMANIFEST && need_to_write == 0) { // Finish erasing flash while( flash_target < SI32_MCU_FLASH_SIZE) { if( 0 != hw_flash_erase( flash_target, 1 ) ) { dfu_status.bState = dfuERROR; dfu_status.bStatus = errERASE; hw_state_indicator( HW_STATE_ERROR ); } flash_target += BLOCK_SIZE_U8; } dfu_status.bState=dfuMANIFEST_WAIT_RESET; } for (i=0; i<STATUS_SZ; i++) { usb_buf_write(EP_CTRL, *((U8 *)&dfu_status + i)); } ep_write(EP_CTRL); if( dfu_status.bState == dfuMANIFEST_WAIT_RESET ) { hw_wait_ms(200); hw_boot_image( 1 ); } if( need_to_write ) { if( 0 != hw_flash_erase( flash_target, 1 ) ) { dfu_status.bState = dfuERROR; dfu_status.bStatus = errERASE; hw_state_indicator( HW_STATE_ERROR ); } if( 0 != hw_flash_write( flash_target, ( U32* )flash_buffer, flash_buffer_ptr - flash_buffer, 1 ) ) { dfu_status.bState = dfuERROR; dfu_status.bStatus = errVERIFY; hw_state_indicator( HW_STATE_ERROR ); } flash_buffer_ptr = flash_buffer; flash_target += BLOCK_SIZE_U8; need_to_write = 0; if( dfu_status.bState != dfuMANIFEST ) dfu_status.bState=dfuDNLOAD_SYNC; } } break; case DFU_CLRSTATUS: if (req->type & (HOST_TO_DEVICE | TYPE_CLASS | RECIPIENT_INTF)) { // wvalue is zero // wlength is 0 // data is none if( dfu_status.bState == dfuERROR ) { dfu_status.bStatus = OK; dfu_status.bState = dfuIDLE; hw_state_indicator( HW_STATE_ERROR_CLR ); } } break; case DFU_GETSTATE: if (req->type & (DEVICE_TO_HOST | TYPE_CLASS | RECIPIENT_INTF)) { // wvalue is zero // wlength is 1 // data is state // Transition?: No State Transition usb_buf_write( EP_CTRL, dfu_status.bState ); ep_write(EP_CTRL); } break; case DFU_ABORT: if (req->type & (HOST_TO_DEVICE | TYPE_CLASS | RECIPIENT_INTF)) { // wvalue is zero // wlength is 0 // data is none if( dfu_status.bState == dfuIDLE ) { dfu_status.bStatus = OK; dfu_status.bState = dfuIDLE; } else if ( dfu_status.bState == dfuDNLOAD_IDLE ) { flash_target = FLASH_TARGET; if( 0 != hw_flash_erase( flash_target, 1 ) ) { dfu_status.bState = dfuERROR; dfu_status.bStatus = errERASE; hw_state_indicator( HW_STATE_ERROR ); } dfu_status.bStatus = OK; dfu_status.bState = dfuIDLE; ep_send_zlp(EP_CTRL); } } break; default: ep_set_stall(EP_CTRL); break; } }
void ep_write(U8 ep_num) { U8 i, ep_size, len; usb_pcb_t *pcb = usb_pcb_get(); uint32_t ControlReg = SI32_USB_A_read_ep0control(SI32_USB_0); ep_size = ep_size_get( ep_num ); len = pcb->fifo[ep_num].len; if( len > 0 ) { if( ep_num == 0 ) { // Make sure we're free to write while( SI32_USB_A_read_ep0control(SI32_USB_0) & SI32_USB_A_EP0CONTROL_IPRDYI_MASK ); //if( ( ongoing_write & ( 1 < ep_num ) ) == 0) //SI32_USB_A_clear_out_packet_ready_ep0( SI32_USB_0 ); for (i=0; i<len; i++) { if ( i == ep_size ) { // we've filled the max packet size so break and send the data //ControlReg |= SI32_USB_A_EP0CONTROL_IPRDYI_MASK; //SI32_USB_0->EP0CONTROL.U32 = ControlReg; ongoing_write |= ( 1 < ep_num ); break; } SI32_USB_A_write_ep0_fifo_u8( SI32_USB_0, usb_buf_read( ep_num ) ); } ongoing_write = 0; ControlReg |= SI32_USB_A_EP0CONTROL_IPRDYI_MASK; //ControlReg |= SI32_USB_A_EP0CONTROL_DEND_MASK; SI32_USB_0->EP0CONTROL.U32 = ControlReg; } else { if( ep_dir_get( ep_num ) == DIR_OUT ) return; // JEFF TESTING: Return immediately if our endpoint is not ready. This should never be the case // unless the endpoint is hung. We are not sending that much data so something must be wrong. // Also add a timer to the fifo_empty function at the end to eliminate endless loop on USB error. if( !SI32_USBEP_A_is_in_fifo_empty( usb_ep[ ep_num - 1 ] ) ) return; if( SI32_USBEP_A_read_epcontrol( usb_ep[ ep_num - 1 ] ) & SI32_USBEP_A_EPCONTROL_IPRDYI_MASK ) return; // Make sure we're free to write //while( SI32_USBEP_A_read_epcontrol( usb_ep[ ep_num - 1 ] ) & SI32_USBEP_A_EPCONTROL_IPRDYI_MASK ); for (i=0; i<len; i++) { // check if we've reached the max packet size for the endpoint if ( i == ep_size ) { // we've filled the max packet size so break and send the data break; } SI32_USBEP_A_write_fifo_u8( usb_ep[ ep_num - 1 ], usb_buf_read( ep_num ) ); } // clearing these two will send the data out SI32_USBEP_A_clear_in_data_underrun( usb_ep[ ep_num - 1 ] ); SI32_USBEP_A_set_in_packet_ready( usb_ep[ ep_num - 1 ] ); } } }
void hw_init() { usb_pcb_t *pcb = usb_pcb_get(); SI32_CLKCTRL_0->APBCLKG0_SET = SI32_CLKCTRL_A_APBCLKG0_PLL0CEN_ENABLED_U32 | SI32_CLKCTRL_A_APBCLKG0_PB0CEN_DISABLED_U32 | SI32_CLKCTRL_A_APBCLKG0_USART0CEN_DISABLED_U32 | SI32_CLKCTRL_A_APBCLKG0_USART1CEN_DISABLED_U32 | SI32_CLKCTRL_A_APBCLKG0_UART0CEN_DISABLED_U32 | SI32_CLKCTRL_A_APBCLKG0_UART1CEN_DISABLED_U32 | SI32_CLKCTRL_A_APBCLKG0_SPI0CEN_DISABLED_U32 | SI32_CLKCTRL_A_APBCLKG0_SPI1CEN_DISABLED_U32 | SI32_CLKCTRL_A_APBCLKG0_SPI2CEN_DISABLED_U32 | SI32_CLKCTRL_A_APBCLKG0_I2C0CEN_DISABLED_U32 | SI32_CLKCTRL_A_APBCLKG0_I2C1CEN_DISABLED_U32 | SI32_CLKCTRL_A_APBCLKG0_EPCA0CEN_DISABLED_U32 | SI32_CLKCTRL_A_APBCLKG0_PCA0CEN_DISABLED_U32 | SI32_CLKCTRL_A_APBCLKG0_PCA1CEN_DISABLED_U32 | SI32_CLKCTRL_A_APBCLKG0_SSG0CEN_DISABLED_U32 | SI32_CLKCTRL_A_APBCLKG0_TIMER0CEN_DISABLED_U32 | SI32_CLKCTRL_A_APBCLKG0_TIMER1CEN_DISABLED_U32 | SI32_CLKCTRL_A_APBCLKG0_ADC0CEN_DISABLED_U32 | SI32_CLKCTRL_A_APBCLKG0_ADC1CEN_DISABLED_U32 | SI32_CLKCTRL_A_APBCLKG0_CMP0CEN_DISABLED_U32 | SI32_CLKCTRL_A_APBCLKG0_CMP1CEN_DISABLED_U32 | SI32_CLKCTRL_A_APBCLKG0_CS0CEN_DISABLED_U32 | SI32_CLKCTRL_A_APBCLKG0_AES0CEN_DISABLED_U32 | SI32_CLKCTRL_A_APBCLKG0_CRC0CEN_DISABLED_U32 | SI32_CLKCTRL_A_APBCLKG0_IDAC0CEN_DISABLED_U32 | SI32_CLKCTRL_A_APBCLKG0_IDAC1CEN_DISABLED_U32 | SI32_CLKCTRL_A_APBCLKG0_LPT0CEN_DISABLED_U32 | SI32_CLKCTRL_A_APBCLKG0_I2S0CEN_DISABLED_U32 | SI32_CLKCTRL_A_APBCLKG0_USB0CEN_ENABLED_U32 | SI32_CLKCTRL_A_APBCLKG0_EVREGCEN_DISABLED_U32 | SI32_CLKCTRL_A_APBCLKG0_FLCTRLCEN_ENABLED_U32; SI32_CLKCTRL_0->AHBCLKG_SET = SI32_CLKCTRL_A_AHBCLKG_RAMCEN_ENABLED_U32 | SI32_CLKCTRL_A_AHBCLKG_DMACEN_DISABLED_U32 | SI32_CLKCTRL_A_AHBCLKG_FLASHCEN_ENABLED_U32 | SI32_CLKCTRL_A_AHBCLKG_EMIF0CEN_DISABLED_U32 | SI32_CLKCTRL_A_AHBCLKG_USB0BCEN_ENABLED_U32; SI32_WDTIMER_A_stop_counter(SI32_WDTIMER_0); #ifdef PCB_V7 int pcb_v7_is_defined; //Will show a compiler warning to note hardware version // Setup PBHD4 SI32_PBCFG_A_unlock_ports(SI32_PBCFG_0); SI32_PBHD_A_write_pblock(SI32_PBHD_4, 0x00); SI32_PBHD_A_select_pin0_safe_state(SI32_PBHD_4, 0x0); SI32_PBHD_A_select_pin1_safe_state(SI32_PBHD_4, 0x0); SI32_PBHD_A_select_pin2_safe_state(SI32_PBHD_4, 0x0); SI32_PBHD_A_select_pin3_safe_state(SI32_PBHD_4, 0x0); SI32_PBHD_A_select_pin4_safe_state(SI32_PBHD_4, 0x0); SI32_PBHD_A_select_pin5_safe_state(SI32_PBHD_4, 0x0); SI32_PBHD_A_enable_bias(SI32_PBHD_4); SI32_PBHD_A_select_normal_power_port_mode(SI32_PBHD_4); SI32_PBHD_A_enable_drivers(SI32_PBHD_4); //Setup PB4.3 LED0/1 //Setup PB4.2 to LOW to turn on mosfets for bat charger! SI32_PBHD_A_set_pins_push_pull_output( SI32_PBHD_4, 0x000C ); SI32_PBHD_A_disable_pullup_resistors( SI32_PBHD_4 ); SI32_PBHD_A_write_pins_low( SI32_PBHD_4, 0x04 ); SI32_PBHD_A_write_pins_high( SI32_PBHD_4, 0x08 ); SI32_PBCFG_A_enable_crossbar_0(SI32_PBCFG_0); // Setup PB2 SI32_PBSTD_A_disable_pullup_resistors( SI32_PBSTD_2 ); // PB2.1 is wakeup SI32_PBSTD_A_set_pins_digital_input(SI32_PBSTD_2, 0x00000002); // Setup PB3 SI32_PBSTD_A_disable_pullup_resistors( SI32_PBSTD_3 ); //PB3.9 is usb voltage detection SI32_PBSTD_A_set_pins_digital_input(SI32_PBSTD_3, 0x00000200); #else int pcb_v5_is_defined; //Will show a compiler warning to note hardware version #endif /* --------------------- */ /* Initialize USB Module */ /* --------------------- */ SI32_USB_A_enable_usb_oscillator(SI32_USB_0); SI32_USB_A_verify_clock_is_running(SI32_USB_0); SI32_USB_A_select_usb_clock_48mhz (SI32_USB_0); // Perform asynchronous reset of the USB module SI32_USB_A_reset_module(SI32_USB_0); // Wait for reset to complete while (SI32_USB_0->CLKSEL.RESET == SI32_USB_A_CLKSEL_RESET_SET_VALUE); SI32_USB_A_write_cmint (SI32_USB_0, 0x00000000); SI32_USB_A_write_ioint (SI32_USB_0, 0x00000000); SI32_USB_A_enable_ep0_interrupt (SI32_USB_0); // Enable Reset, Resume, Suspend interrupts SI32_USB_A_enable_suspend_interrupt (SI32_USB_0); SI32_USB_A_enable_resume_interrupt (SI32_USB_0); SI32_USB_A_enable_reset_interrupt (SI32_USB_0); //SI32_USB_A_enable_start_of_frame_interrupt (SI32_USB_0); // Enable Transceiver, fullspeed SI32_USB_A_write_tcontrol (SI32_USB_0, 0x00); SI32_USB_A_select_transceiver_full_speed (SI32_USB_0); SI32_USB_A_enable_transceiver (SI32_USB_0); // _SI32_USB_A_enable_internal_pull_up (SI32_USB_0); SI32_USB_A_enable_internal_pull_up( SI32_USB_0 ); // Enable clock recovery, single-step mode disabled SI32_USB_A_enable_clock_recovery (SI32_USB_0); SI32_USB_A_select_clock_recovery_mode_full_speed (SI32_USB_0); SI32_USB_A_select_clock_recovery_normal_cal (SI32_USB_0); SI32_USB_0->CMINTEPE.U32 |= (1<<16) ; SI32_USB_0->CMINTEPE.U32 |= 7; NVIC_EnableIRQ (USB0_IRQn); SI32_USB_A_enable_module( SI32_USB_0 ); pcb->connected = true; }