/* mbed Microcontroller Library * Copyright (c) 2018-2020 ARM Limited, All rights reserved. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #if defined(DEVICE_USBDEVICE) && DEVICE_USBDEVICE extern "C" { #include "r_typedefs.h" #include "iodefine.h" } #include "USBPhyHw.h" #include "USBEndpoints_RZ_A2.h" #include "USBPhy_RZ_A2_Def.h" #include "pinmap.h" /**** User Selection ****/ #if defined(TARGET_SEMB1402) #define USB_FUNCTION_CH 0 #else #define USB_FUNCTION_CH 1 #endif #define USB_FUNCTION_HISPEED 1 // 1: High-Speed 0: Full-Speed #if (USB_FUNCTION_CH == 0) #define USB_MX USB01 #define USBX0 USB00 #define USBFIX_IRQn USBFI0_IRQn #define USBHIX_IRQn USBHI0_IRQn #else #define USB_MX USB11 #define USBX0 USB10 #define USBFIX_IRQn USBFI1_IRQn #define USBHIX_IRQn USBHI1_IRQn #endif /* There are maintenance routine of SHTNAK and BFRE bits in original sample program. * This sample is not programmed. Do maintenance the "def_pipecfg" array if you want it. */ const struct PIPECFGREC { uint16_t endpoint; uint16_t pipesel; uint16_t pipecfg; uint16_t pipebuf; uint16_t pipemaxp; uint16_t pipeperi; } def_pipecfg[] = { /* EP0OUT and EP0IN are configured by USB IP */ { EP1OUT, /* EP1: Host -> Func, INT */ 6, USB_TYPFIELD_INT | USB_BFREOFF | USB_CFG_DBLBOFF | USB_CFG_CNTMDON | USB_DIR_P_OUT | 1, USB_BUF_SIZE(64) | 0x04u, MAX_PACKET_SIZE_EP1, 3, }, { EP1IN, /* EP1: Host <- Func, INT */ 7, USB_TYPFIELD_INT | USB_BFREOFF | USB_CFG_DBLBOFF | USB_CFG_CNTMDOFF | USB_DIR_P_IN | 1, USB_BUF_SIZE(64) | 0x05u, MAX_PACKET_SIZE_EP1, 3, }, { EP2OUT, /* EP2: Host -> Func, BULK */ 3, USB_TYPFIELD_BULK | USB_BFREOFF | USB_CFG_DBLBON | USB_CFG_CNTMDON | USB_SHTNAKFIELD | USB_DIR_P_OUT | 2, USB_BUF_SIZE(2048) | 0x30u, MAX_PACKET_SIZE_EP2, 0, }, { EP2IN, /* EP2: Host <- Func, BULK */ 4, USB_TYPFIELD_BULK | USB_BFREOFF | USB_CFG_DBLBOFF | USB_CFG_CNTMDON | USB_DIR_P_IN | 2, USB_BUF_SIZE(2048) | 0x50u, MAX_PACKET_SIZE_EP2, 0, }, { EP3OUT, /* EP3: Host -> Func, ISO */ 1, USB_TYPFIELD_ISO | USB_BFREOFF | USB_CFG_DBLBON | USB_CFG_CNTMDOFF | USB_SHTNAKFIELD | USB_DIR_P_OUT | 3, USB_BUF_SIZE(512) | 0x10u, MAX_PACKET_SIZE_EP3, 0, }, { EP3IN, /* EP3: Host <- Func, ISO */ 2, USB_TYPFIELD_ISO | USB_BFREOFF | USB_CFG_DBLBON | USB_CFG_CNTMDOFF | USB_DIR_P_IN | 3, USB_BUF_SIZE(512) | 0x20u, MAX_PACKET_SIZE_EP3, 0, }, { /* terminator */ 0, 0, 0, 0, 0, 0 }, }; static USBPhyHw *instance; static uint8_t _usb_speed = USB_FUNCTION_HISPEED; static bool run_later_ctrl_comp = false; /*static*/ void USBPhyHw::set_usb_speed(uint8_t speed) { _usb_speed = speed; } USBPhy *get_usb_phy() { static USBPhyHw usbphy; return &usbphy; } USBPhyHw::USBPhyHw(): events(NULL) { } USBPhyHw::~USBPhyHw() { } void USBPhyHw::init(USBPhyEvents *events) { volatile uint8_t dummy_read; if (this->events == NULL) { sleep_manager_lock_deep_sleep(); } this->events = events; /* registers me */ instance = this; /* Disable IRQ */ GIC_DisableIRQ(USBFIX_IRQn); GIC_DisableIRQ(USBHIX_IRQn); #if (USB_FUNCTION_CH == 0) #if defined(TARGET_SEMB1402) pin_function(PC_1, 1); /* VBUSIN1 */ #else pin_function(P5_2, 3); /* VBUSIN1 */ #endif CPG.STBCR6.BIT.MSTP61 = 0; dummy_read = CPG.STBCR6.BYTE; CPG.STBREQ3.BYTE &= ~0x03; dummy_read = CPG.STBREQ3.BYTE; #else /* (USB_FUNCTION_CH == 1) */ #if defined(TARGET_GR_MANGO) pin_function(P2_2, 5); /* VBUSIN1 */ DigitalOut usb_sel(P2_0); usb_sel = 1; #else pin_function(PC_0, 1); /* VBUSIN1 */ #endif CPG.STBCR6.BIT.MSTP60 = 0; dummy_read = CPG.STBCR6.BYTE; CPG.STBREQ3.BYTE &= ~0x0C; dummy_read = CPG.STBREQ3.BYTE; #endif (void)dummy_read; #if defined(TARGET_GR_MANGO) || defined(TARGET_RZ_A2M_SBEV) || defined(TARGET_SEMB1402) USBX0.PHYCLK_CTRL.BIT.UCLKSEL = 0; /* EXTAL */ #else USBX0.PHYCLK_CTRL.BIT.UCLKSEL = 1; /* USB_X1 */ #endif USBX0.PHYIF_CTRL.LONG = 0x00000000; USBX0.COMMCTRL.BIT.OTG_PERI = 1; /* 0 : Host, 1 : Peri */ USB_MX.LPSTS.WORD |= USB_SUSPENDM; USBX0.USBCTR.LONG = 0x00000000; cpu_delay_1us(100); /* 100us wait */ #if (0) if (events != NULL) { sleep_manager_unlock_deep_sleep(); } #endif events = NULL; } void USBPhyHw::deinit() { volatile uint8_t dummy_read; disconnect(); #if (USB_FUNCTION_CH == 0) CPG.STBCR6.BIT.MSTP61 = 1; #else CPG.STBCR6.BIT.MSTP60 = 1; #endif dummy_read = CPG.STBCR6.BYTE; (void)dummy_read; } bool USBPhyHw::powered() { // return true if powered false otherwise. Devices which don't support // this should always return true return true; } void USBPhyHw::connect() { /* Setting MCU(USB interrupt init) register */ InterruptHandlerRegister(USBFIX_IRQn, &_usbisr); InterruptHandlerRegister(USBHIX_IRQn, &_usbisr); GIC_EnableIRQ(USBFIX_IRQn); GIC_EnableIRQ(USBHIX_IRQn); GIC_SetConfiguration(USBFIX_IRQn, 1); GIC_SetConfiguration(USBHIX_IRQn, 1); GIC_SetPriority(USBFIX_IRQn, 5); GIC_SetPriority(USBHIX_IRQn, 5); /* Setting USB relation register */ USB_MX.SYSCFG0.WORD |= USB_USBE; USB_MX.SYSCFG1.WORD = (7 & 0x003f); /* 7 : 9 access cycles waits */ USB_MX.CFIFOSEL.WORD = USB_MBW_32; USB_MX.D0FIFOSEL.WORD = USB_MBW_32; USB_MX.D1FIFOSEL.WORD = USB_MBW_32; USB_MX.INTENB0.WORD |= (USB_VBSE | USB_SOFE | USB_DVSE | USB_CTRE | USB_BEMPE | USB_NRDYE | USB_BRDYE); /* Enable pullup on D+ */ USB_MX.SYSCFG0.WORD |= USB_DPRPU; if (_usb_speed == 0) { USB_MX.SYSCFG0.WORD &= ~USB_HSE; } else { USB_MX.SYSCFG0.WORD |= USB_HSE; } USB_MX.SYSCFG0.WORD &= ~USB_DRPD; } void USBPhyHw::disconnect() { /* Disable USB */ GIC_DisableIRQ(USBFIX_IRQn); GIC_DisableIRQ(USBHIX_IRQn); InterruptHandlerRegister(USBFIX_IRQn, NULL); InterruptHandlerRegister(USBHIX_IRQn, NULL); USB_MX.INTSTS0.WORD = 0; USB_MX.BRDYSTS.WORD = 0; USB_MX.NRDYSTS.WORD = 0; USB_MX.BEMPSTS.WORD = 0; USB_MX.INTENB0.WORD = 0; USB_MX.BRDYENB.WORD = 0; USB_MX.NRDYENB.WORD = 0; USB_MX.BEMPENB.WORD = 0; /* Disable pullup on D+ */ USB_MX.SYSCFG0.WORD &= (~USB_DPRPU); /* Pull-up disable */ } void USBPhyHw::configure() { } void USBPhyHw::unconfigure() { } void USBPhyHw::sof_enable() { /* Enable SOF interrupt */ USB_MX.INTENB0.WORD |= USB_SOFE; } void USBPhyHw::sof_disable() { /* Disable SOF interrupt */ USB_MX.INTENB0.WORD &= ~USB_SOFE; } void USBPhyHw::set_address(uint8_t address) { if (address <= 127) { set_pid(USB_PIPE0, USB_PID_BUF); /* Set BUF */ } else { set_pid(USB_PIPE0, USB_PID_STALL); /* Not specification */ } } void USBPhyHw::remote_wakeup() { } const usb_ep_table_t *USBPhyHw::endpoint_table() { static const usb_ep_table_t rza1_table = { 1, // No cost per endpoint - everything allocated up front { {USB_EP_ATTR_ALLOW_CTRL | USB_EP_ATTR_DIR_IN_AND_OUT, 0, 0}, {USB_EP_ATTR_ALLOW_INT | USB_EP_ATTR_DIR_IN_AND_OUT, 0, 0}, {USB_EP_ATTR_ALLOW_BULK | USB_EP_ATTR_DIR_IN_AND_OUT, 0, 0}, {USB_EP_ATTR_ALLOW_ISO | USB_EP_ATTR_DIR_IN_AND_OUT, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, } }; return &rza1_table; } uint32_t USBPhyHw::ep0_set_max_packet(uint32_t max_packet) { return MAX_PACKET_SIZE_EP0; } void USBPhyHw::ep0_setup_read_result(uint8_t *buffer, uint32_t size) { memcpy(buffer, setup_buffer, size); } void USBPhyHw::ep0_read(uint8_t *data, uint32_t size) { pipe_ctrl[USB_PIPE0].req_size = size; pipe_ctrl[USB_PIPE0].data_cnt = size; pipe_ctrl[USB_PIPE0].p_data = data; chg_curpipe(USB_PIPE0, USB_ISEL_READ); /* Switch FIFO and pipe number. */ USB_MX.CFIFOCTR.WORD = USB_BCLR; /* Buffer clear */ set_pid(USB_PIPE0, USB_PID_BUF); /* Set BUF */ USB_MX.BRDYENB.WORD |= (1 << USB_PIPE0); /* Enable ready interrupt */ USB_MX.NRDYENB.WORD |= (1 << USB_PIPE0); /* Enable not ready interrupt */ } uint32_t USBPhyHw::ep0_read_result() { return pipe_ctrl[USB_PIPE0].req_size; } void USBPhyHw::ep0_write(uint8_t *buffer, uint32_t size) { if ((buffer == NULL) || (size == 0)) { set_pid(USB_PIPE0, USB_PID_BUF); /* Set BUF */ return; } pipe_ctrl[USB_PIPE0].req_size = size; pipe_ctrl[USB_PIPE0].data_cnt = size; pipe_ctrl[USB_PIPE0].p_data = buffer; chg_curpipe(USB_PIPE0, USB_ISEL_WRITE); /* Switch FIFO and pipe number. */ USB_MX.CFIFOCTR.WORD = USB_BCLR; /* Buffer clear */ /* Clear the PIPExBEMP status bit of the specified pipe to clear */ USB_MX.BEMPSTS.WORD = (uint16_t)((~(1 << USB_PIPE0)) & BEMPSTS_MASK); /* Peripheral control sequence */ switch (write_data(USB_PIPE0)) { case USB_WRITING : /* Continue of data write */ USB_MX.BRDYENB.WORD |= (1 << USB_PIPE0);/* Enable Ready interrupt */ USB_MX.NRDYENB.WORD |= (1 << USB_PIPE0);/* Enable Not Ready Interrupt */ set_pid(USB_PIPE0, USB_PID_BUF); break; case USB_WRITEEND : /* End of data write */ case USB_WRITESHRT : /* End of data write */ USB_MX.BEMPENB.WORD |= (1 << USB_PIPE0);/* Enable Empty Interrupt */ USB_MX.NRDYENB.WORD |= (1 << USB_PIPE0);/* Enable Not Ready Interrupt */ set_pid(USB_PIPE0, USB_PID_BUF); break; case USB_FIFOERROR : /* FIFO access error */ ctrl_end((uint16_t)USB_DATA_ERR); break; default : break; } } void USBPhyHw::ep0_stall() { set_pid(USB_PIPE0, USB_PID_STALL); run_later_ctrl_comp = false; } bool USBPhyHw::endpoint_add(usb_ep_t endpoint, uint32_t max_packet, usb_ep_type_t type) { const struct PIPECFGREC *cfg; uint16_t pipe; volatile uint16_t *p_reg; if ((endpoint == EP0OUT) || (endpoint == EP0IN)) { return true; } for (cfg = &def_pipecfg[0]; cfg->pipesel != 0; cfg++) { if (cfg->endpoint == endpoint) { break; } } if (cfg->pipesel == 0) { return false; } pipe = (cfg->pipesel & USB_CURPIPE); /* Interrupt Disable */ USB_MX.BRDYENB.WORD &= (~(1 << pipe)); /* Disable Ready Interrupt */ USB_MX.NRDYENB.WORD &= (~(1 << pipe)); /* Disable Not Ready Interrupt */ USB_MX.BEMPENB.WORD &= (~(1 << pipe)); /* Disable Empty Interrupt */ set_pid(pipe, USB_PID_NAK); /* CurrentPIPE Clear */ if ((USB_MX.CFIFOSEL.WORD & USB_CURPIPE) == pipe) { USB_MX.CFIFOSEL.WORD &= ~USB_CURPIPE; } if ((USB_MX.D0FIFOSEL.WORD & USB_CURPIPE) == pipe) { USB_MX.D0FIFOSEL.WORD &= ~USB_CURPIPE; } if ((USB_MX.D1FIFOSEL.WORD & USB_CURPIPE) == pipe) { USB_MX.D1FIFOSEL.WORD &= ~USB_CURPIPE; } /* PIPE Configuration */ USB_MX.PIPESEL.WORD = pipe; /* Pipe select */ USB_MX.PIPECFG.WORD = cfg->pipecfg; USB_MX.PIPEBUF.WORD = cfg->pipebuf; USB_MX.PIPEMAXP.WORD = cfg->pipemaxp; USB_MX.PIPEPERI.WORD = cfg->pipeperi; p_reg = get_pipectr_reg(pipe); /* Set toggle bit to DATA0 */ *p_reg |= USB_SQCLR; /* Buffer Clear */ *p_reg |= USB_ACLRM; *p_reg &= ~USB_ACLRM; return true; } void USBPhyHw::endpoint_remove(usb_ep_t endpoint) { uint16_t pipe = EP2PIPE(endpoint); /* Interrupt Disable */ USB_MX.BRDYENB.WORD &= (~(1 << pipe)); /* Disable Ready Interrupt */ USB_MX.NRDYENB.WORD &= (~(1 << pipe)); /* Disable Not Ready Interrupt */ USB_MX.BEMPENB.WORD &= (~(1 << pipe)); /* Disable Empty Interrupt */ set_pid(pipe, USB_PID_NAK); /* CurrentPIPE Clear */ if ((USB_MX.CFIFOSEL.WORD & USB_CURPIPE) == pipe) { USB_MX.CFIFOSEL.WORD &= ~USB_CURPIPE; } if ((USB_MX.D0FIFOSEL.WORD & USB_CURPIPE) == pipe) { USB_MX.D0FIFOSEL.WORD &= ~USB_CURPIPE; } if ((USB_MX.D1FIFOSEL.WORD & USB_CURPIPE) == pipe) { USB_MX.D1FIFOSEL.WORD &= ~USB_CURPIPE; } /* PIPE Configuration */ USB_MX.PIPESEL.WORD = pipe; /* Pipe select */ USB_MX.PIPECFG.WORD = 0; pipe_ctrl[pipe].enable = false; pipe_ctrl[pipe].status = USB_DATA_NONE; } void USBPhyHw::endpoint_stall(usb_ep_t endpoint) { uint16_t pipe = EP2PIPE(endpoint); set_pid(pipe, USB_PID_STALL); pipe_ctrl[pipe].enable = false; pipe_ctrl[pipe].status = USB_DATA_STALL; } void USBPhyHw::endpoint_unstall(usb_ep_t endpoint) { uint16_t pipe = EP2PIPE(endpoint); volatile uint16_t *p_reg; set_pid(pipe, USB_PID_NAK); p_reg = get_pipectr_reg(pipe); /* Set toggle bit to DATA0 */ *p_reg |= USB_SQCLR; /* Buffer Clear */ *p_reg |= USB_ACLRM; *p_reg &= ~USB_ACLRM; pipe_ctrl[pipe].enable = false; pipe_ctrl[pipe].status = USB_DATA_NONE; } bool USBPhyHw::endpoint_read(usb_ep_t endpoint, uint8_t *data, uint32_t size) { uint16_t mxps; uint16_t trncnt; volatile uint16_t *p_reg; uint16_t pipe = EP2PIPE(endpoint); if (pipe_ctrl[pipe].status == USB_DATA_STALL) { return false; } pipe_ctrl[pipe].status = USB_DATA_READING; pipe_ctrl[pipe].req_size = size; pipe_ctrl[pipe].data_cnt = size; pipe_ctrl[pipe].p_data = data; pipe_ctrl[pipe].enable = true; set_pid(pipe, USB_PID_NAK); /* Set NAK */ USB_MX.BEMPSTS.WORD = (uint16_t)((~(1 << pipe)) & BEMPSTS_MASK); /* BEMP Status Clear */ USB_MX.BRDYSTS.WORD = (uint16_t)((~(1 << pipe)) & BRDYSTS_MASK); /* BRDY Status Clear */ USB_MX.NRDYSTS.WORD = (uint16_t)((~(1 << pipe)) & NRDYSTS_MASK); /* NRDY Status Clear */ chg_curpipe(pipe, USB_ISEL_READ); /* Switch FIFO and pipe number. */ USB_MX.CFIFOCTR.WORD = USB_BCLR; /* Clear BCLR */ if (size != 0) { /* Max Packet Size */ USB_MX.PIPESEL.WORD = pipe; /* Pipe select */ mxps = (uint16_t)(USB_MX.PIPEMAXP.WORD & USB_MXPS); /* Data size check */ if ((size % mxps) == (uint32_t)0u) { trncnt = (uint16_t)(size / mxps); } else { trncnt = (uint16_t)((size / mxps) + (uint32_t)1u); } /* Set Transaction counter */ p_reg = get_pipetre_reg(pipe); if (p_reg != NULL) { *p_reg |= USB_TRCLR; } p_reg = get_pipetrn_reg(pipe); if (p_reg != NULL) { *p_reg = trncnt; } p_reg = get_pipetre_reg(pipe); if (p_reg != NULL) { *p_reg |= USB_TRENB; } p_reg = get_pipectr_reg(pipe); /* Buffer Clear */ *p_reg |= USB_ACLRM; *p_reg &= ~USB_ACLRM; } set_pid(pipe, USB_PID_BUF); /* Set BUF */ USB_MX.BRDYENB.WORD |= (1 << pipe); /* Enable Ready Interrupt */ USB_MX.NRDYENB.WORD |= (1 << pipe); /* Enable Not Ready Interrupt */ return true; } uint32_t USBPhyHw::endpoint_read_result(usb_ep_t endpoint) { uint16_t pipe = EP2PIPE(endpoint); return pipe_ctrl[pipe].req_size; } bool USBPhyHw::endpoint_write(usb_ep_t endpoint, uint8_t *data, uint32_t size) { volatile uint16_t *p_reg; uint16_t pipe = EP2PIPE(endpoint); if (pipe_ctrl[pipe].status == USB_DATA_STALL) { return false; } pipe_ctrl[pipe].status = USB_DATA_WRITING; pipe_ctrl[pipe].req_size = size; pipe_ctrl[pipe].data_cnt = size; pipe_ctrl[pipe].p_data = data; pipe_ctrl[pipe].enable = true; set_pid(pipe, USB_PID_NAK); /* Set NAK */ USB_MX.BEMPSTS.WORD = (uint16_t)((~(1 << pipe)) & BEMPSTS_MASK);/* BEMP Status Clear */ USB_MX.BRDYSTS.WORD = (uint16_t)((~(1 << pipe)) & BRDYSTS_MASK);/* BRDY Status Clear */ USB_MX.NRDYSTS.WORD = (uint16_t)((~(1 << pipe)) & NRDYSTS_MASK);/* NRDY Status Clear */ p_reg = get_pipectr_reg(pipe); /* Buffer Clear */ *p_reg |= USB_ACLRM; *p_reg &= ~USB_ACLRM; buf_to_fifo(pipe); /* Buffer to FIFO data write */ set_pid(pipe, USB_PID_BUF); /* Set BUF */ return true; } void USBPhyHw::endpoint_abort(usb_ep_t endpoint) { forced_termination(EP2PIPE(endpoint), (uint16_t)USB_DATA_NONE); } void USBPhyHw::process() { /* Register Save */ uint16_t intsts0 = USB_MX.INTSTS0.WORD; uint16_t brdysts = USB_MX.BRDYSTS.WORD; uint16_t nrdysts = USB_MX.NRDYSTS.WORD; uint16_t bempsts = USB_MX.BEMPSTS.WORD; uint16_t intenb0 = USB_MX.INTENB0.WORD; uint16_t brdyenb = USB_MX.BRDYENB.WORD; uint16_t nrdyenb = USB_MX.NRDYENB.WORD; uint16_t bempenb = USB_MX.BEMPENB.WORD; /* Interrupt status get */ uint16_t ists0 = (uint16_t)(intsts0 & intenb0); uint16_t bsts = (uint16_t)(brdysts & brdyenb); uint16_t nsts = (uint16_t)(nrdysts & nrdyenb); uint16_t ests = (uint16_t)(bempsts & bempenb); uint16_t i; if ((intsts0 & (USB_VBINT | USB_RESM | USB_SOFR | USB_DVST | USB_CTRT | USB_BEMP | USB_NRDY | USB_BRDY)) == 0u) { return; } /***** Processing USB bus signal *****/ /***** Resume signal *****/ if ((ists0 & USB_RESM) == USB_RESM) { USB_MX.INTSTS0.WORD = (uint16_t)~USB_RESM; USB_MX.INTENB0.WORD &= (~USB_RSME); /* RESM interrupt disable */ events->suspend(true); } /***** Vbus change *****/ else if ((ists0 & USB_VBINT) == USB_VBINT) { USB_MX.INTSTS0.WORD = (uint16_t)~USB_VBINT; if (chk_vbsts()) { /* USB attach */ USB_MX.SYSCFG0.WORD |= USB_CNEN; } else { /* USB detach */ USB_MX.SYSCFG0.WORD &= (~USB_CNEN); for (i = USB_MIN_PIPE_NO; i < PIPE_NUM; i++) { if (pipe_ctrl[i].enable) { forced_termination(i, (uint16_t)USB_DATA_NONE); } } USB_MX.INTSTS0.WORD = 0; USB_MX.BRDYSTS.WORD = 0; USB_MX.NRDYSTS.WORD = 0; USB_MX.BEMPSTS.WORD = 0; USB_MX.BRDYENB.WORD = 0; USB_MX.NRDYENB.WORD = 0; USB_MX.BEMPENB.WORD = 0; } } /***** SOFR change *****/ else if ((ists0 & USB_SOFR) == USB_SOFR) { USB_MX.INTSTS0.WORD = (uint16_t)~USB_SOFR; events->sof(USB_MX.FRMNUM.BIT.FRNM & USB_FRNM); } /***** Processing device state *****/ /***** DVST change *****/ else if ((ists0 & USB_DVST) == USB_DVST) { USB_MX.INTSTS0.WORD = (uint16_t)~USB_DVST; switch ((uint16_t)(intsts0 & USB_DVSQ)) { case USB_DS_POWR : break; case USB_DS_DFLT : USB_MX.DCPCFG.WORD = 0; /* DCP configuration register (0x5C) */ USB_MX.DCPMAXP.WORD = MAX_PACKET_SIZE_EP0; /* DCP maxpacket size register (0x5E) */ events->reset(); break; case USB_DS_ADDS : break; case USB_DS_CNFG : break; case USB_DS_SPD_POWR : case USB_DS_SPD_DFLT : case USB_DS_SPD_ADDR : case USB_DS_SPD_CNFG : events->suspend(false); break; default : break; } } /***** Processing PIPE0 data *****/ else if (((ists0 & USB_BRDY) == USB_BRDY) && ((bsts & USB_BRDY0) == USB_BRDY0)) { /* ==== BRDY PIPE0 ==== */ USB_MX.BRDYSTS.WORD = (uint16_t)((~USB_BRDY0) & BRDYSTS_MASK); /* When operating by the peripheral function, usb_brdy_pipe() is executed with PIPEx request because */ /* two BRDY messages are issued even when the demand of PIPE0 and PIPEx has been generated at the same time. */ if ((USB_MX.CFIFOSEL.WORD & USB_ISEL_WRITE) == USB_ISEL_WRITE) { switch (write_data(USB_PIPE0)) { case USB_WRITEEND : case USB_WRITESHRT : USB_MX.BRDYENB.WORD &= (~(1 << USB_PIPE0)); break; case USB_WRITING : set_pid(USB_PIPE0, USB_PID_BUF); break; case USB_FIFOERROR : ctrl_end((uint16_t)USB_DATA_ERR); break; default : break; } events->ep0_in(); } else { switch (read_data(USB_PIPE0)) { case USB_READEND : case USB_READSHRT : USB_MX.BRDYENB.WORD &= (~(1 << USB_PIPE0)); pipe_ctrl[USB_PIPE0].req_size -= pipe_ctrl[USB_PIPE0].data_cnt; break; case USB_READING : set_pid(USB_PIPE0, USB_PID_BUF); break; case USB_READOVER : ctrl_end((uint16_t)USB_DATA_OVR); pipe_ctrl[USB_PIPE0].req_size -= pipe_ctrl[USB_PIPE0].data_cnt; break; case USB_FIFOERROR : ctrl_end((uint16_t)USB_DATA_ERR); break; default : break; } events->ep0_out(); } } else if (((ists0 & USB_BEMP) == USB_BEMP) && ((ests & USB_BEMP0) == USB_BEMP0)) { /* ==== BEMP PIPE0 ==== */ USB_MX.BEMPSTS.WORD = (uint16_t)((~USB_BEMP0) & BEMPSTS_MASK); events->ep0_in(); } else if (((ists0 & USB_NRDY) == USB_NRDY) && ((nsts & USB_NRDY0) == USB_NRDY0)) { /* ==== NRDY PIPE0 ==== */ USB_MX.NRDYSTS.WORD = (uint16_t)((~USB_NRDY0) & NRDYSTS_MASK); /* Non processing. */ } /***** Processing setup transaction *****/ else if ((ists0 & USB_CTRT) == USB_CTRT) { USB_MX.INTSTS0.WORD = (uint16_t)~USB_CTRT; /* CTSQ bit changes later than CTRT bit for ASSP. */ /* CTSQ reloading */ uint16_t stginfo = (uint16_t)(intsts0 & USB_CTSQ); if (stginfo != USB_CS_IDST) { if (((USB_CS_RDDS == stginfo) || (USB_CS_WRDS == stginfo)) || (USB_CS_WRND == stginfo)) { /* Save request register */ uint16_t *bufO = &setup_buffer[0]; USB_MX.INTSTS0.WORD = (uint16_t)~USB_VALID; *bufO++ = USB_MX.USBREQ.WORD; /* data[0] <= bmRequest, data[1] <= bmRequestType */ *bufO++ = USB_MX.USBVAL.WORD; /* data[2] data[3] <= wValue */ *bufO++ = USB_MX.USBINDX.WORD; /* data[4] data[5] <= wIndex */ *bufO++ = USB_MX.USBLENG.WORD; /* data[6] data[7] <= wLength */ } } /* Switch on the control transfer stage (CTSQ). */ switch (stginfo) { case USB_CS_IDST : /* Idle or setup stage */ break; case USB_CS_RDDS : /* Control read data stage */ events->ep0_setup(); break; case USB_CS_WRDS : /* Control write data stage */ events->ep0_setup(); break; case USB_CS_WRND : /* Status stage of a control write where there is no data stage. */ events->ep0_setup(); run_later_ctrl_comp = true; break; case USB_CS_RDSS : /* Control read status stage */ USB_MX.DCPCTR.WORD |= USB_CCPL; break; case USB_CS_WRSS : /* Control write status stage */ USB_MX.DCPCTR.WORD |= USB_CCPL; break; case USB_CS_SQER : /* Control sequence error */ default : /* Illegal */ ctrl_end((uint16_t)USB_DATA_ERR); break; } } /***** Processing PIPE1-MAX_PIPE_NO data *****/ else if ((ists0 & USB_BRDY) == USB_BRDY) { /* ==== BRDY PIPEx ==== */ USB_MX.BRDYSTS.WORD = (uint16_t)((~bsts) & BRDYSTS_MASK); for (i = USB_MIN_PIPE_NO; i < PIPE_NUM; i++) { if ((bsts & USB_BITSET(i)) != 0u) { /* Interrupt check */ if (pipe_ctrl[i].enable) { USB_MX.PIPESEL.WORD = i; /* Pipe select */ if (USB_BUF2FIFO == (uint16_t)(USB_MX.PIPECFG.WORD & USB_DIRFIELD)) { /* write */ buf_to_fifo(i); /* Buffer to FIFO data write */ events->in(PIPE2EP(i)); } else { /* read */ fifo_to_buf(i); /* FIFO to Buffer data read */ events->out(PIPE2EP(i)); } } } } } else if ((ists0 & USB_BEMP) == USB_BEMP) { /* ==== BEMP PIPEx ==== */ USB_MX.BEMPSTS.WORD = (uint16_t)((~ests) & BEMPSTS_MASK); for (i = USB_MIN_PIPE_NO; i < PIPE_NUM; i++) { if ((ests & USB_BITSET(i)) != 0) { /* Interrupt check */ if (pipe_ctrl[i].enable) { /* MAX packet size error ? */ if (((get_pid(i) & USB_PID_STALL) == USB_PID_STALL) || ((get_pid(i) & USB_PID_STALL2) == USB_PID_STALL2)) { forced_termination(i, (uint16_t)USB_DATA_STALL); } else { if ((i >= USB_PIPE6) || ((*get_pipectr_reg(i) & USB_INBUFM) != USB_INBUFM)) { data_end(i, (uint16_t)USB_DATA_NONE); /* End of data transfer */ } else { USB_MX.BEMPENB.WORD |= (1 << i); } } events->in(PIPE2EP(i)); } } } } else if ((ists0 & USB_NRDY) == USB_NRDY) { /* ==== NRDY PIPEx ==== */ USB_MX.NRDYSTS.WORD = (uint16_t)((~nsts) & NRDYSTS_MASK); for (i = USB_MIN_PIPE_NO; i < PIPE_NUM; i++) { if ((nsts & USB_BITSET(i)) != 0) { /* Interrupt check */ if (pipe_ctrl[i].enable) { if (((get_pid(i) & USB_PID_STALL) != USB_PID_STALL) && ((get_pid(i) & USB_PID_STALL2) != USB_PID_STALL2)) { set_pid(i, USB_PID_BUF); } } } } } else { /* Non processing. */ } } void USBPhyHw::_usbisr(void) { GIC_DisableIRQ(USBFIX_IRQn); GIC_DisableIRQ(USBHIX_IRQn); run_later_ctrl_comp = false; instance->events->start_process(); if (run_later_ctrl_comp) { USB_MX.DCPCTR.WORD &= (~USB_PID); USB_MX.DCPCTR.WORD |= USB_PID_BUF; USB_MX.DCPCTR.WORD |= USB_CCPL; } // Re-enable interrupt GIC_ClearPendingIRQ(USBFIX_IRQn); GIC_ClearPendingIRQ(USBHIX_IRQn); GIC_EnableIRQ(USBFIX_IRQn); GIC_EnableIRQ(USBHIX_IRQn); } void USBPhyHw::chg_curpipe(uint16_t pipe, uint16_t isel) { uint16_t buf; buf = USB_MX.CFIFOSEL.WORD; buf &= (uint16_t)(~(USB_RCNT | USB_ISEL | USB_CURPIPE | USB_MBW)); buf |= (uint16_t)((USB_RCNT | isel | pipe | USB_MBW_32) & (USB_RCNT | USB_ISEL | USB_CURPIPE | USB_MBW)); USB_MX.CFIFOSEL.WORD = buf; do { cpu_delay_1us(1); buf = USB_MX.CFIFOSEL.WORD; } while ((buf & (uint16_t)(USB_ISEL | USB_CURPIPE)) != (uint16_t)(isel | pipe)); } uint16_t USBPhyHw::is_set_frdy(uint16_t pipe, uint16_t isel) { uint16_t buffer; int retry_cnt = 0; chg_curpipe(pipe, isel); /* Changes the FIFO port by the pipe. */ for (retry_cnt = 0; retry_cnt < 10; retry_cnt++) { buffer = USB_MX.CFIFOCTR.WORD; if ((uint16_t)(buffer & USB_FRDY) == USB_FRDY) { return (buffer); } cpu_delay_1us(1); } return (USB_FIFOERROR); } uint8_t *USBPhyHw::read_fifo(uint16_t pipe, uint16_t count, uint8_t *read_p) { uint16_t even; uint16_t odd; uint32_t odd_byte_data_temp; for (even = (uint16_t)(count >> 2); (even != 0); --even) { /* 32bit FIFO access */ *((uint32_t *)read_p) = USB_MX.CFIFO.LONG; read_p += sizeof(uint32_t); } odd = count % 4; if (count < 4) { odd = count; } if (odd != 0) { /* 32bit FIFO access */ odd_byte_data_temp = USB_MX.CFIFO.LONG; /* Condition compilation by the difference of the endian */ do { *read_p = (uint8_t)(odd_byte_data_temp & 0x000000ff); odd_byte_data_temp = odd_byte_data_temp >> 8; /* Renewal read pointer */ read_p += sizeof(uint8_t); odd--; } while (odd != 0); } return read_p; } uint16_t USBPhyHw::read_data(uint16_t pipe) { uint16_t count; uint16_t buffer; uint16_t mxps; uint16_t dtln; uint16_t end_flag; /* Changes FIFO port by the pipe. */ buffer = is_set_frdy(pipe, 0); if (buffer == USB_FIFOERROR) { return (USB_FIFOERROR); /* FIFO access error */ } dtln = (uint16_t)(buffer & USB_DTLN); /* Max Packet Size */ if (pipe == USB_PIPE0) { mxps = (uint16_t)(USB_MX.DCPMAXP.WORD & USB_MAXP); } else { USB_MX.PIPESEL.WORD = pipe; /* Pipe select */ mxps = (uint16_t)(USB_MX.PIPEMAXP.WORD & USB_MXPS); } if (pipe_ctrl[pipe].data_cnt < dtln) { /* Buffer Over ? */ end_flag = USB_READOVER; set_pid(pipe, USB_PID_NAK); /* Set NAK */ count = (uint16_t)pipe_ctrl[pipe].data_cnt; pipe_ctrl[pipe].data_cnt = dtln; } else if (pipe_ctrl[pipe].data_cnt == dtln) { /* Just Receive Size */ count = dtln; if ((count == 0) || ((dtln % mxps) != 0)) { /* Just Receive Size */ /* Peripheral Function */ end_flag = USB_READSHRT; } else { end_flag = USB_READEND; set_pid(pipe, USB_PID_NAK); /* Set NAK */ } } else { /* Continuous Receive data */ count = dtln; end_flag = USB_READING; if (count == 0) { /* Null Packet receive */ end_flag = USB_READSHRT; set_pid(pipe, USB_PID_NAK); /* Set NAK */ } if ((count % mxps) != 0) { /* Null Packet receive */ end_flag = USB_READSHRT; set_pid(pipe, USB_PID_NAK); /* Set NAK */ } } if (dtln == 0) { /* 0 length packet */ USB_MX.CFIFOCTR.WORD = USB_BCLR; /* Clear BCLR */ } else { pipe_ctrl[pipe].p_data = read_fifo(pipe, count, pipe_ctrl[pipe].p_data); } pipe_ctrl[pipe].data_cnt -= count; return end_flag; } void USBPhyHw::fifo_to_buf(uint16_t pipe) { /* Check FIFO access sequence */ switch (read_data(pipe)) { case USB_READING : /* Continue of data read */ break; case USB_READEND : /* End of data read */ data_end(pipe, (uint16_t)USB_DATA_OK); pipe_ctrl[pipe].req_size -= pipe_ctrl[pipe].data_cnt; break; case USB_READSHRT : /* End of data read */ data_end(pipe, (uint16_t)USB_DATA_SHT); pipe_ctrl[pipe].req_size -= pipe_ctrl[pipe].data_cnt; break; case USB_READOVER : /* Buffer over */ forced_termination(pipe, (uint16_t)USB_DATA_OVR); pipe_ctrl[pipe].req_size -= pipe_ctrl[pipe].data_cnt; break; case USB_FIFOERROR : /* FIFO access error */ default: forced_termination(pipe, (uint16_t)USB_DATA_ERR); break; } } uint8_t *USBPhyHw::write_fifo(uint16_t pipe, uint16_t count, uint8_t *write_p) { uint16_t even; uint16_t odd; set_mbw(pipe, USB_MBW_32); /* 32bit access */ for (even = (uint16_t)(count >> 2); (even != 0); --even) { USB_MX.CFIFO.LONG = *((uint32_t *)write_p); write_p += sizeof(uint32_t); } odd = count % 4; if ((odd & (uint16_t)0x0002u) != 0u) { set_mbw(pipe, USB_MBW_16); /* 16bit access */ USB_MX.CFIFO.WORD.L = *((uint16_t *)write_p); write_p += sizeof(uint16_t); } if ((odd & (uint16_t)0x0001u) != 0u) { set_mbw(pipe, USB_MBW_8); /* 8bit access */ USB_MX.CFIFO.BYTE.LL = *write_p; write_p++; } return write_p; } uint16_t USBPhyHw::write_data(uint16_t pipe) { uint16_t size; uint16_t count; uint16_t mxps; uint16_t end_flag; uint16_t buffer; /* Changes FIFO port by the pipe. */ if (pipe == USB_PIPE0) { buffer = is_set_frdy(pipe, USB_ISEL_WRITE); } else { buffer = is_set_frdy(pipe, 0); } if (buffer == USB_FIFOERROR) { return (USB_FIFOERROR); } if (pipe == USB_PIPE0) { /* Max Packet Size */ mxps = (uint16_t)(USB_MX.DCPMAXP.WORD & USB_MAXP); /* Data buffer size */ if ((USB_MX.DCPCFG.WORD & USB_CNTMDFIELD) == USB_CFG_CNTMDON) { size = USB_PIPE0BUF; } else { size = mxps; } } else { /* Max Packet Size */ USB_MX.PIPESEL.WORD = pipe; /* Pipe select */ mxps = (uint16_t)(USB_MX.PIPEMAXP.WORD & USB_MXPS); /* Data buffer size */ if ((USB_MX.PIPECFG.WORD & USB_CNTMDFIELD) == USB_CFG_CNTMDON) { size = (uint16_t)((uint16_t)((USB_MX.PIPEBUF.WORD >> USB_BUFSIZE_BIT) + 1) * USB_PIPEXBUF); } else { size = mxps; } } /* Data size check */ if (pipe_ctrl[pipe].data_cnt <= (uint32_t)size) { count = (uint16_t)pipe_ctrl[pipe].data_cnt; if (count == 0) { end_flag = USB_WRITESHRT; /* Null Packet is end of write */ } else if ((count % mxps) != 0) { end_flag = USB_WRITESHRT; /* Short Packet is end of write */ } else { end_flag = USB_WRITEEND; /* Just Send Size */ } } else { /* Write continues */ end_flag = USB_WRITING; count = size; } pipe_ctrl[pipe].p_data = write_fifo(pipe, count, pipe_ctrl[pipe].p_data); /* Check data count to remain */ if (pipe_ctrl[pipe].data_cnt < (uint32_t)size) { pipe_ctrl[pipe].data_cnt = 0u; /* Clear data count */ if ((USB_MX.CFIFOCTR.WORD & USB_BVAL) == 0u) { /* Check BVAL */ USB_MX.CFIFOCTR.WORD |= USB_BVAL; /* Short Packet */ } } else { pipe_ctrl[pipe].data_cnt -= count; /* Total data count - count */ } return end_flag; } void USBPhyHw::buf_to_fifo(uint16_t pipe) { /* Disable Ready Interrupt */ USB_MX.BRDYENB.WORD &= (~(1 << pipe)); /* Peripheral control sequence */ switch (write_data(pipe)) { case USB_WRITING: /* Continue of data write */ USB_MX.BRDYENB.WORD |= (1 << pipe); /* Enable Ready Interrupt */ USB_MX.NRDYENB.WORD |= (1 << pipe); /* Enable Not Ready Interrupt */ break; case USB_WRITEEND: /* End of data write */ case USB_WRITESHRT: /* End of data write */ USB_MX.BEMPENB.WORD |= (1 << pipe); /* Enable Empty Interrupt */ USB_MX.NRDYENB.WORD |= (1 << pipe); /* Enable Not Ready Interrupt */ break; case USB_FIFOERROR: /* FIFO access error */ default: forced_termination(pipe, (uint16_t)USB_DATA_ERR); break; } } uint16_t *USBPhyHw::get_pipectr_reg(uint16_t pipe) { if (pipe == USB_PIPE0) { return (uint16_t *) & (USB_MX.DCPCTR); } else { return (uint16_t *) & (USB_MX.PIPE1CTR) + (pipe - USB_PIPE1); } } uint16_t *USBPhyHw::get_pipetre_reg(uint16_t pipe) { if ((pipe >= USB_PIPE1) && (pipe <= USB_PIPE5)) { return (uint16_t *) & (USB_MX.PIPE1TRE) + ((pipe - USB_PIPE1) * 2); } else if ((pipe >= USB_PIPE9) && (pipe <= USB_PIPE10)) { return (uint16_t *) & (USB_MX.PIPE9TRE) + ((pipe - USB_PIPE9) * 2); } else if ((pipe >= USB_PIPE11) && (pipe <= USB_PIPE15)) { return (uint16_t *) & (USB_MX.PIPEBTRE) + ((pipe - USB_PIPE11) * 2); } else { return NULL; } } uint16_t *USBPhyHw::get_pipetrn_reg(uint16_t pipe) { if ((pipe >= USB_PIPE1) && (pipe <= USB_PIPE5)) { return (uint16_t *) & (USB_MX.PIPE1TRN) + ((pipe - USB_PIPE1) * 2); } else if ((pipe >= USB_PIPE9) && (pipe <= USB_PIPE10)) { return (uint16_t *) & (USB_MX.PIPE9TRN) + ((pipe - USB_PIPE9) * 2); } else if ((pipe >= USB_PIPE11) && (pipe <= USB_PIPE15)) { return (uint16_t *) & (USB_MX.PIPEBTRN) + ((pipe - USB_PIPE11) * 2); } else { return NULL; } } uint16_t USBPhyHw::get_pid(uint16_t pipe) { volatile uint16_t *p_reg; p_reg = get_pipectr_reg(pipe); return (uint16_t)(*p_reg & USB_PID); } void USBPhyHw::set_mbw(uint16_t pipe, uint16_t data) { USB_MX.CFIFOSEL.WORD &= (~USB_MBW); if (data != 0) { USB_MX.CFIFOSEL.WORD |= data; } (void)pipe; } void USBPhyHw::set_pid(uint16_t pipe, uint16_t new_pid) { volatile uint16_t *p_reg; uint16_t old_pid; p_reg = get_pipectr_reg(pipe); old_pid = get_pid(pipe); switch (new_pid) { case USB_PID_STALL: if ((old_pid & USB_PID_BUF) == USB_PID_BUF) { *p_reg &= (~USB_PID); *p_reg |= USB_PID_STALL2; } else { *p_reg &= (~USB_PID); *p_reg |= new_pid; } break; case USB_PID_BUF: if (((old_pid & USB_PID_STALL) == USB_PID_STALL) || ((old_pid & USB_PID_STALL2) == USB_PID_STALL2)) { *p_reg &= (~USB_PID); *p_reg |= USB_PID_NAK; } *p_reg &= (~USB_PID); *p_reg |= new_pid; break; case USB_PID_NAK: if ((old_pid & USB_PID_STALL2) == USB_PID_STALL2) { *p_reg &= (~USB_PID); *p_reg |= USB_PID_STALL; } *p_reg &= (~USB_PID); *p_reg |= new_pid; do { cpu_delay_1us(1); p_reg = get_pipectr_reg(pipe); } while ((*p_reg & USB_PBUSY) == USB_PBUSY); break; default: *p_reg &= (~USB_PID); *p_reg |= new_pid; break; } } void USBPhyHw::cpu_delay_1us(uint16_t time) { volatile uint32_t i = 48 * time; while (i > 0) { i--; } } uint16_t USBPhyHw::EP2PIPE(uint16_t endpoint) { const struct PIPECFGREC *cfg; for (cfg = &def_pipecfg[0]; cfg->pipesel != 0; cfg++) { if (cfg->endpoint == endpoint) { break; } } return (cfg->pipesel & USB_CURPIPE); } uint16_t USBPhyHw::PIPE2EP(uint16_t pipe) { const struct PIPECFGREC *cfg; if (pipe == USB_PIPE0) { return 0; } for (cfg = &def_pipecfg[0]; cfg->pipesel != 0; cfg++) { if ((cfg->pipesel & USB_CURPIPE) == pipe) { break; } } return cfg->endpoint; } bool USBPhyHw::chk_vbsts(void) { uint16_t buf1; uint16_t buf2; uint16_t buf3; bool connect_flg = false; /* VBUS chattering cut */ do { buf1 = USB_MX.INTSTS0.WORD; cpu_delay_1us(10); buf2 = USB_MX.INTSTS0.WORD; cpu_delay_1us(10); buf3 = USB_MX.INTSTS0.WORD; } while (((buf1 & USB_VBSTS) != (buf2 & USB_VBSTS)) || ((buf2 & USB_VBSTS) != (buf3 & USB_VBSTS))); /* VBUS status judge */ if ((buf1 & USB_VBSTS) != (uint16_t)0) { connect_flg = true; } return connect_flg; } void USBPhyHw::ctrl_end(uint16_t status) { /* Interrupt disable */ USB_MX.BEMPENB.WORD &= (~(1 << USB_PIPE0)); /* Disable Empty Interrupt */ USB_MX.BRDYENB.WORD &= (~(1 << USB_PIPE0)); /* Disable Ready Interrupt */ USB_MX.NRDYENB.WORD &= (~(1 << USB_PIPE0)); /* Disable Not Ready Interrupt */ set_mbw(USB_PIPE0, USB_MBW_32); if ((status == USB_DATA_ERR) || (status == USB_DATA_OVR)) { set_pid(USB_PIPE0, USB_PID_STALL); /* Request error */ } else if (status == USB_DATA_STOP) { set_pid(USB_PIPE0, USB_PID_NAK); /* Pipe stop */ } else { USB_MX.DCPCTR.WORD |= USB_CCPL; /* Set CCPL bit */ } } void USBPhyHw::data_end(uint16_t pipe, uint16_t status) { volatile uint16_t *p_reg; /* Disable Interrupt */ USB_MX.BRDYENB.WORD &= (~(1 << pipe)); /* Disable Ready Interrupt */ USB_MX.NRDYENB.WORD &= (~(1 << pipe)); /* Disable Not Ready Interrupt */ USB_MX.BEMPENB.WORD &= (~(1 << pipe)); /* Disable Empty Interrupt */ set_pid(pipe, USB_PID_NAK); /* Set NAK */ /* Disable Transaction count */ p_reg = get_pipetre_reg(pipe); if (p_reg != NULL) { *p_reg &= (~USB_TRENB); *p_reg |= USB_TRCLR; } if (pipe_ctrl[pipe].enable) { /* Check PIPE TYPE */ USB_MX.PIPESEL.WORD = pipe; /* Pipe select */ if ((USB_MX.PIPECFG.WORD & USB_TYPFIELD) != USB_TYPFIELD_ISO) { /* Transfer information set */ pipe_ctrl[pipe].enable = false; pipe_ctrl[pipe].status = status; } else if ((uint16_t)(USB_MX.PIPECFG.WORD & USB_DIRFIELD) == USB_BUF2FIFO) { /* ISO OUT Transfer (restart) */ pipe_ctrl[pipe].status = USB_DATA_WRITING; } else { /* ISO IN Transfer (restart) */ pipe_ctrl[pipe].status = USB_DATA_READING; } } } void USBPhyHw::forced_termination(uint16_t pipe, uint16_t status) { volatile uint16_t *p_reg; /* Disable Interrupt */ USB_MX.BRDYENB.WORD &= (~(1 << pipe)); /* Disable Ready Interrupt */ USB_MX.NRDYENB.WORD &= (~(1 << pipe)); /* Disable Not Ready Interrupt */ USB_MX.BEMPENB.WORD &= (~(1 << pipe)); /* Disable Empty Interrupt */ set_pid(pipe, USB_PID_NAK); /* Set NAK */ /* Disable Transaction count */ p_reg = get_pipetre_reg(pipe); if (p_reg != NULL) { *p_reg &= (~USB_TRENB); *p_reg |= USB_TRCLR; } set_mbw(pipe, USB_MBW_32); chg_curpipe(pipe, 0); /* Changes the FIFO port by the pipe. */ p_reg = get_pipectr_reg(pipe); /* Buffer Clear */ *p_reg |= USB_ACLRM; *p_reg &= ~USB_ACLRM; pipe_ctrl[pipe].enable = false; pipe_ctrl[pipe].status = status; } #endif