📄 usb.c
字号:
}
}
/* EP2 Tx */
void USB_ep2_tx(void) {
UCR2_TX2E=0; /* disable EP2 transmitter */
UIR2_TXD2FR = 1; /* clear the interrupt flag to make sure the packet transmits */
if (usb_ep2_dcntT==0) return; /* no data to transmit - return without enabling the transmitter */
/* transmit data from the buffer (must be in Zero Page) */
UE2D0 = *(usb_dptr++); /* copy all 8 bytes, packet might be shorter than 8 bytes */
UE2D1 = *(usb_dptr++);
UE2D2 = *(usb_dptr++);
UE2D3 = *(usb_dptr++);
UE2D4 = *(usb_dptr++);
UE2D5 = *(usb_dptr++);
UE2D6 = *(usb_dptr++);
UE2D7 = *(usb_dptr++);
if (usb_ep2_dcntT>8) {
UCR2 = ((UCR2^UCR2_T2SEQ_MASK)&UCR2_T2SEQ_MASK) | UCR2_TX2E_MASK | UCR2_RX2E_MASK + 8; /* enable transmission on EP2, toggle DATA0/1, length 8 (more data in buffer) */
usb_ep2_dcntT-=8;
} else {
UCR2 = ((UCR2^UCR2_T2SEQ_MASK)&UCR2_T2SEQ_MASK) | UCR2_TX2E_MASK | UCR2_RX2E_MASK + usb_ep2_dcntT; /* enable transmission on EP2, toggle DATA0/1, length according to count */
usb_ep2_dcntT = 0; /* no more data to transmit */
}
}
/* EP0 Rx */
void USB_ep0_rx(void) {
unsigned char * ptr=&UE0D0;
while ((ptr<((&UE0D0)+8))&&(usb_ep0_dcntR)) {
*(usb_dptr++) = *(ptr++); /* copy data */
usb_ep0_dcntR--; /* decrement count */
}
if (usb_ep0_dcntR==0) {
/* command reception complete */
command_exec();
usb_ep0_dcntT=0xff; /* make sure the Tx routine does not interpret the subsequent IRQ incorrectly */
usb_ep0_zeroterm=0; /* switch zero-length termination off */
UCR0 = UCR0_TOSEQ_MASK | UCR0_TX0E_MASK | UCR0_RX0E_MASK; /* enable transmission on EP0, DATA1, lenght 0 (status packet for the control transfer) */
}
}
/* EP2 Rx */
void USB_ep2_rx(void) {
/* EP2 receives the messages in raw format (size of cmd+data, cmd, data0, data1, ...) */
unsigned char * ptr=&UE2D0;
if (usb_ep2_dcntR==0) {
/* if the routine is called with no data to be received, it must be beginning of a message */
UCR2_TX2E=0; /* disable EP2 transmitter */
usb_ep2_dcntR=UE2D0;
usb_dptr=command_buffer;
ptr = &UE2D1; /* skip copying the size */
}
while ((ptr<((&UE2D0)+8))&&(usb_ep2_dcntR)) {
*(usb_dptr++) = *(ptr++); /* copy data */
usb_ep2_dcntR--; /* decrement count */
}
if (usb_ep2_dcntR==0) {
/* command reception complete */
usb_ep2_dcntT = command_exec();
usb_dptr = command_buffer;
USB_ep2_tx(); /* start transmitting the data */
}
}
/* handles the set-up frame */
void USB_Setup(void) {
usb_ep0_dcntT=0xff; /* stop any data transfer in progress upon reception of a new setup packet */
usb_ep0_zeroterm=0; /* switch zero-length termination off */
if (USR0!=USR0_SETUP_MASK + 8) { /* check whether it is valid setup request (DATA0 && size==8) */
UCR3 = UCR3_ISTALL0_MASK | UCR3_OSTALL0_MASK; /* stall EP0 communication and wait for new setup */
} else {
UCR0_TOSEQ=0; /* each setup transaction needs to start with DATA1 response (DATA0/1 inverted in tx) */
if (((*(setup_packet*)&UE0D0).bmRequestType&0x60)==0) { /* standard request? */
switch ((*(setup_packet*)&UE0D0).bRequest) {
case SET_CONFIGURATION:
if ((*(setup_packet*)&UE0D0).wValue.lo) {
/* non-zero configuration number */
/* initialise EP2 */
UCR3 |= UCR3_ENABLE2_MASK; /* enable EP2 */
UCR2 = UCR2_T2SEQ_MASK | UCR2_RX2E_MASK; /* enable EP2 receiver, transaction starts with DATA0 and the flag is inverted before transmitting */
usb_ep0_dcntT=0xff; /* bring the state machine into a known idle state */
usb_ep0_dcntR=0;
usb_ep2_dcntT=0;
usb_ep2_dcntR=0;
USB_State = US_CONFIGURED; /* change state */
} else {
/* configuration zero means back to addressed state */
USB_State = US_ADDRESSED;
}
/* next send back the confirmation... */
case SET_INTERFACE:
/* do nothing, just send back a confirmation */
case SET_ADDRESS:
/* Note: address of the device is going to change only after this transmission is completed */
case CLEAR_FEATURE:
/* clear feature does nothing, just sends a confirmation */
UCR0 = UCR0_TOSEQ_MASK | UCR0_TX0E_MASK | UCR0_RX0E_MASK; /* enable transmission on EP0, DATA1, lenght 0 (confirmation of new address reception) */
return;
case GET_CONFIGURATION:
if (USB_State == US_CONFIGURED) UE0D0 = 1; else UE0D0 = 0;
UCR0 = UCR0_TOSEQ_MASK | UCR0_TX0E_MASK | UCR0_RX0E_MASK + 1; /* enable transmission on EP0, DATA1, lenght 1 */
case GET_DESCRIPTOR:
{
unsigned char requested_length;
if ((*(setup_packet*)&UE0D0).wLength.hi) requested_length=0xff; else /* no descriptor is longer than 255 bytes... */
requested_length=(*(setup_packet*)&UE0D0).wLength.lo;
/* which descriptor? */
switch ((*(setup_packet*)&UE0D0).wValue.hi) {
case DT_DEVICE: /* device descriptor */
copydown(sizeof(device_descriptor), &DeviceDesc, command_buffer); /* copy descriptor to the buffer */
usb_ep0_dcntT = sizeof(device_descriptor); /* update count */
usb_dptr = command_buffer; /* data to transmit */
if (usb_ep0_dcntT>=requested_length) {
usb_ep0_dcntT=requested_length;
} else {
usb_ep0_zeroterm=1;
}
USB_ep0_tx(); /* start transmitting the data */
break;
case DT_CONFIGURATION:
copydown(sizeof(config_data), &config_data, command_buffer); /* copy descriptor to the buffer */
usb_ep0_dcntT = sizeof(config_data); /* update count */
usb_dptr = command_buffer; /* data to transmit */
if (usb_ep0_dcntT>=requested_length) {
usb_ep0_dcntT=requested_length;
} else {
usb_ep0_zeroterm=1;
}
USB_ep0_tx(); /* start transmitting the data */
break;
case DT_STRING:
usb_ep0_dcntT = copystring((*(setup_packet*)&UE0D0).wValue.lo, command_buffer);
usb_dptr = command_buffer; /* data to transmit */
if (usb_ep0_dcntT>=requested_length) {
usb_ep0_dcntT=requested_length;
} else {
usb_ep0_zeroterm=1;
}
USB_ep0_tx(); /* start transmitting the data */
break;
}
}
return;
}
} else if (((*(setup_packet*)&UE0D0).bmRequestType&0x60)==0x40) { /* vendor specific request? */
if ((*(setup_packet*)&UE0D0).bmRequestType&0x80) {
/* transfer dir device->host (it will be a command which reads data from the target or command which has 5 or less bytes) */
/* transfer 5 bytes from the status frame to the buffer */
command_buffer[1]=UE0D1; /* cmd */
command_buffer[2]=UE0D2; /* data0 */
command_buffer[3]=UE0D3; /* data1 */
command_buffer[4]=UE0D4; /* data2 */
command_buffer[5]=UE0D5; /* data3 */
usb_ep0_dcntT=(*(setup_packet*)&UE0D0).wLength.lo; /* save transmit size, the host MUST NOT request more than 254 bytes! */
command_exec();
usb_dptr = command_buffer; /* point to data to return to the host */
USB_ep0_tx(); /* start transmitting the data (or send an empty status frame in case there is no data to transmit) */
} else {
/* transfer dir host->device (it will be a command which writes data to the target) */
/* transfer size is 5+length (5 first bytes are thransferred in the setup frame) */
command_buffer[1]=UE0D1; /* cmd */
command_buffer[2]=UE0D2; /* data0 */
command_buffer[3]=UE0D3; /* data1 */
command_buffer[4]=UE0D4; /* data2 */
command_buffer[5]=UE0D5; /* data3 */
usb_ep0_dcntR=(*(setup_packet*)&UE0D0).wLength.lo; /* the host MUST NOT send more data than will fit into the buffer!! */
if (usb_ep0_dcntR==0) {
/* no more data to follow */
USB_ep0_rx(); /* the routine will not copy any data, but will launch command execution and status frame transmit */
/* this is cleaner as this code is in one place only */
return;
}
/* data to follow, set-up pointer */
usb_dptr = command_buffer+6; /* first 5 bytes stored already starting from position 1 */
}
return;
}
/* non-standard or unsupported request */
UCR3 = UCR3_ISTALL0_MASK | UCR3_OSTALL0_MASK; /* stall EP0 communication and wait for new setup */
}
}
/* USB interrupt service routine */
void interrupt usb_isr(void) {
suspend_timer=0; /* keep the device out of stop */
if (UIR1_EOPF) {
usb_1ms_tick(); /* call timing routine */
UIR2_EOPFR = 1; /* clear the flag */
} else {
if (led_timer<255) led_timer++; /* interrupt request has a different reason, perform correction of LED tick (it is not going to be accurate, but this is better than nothing) */
if (UIR1_RXD0F) { /* EP0 Rx complete */
UCR0_RX0E=0; /* deactivate receiver */
if (USR0_SETUP) { /* was it a setup frame? */
USB_Setup(); /* handle the setup frame */
} else { /* other EP0 Rx */
if (USR0_RP0SIZ) USB_ep0_rx(); /* EP0 receives either zero-length status frames or valid data */
}
UIR2_RXD0FR = 1; /* clear the flag and enable further reception */
UCR0_RX0E=1; /* reactivate receiver */
} else if (UIR1_TXD0F) { /* EP0 Tx complete */
USB_ep0_tx(); /* handle Tx on EP0 */
UIR2_TXD0FR = 1; /* clear the flag */
} else if (UIR1_RXD2F) { /* EP2 Rx complete */
UCR2_RX2E=0; /* deactivate receiver */
USB_ep2_rx(); /* receive the data */
UIR2_RXD2FR = 1; /* clear the flag and enable further reception */
UCR2_RX2E=1; /* reactivate receiver */
} else if (UIR1_TXD2F) { /* EP2 Tx complete */
USB_ep2_tx(); /* handle Tx on EP0 */
UIR2_TXD2FR = 1; /* clear the flag */
} else if (UIR1_RSTF) { /* bus reset */
usb_init(); /* soft reset the USB interface */
USB_State = US_DEFAULT; /* change the state to reflect the reset has occured */
UCR0 = UCR0_RX0E_MASK; /* enable EP0 reception */
UIR2_RSTFR = 1; /* clear the flag */
} else if (UIR1_RESUMF) { /* resume interrupt */
UIR0_SUSPND = 0; /* clear the suspend flag */
UIR2_RESUMFR = 1; /* clear the interrupt flag */
usb_ep0_dcntT=0xff; /* special meaning - means no transmission in progress */
usb_ep0_dcntR=0; /* no data to receive */
usb_ep2_dcntT=0; /* no data to transmit */
usb_ep2_dcntR=0; /* no data to receive */
led_timer=0;
led_state=LED_ON;
}
}
}
/* initialise the USB peripheral */
void usb_init(void) {
usb_ep0_dcntT=0xff; /* special meaning - means no transmission in progress */
usb_ep0_dcntR=0; /* no data to receive */
usb_ep2_dcntT=0; /* no data to transmit */
usb_ep2_dcntR=0; /* no data to receive */
led_timer=0;
led_state=LED_ON;
LED_INIT; /* usb interrupt drives the LED, so make sure it is initialised */
UADDR = UADDR_USBEN_MASK; /* enable the USB module, assign address to the default value (0) */
UIR0 = UIR0_RXD2IE_MASK | UIR0_RXD0IE_MASK | UIR0_TXD2IE_MASK | UIR0_TXD0IE_MASK | UIR0_EOPIE_MASK; /* enable Rx&Tx interupts on EP0 & EP2, enable end of frame interrupt */
UCR0 = 0; /* reset EP0 */
UCR1 = 0; /* reset EP1 */
UCR2 = 0; /* reset EP2 */
UCR4 = 0; /* normal operation */
UCR3 = UCR3_TX1STR_MASK ; /*NO Pullup clear TX1ST & enable internal pull-up */
USB_State = US_POWERED; /* must be powered when running this code... */
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -