diff options
author | AJM <poslathian@poslathian.(none)> | 2010-04-20 14:35:58 -0400 |
---|---|---|
committer | bnewbold <bnewbold@robocracy.org> | 2010-05-20 22:09:15 -0400 |
commit | bfb86b6c2ac84c691c150e20adcc1b77d57efd10 (patch) | |
tree | feb5286f411417d6832a417e02e07fe1c775f4e7 /core | |
parent | 0db5696149d8f01275955c94ec55c9c43d7ca390 (diff) | |
download | librambutan-bfb86b6c2ac84c691c150e20adcc1b77d57efd10.tar.gz librambutan-bfb86b6c2ac84c691c150e20adcc1b77d57efd10.zip |
finished the entire low level usb app for virtual com minus the precise handling of get/send data callbacks and toggle line state. completely undebugged for now.
Diffstat (limited to 'core')
-rw-r--r-- | core/usb/README | 4 | ||||
-rw-r--r-- | core/usb/descriptors.c | 16 | ||||
-rw-r--r-- | core/usb/descriptors.h | 8 | ||||
-rw-r--r-- | core/usb/usb.c | 368 | ||||
-rw-r--r-- | core/usb/usb.h | 57 | ||||
-rw-r--r-- | core/usb/usb_callbacks.c | 193 | ||||
-rw-r--r-- | core/usb/usb_callbacks.h | 47 | ||||
-rw-r--r-- | core/usb/usb_config.h | 28 | ||||
-rw-r--r-- | core/usb/usb_hardware.c | 132 | ||||
-rw-r--r-- | core/usb/usb_hardware.h | 145 |
10 files changed, 911 insertions, 87 deletions
diff --git a/core/usb/README b/core/usb/README index ef4964c..e542dde 100644 --- a/core/usb/README +++ b/core/usb/README @@ -19,7 +19,9 @@ Current Status: dependence, and when a new USB core library is written (to nix ST dependence) changes will likely have to be made to virtual com application code. Ideally, the new core library should mimick the form of MyUSB (LUFA), since this library (USB for AVR) is growing in popularity and in example - applications. + applications. Additionally, the usb lib here relies on low level hardware functions that were + just ripped out of the bootloader code (for simplicity) but clearly this should be replaced with + direct accesses to functions provided elsewhere in libmaple. The virtual com port serves two important purposes. 1) is allows serial data transfers between user sketches an a host computer. 2) is allows the host machine to issue a system reset by diff --git a/core/usb/descriptors.c b/core/usb/descriptors.c index bfcd085..27d4250 100644 --- a/core/usb/descriptors.c +++ b/core/usb/descriptors.c @@ -3,7 +3,7 @@ #include "descriptors.h" -USB_Descriptor_Device usbVcomDescriptor_Device = { +const USB_Descriptor_Device usbVcomDescriptor_Device = { bLength: sizeof(USB_Descriptor_Device), bDescriptorType: USB_DESCRIPTOR_TYPE_DEVICE, bcdUSB: 0x0200, @@ -20,7 +20,7 @@ USB_Descriptor_Device usbVcomDescriptor_Device = { bNumConfigurations: 0x01 }; -USB_Descriptor_Configuration usbVcomDescriptor_Config = { +const USB_Descriptor_Configuration usbVcomDescriptor_Config = { Header: { bLength: sizeof(USB_Descriptor_Config_Header), @@ -82,7 +82,7 @@ USB_Descriptor_Configuration usbVcomDescriptor_Config = { { bLength: sizeof(USB_Descriptor_Endpoint), bDescriptorType: USB_DESCRIPTOR_TYPE_ENDPOINT, - bEndpointAddress: VCOM_NOTIFICATION_EPNUM, + bEndpointAddress: (USB_DESCRIPTOR_ENDPOINT_IN | VCOM_NOTIFICATION_EPNUM), bmAttributes: EP_TYPE_INTERRUPT, wMaxPacketSize: VCOM_NOTIFICATION_EPSIZE, bInterval: 0xFF @@ -105,7 +105,7 @@ USB_Descriptor_Configuration usbVcomDescriptor_Config = { { bLength: sizeof(USB_Descriptor_Endpoint), bDescriptorType: USB_DESCRIPTOR_TYPE_ENDPOINT, - bEndpointAddress: VCOM_RX_EPNUM, + bEndpointAddress: (USB_DESCRIPTOR_ENDPOINT_OUT | VCOM_RX_EPNUM), bmAttributes: EP_TYPE_BULK, wMaxPacketSize: VCOM_RX_EPSIZE, bInterval: 0x00 @@ -115,7 +115,7 @@ USB_Descriptor_Configuration usbVcomDescriptor_Config = { { bLength: sizeof(USB_Descriptor_Endpoint), bDescriptorType: USB_DESCRIPTOR_TYPE_ENDPOINT, - bEndpointAddress: VCOM_TX_EPNUM, + bEndpointAddress: (USB_DESCRIPTOR_ENDPOINT_IN | VCOM_TX_EPNUM), bmAttributes: EP_TYPE_BULK, wMaxPacketSize: VCOM_TX_EPSIZE, bInterval: 0x00 @@ -139,21 +139,21 @@ USB_Descriptor_Configuration usbVcomDescriptor_Config = { which is 0x0409 for US English */ -USB_Descriptor_String usbVcomDescriptor_LangID = +const USB_Descriptor_String usbVcomDescriptor_LangID = { bLength: USB_DESCRIPTOR_STRING_LEN(1), bDescriptorType: USB_DESCRIPTOR_TYPE_STRING, bString: 0x0409 }; -USB_Descriptor_String usbVcomDescriptor_iManufacturer = +const USB_Descriptor_String usbVcomDescriptor_iManufacturer = { bLength: USB_DESCRIPTOR_STRING_LEN(8), bDescriptorType: USB_DESCRIPTOR_TYPE_STRING, bString: L"LeafLabs" }; -USB_Descriptor_String usbVcomDescriptor_iProduct = +const USB_Descriptor_String usbVcomDescriptor_iProduct = { bLength: USB_DESCRIPTOR_STRING_LEN(8), bDescriptorType: USB_DESCRIPTOR_TYPE_STRING, diff --git a/core/usb/descriptors.h b/core/usb/descriptors.h index d1918e3..45d791d 100644 --- a/core/usb/descriptors.h +++ b/core/usb/descriptors.h @@ -22,6 +22,9 @@ #define EP_TYPE_INTERRUPT 0x03 #define EP_TYPE_BULK 0x02 +#define USB_DESCRIPTOR_ENDPOINT_IN 0x80 +#define USB_DESCRIPTOR_ENDPOINT_OUT 0x00 + #define USB_DESCRIPTOR_STRING_LEN(x) (2 + (x << 1)) #define CDC_FUCNTIONAL_DESCRIPTOR(DataSize) \ @@ -101,6 +104,11 @@ typedef struct { uint16 bString[]; } USB_Descriptor_String; +extern const USB_Descriptor_Device usbVcomDescriptor_Device; +extern const USB_Descriptor_Config usbVcomDescriptor_Config; +extern const USB_Descriptor_String usbVcomDescriptor_LandID; +extern const USB_Descriptor_String usbVcomDescriptor_iManufacturer; +extern const USB_Descriptor_String usbVcomDescriptor_iProduct; #if defined(__cplusplus) } diff --git a/core/usb/usb.c b/core/usb/usb.c index 8826858..2f458cc 100644 --- a/core/usb/usb.c +++ b/core/usb/usb.c @@ -1,85 +1,331 @@ -#include "libmaple.h" +/* ***************************************************************************** + * The MIT License + * + * Copyright (c) 2010 LeafLabs LLC. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * ****************************************************************************/ + +/** + * @file usb.c + * + * @brief usb-specific hardware setup, NVIC, clocks, and usb activities + * in the pre-attached state. includes some of the lower level callbacks + * needed by the usb library, like suspend,resume,init,etc + */ + #include "usb.h" -#include "usb_regs.h" -#include "bootVect.h" +#include "gpio.h" +#include "usb_callbacks.h" + +/* persistent usb structs */ +volatile uint32 bDeviceState = UNCONNECTED; +volatile uint16 wIstr = 0; +volatile bIntPackSOF = 0; + +DEVICE Device_Table = + { + NUM_ENDPTS, + 1 + }; + +DEVICE_PROP Device_Property = + { + usbInit, + usbReset, + usbStatusIn, + usbStatusOut, + usbDataSetup, + usbNoDataSetup, + usbGetInterfaceSetting, + usbGetDeviceDescriptor, + usbGetInterfaceDescriptor, + usbGetConfigDescriptor, + usbGetStringDescriptor, + usbGetFunctionalDescriptor, + 0, + bMaxPacketSize + }; + +USER_STANDARD_REQUESTS User_Standard_Requests = + { + usbGetConfiguration, + usbSetConfiguration, + usbGetInterface, + usbSetInterface, + usbGetStatus, + usbClearFeature, + usbSetEndpointFeature, + usbSetDeviceFeature, + usbSetDeviceAddress + }; + +void (*pEpInt_IN[7])(void) = +{ + vcomManagementCb, + vcomDataTxCb, + NOP_Process, + NOP_Process, + NOP_Process, + NOP_Process, + NOP_Process, +}; -void usb_lpIRQHandler(void) +void (*pEpInt_OUT[7])(void) = { - typedef void (*funcPtr)(void); - - const uint32_t usbIsrAddr = *(uint32_t*)(USB_ISR_ADDR); - void (*ptrToUsbISR)(void) = (funcPtr) usbIsrAddr; - ptrToUsbISR(); -} + NOP_Process, + NOP_Process, + vcomDataRxCb, + NOP_Process, + NOP_Process, + NOP_Process, + NOP_Process, +}; -void usb_userToPMABufferCopy(uint8 *pbUsrBuf, uint16 wPMABufAddr, uint16 wNBytes) +struct { - uint32 n = (wNBytes + 1) >> 1; /* n = (wNBytes + 1) / 2 */ - uint32 i, temp1, temp2; - uint16 *pdwVal; - pdwVal = (uint16 *)(wPMABufAddr * 2 + PMAAddr); - for (i = n; i != 0; i--) - { - temp1 = (uint16) * pbUsrBuf; - pbUsrBuf++; - temp2 = temp1 | (uint16) * pbUsrBuf << 8; - *pdwVal++ = temp2; - pdwVal++; - pbUsrBuf++; - } + volatile RESUME_STATE eState; + volatile uint8 bESOFcnt; +} ResumeS; + +void setupUSB (void) { + gpio_set_mode(USB_DISC_BANK, + USB_DISC_PIN, + GPIO_MODE_OUTPUT_PP); + + /* setup the apb1 clock for USB */ + pRCC->APB1ENR |= 0x00800000; + + /* initialize the usb application */ + gpio_write_bit(USB_DISC_BANK,USB_DISC_PIN,0); /* present ourselves to the host */ + USB_Init(); /* low level init routine provided by st lib */ + } -void usb_PMAToUserBufferCopy(uint8 *pbUsrBuf, uint16 wPMABufAddr, uint16 wNBytes) -{ - uint32 n = (wNBytes + 1) >> 1;/* /2*/ - uint32 i; - uint32 *pdwVal; - pdwVal = (uint32 *)(wPMABufAddr * 2 + PMAAddr); - for (i = n; i != 0; i--) - { - *(uint16*)pbUsrBuf++ = *pdwVal++; - pbUsrBuf++; - } +void usbSuspend(void) { + u16 wCNTR; + wCNTR = _GetCNTR(); + wCNTR |= CNTR_FSUSP | CNTR_LPMODE; + _SetCNTR(wCNTR); + + /* run any power reduction handlers */ + bDeviceState = SUSPENDED; } -void usb_serialWriteStr(const char* outStr) { - uint8 offset=0; - BootVectTable *bootVector = ((BootVectTable*)BOOTLOADER_VECT_TABLE); +void usbResumeInit(void) { + u16 wCNTR; - while ((outStr[offset] != '\0') - && (offset < USB_SERIAL_BUF_SIZE)) { - offset++; - } + /* restart any clocks that had been stopped */ + + wCNTR = _GetCNTR(); + wCNTR &= (~CNTR_LPMODE); + _SetCNTR(wCNTR); + + /* undo power reduction handlers here */ - delay(offset*1); + _SetCNTR(ISR_MSK); - bootVector->serial_count_in = (uint32*) &offset; - usb_userToPMABufferCopy((uint8*)outStr,USB_SERIAL_ENDP_TXADDR,offset); - _SetEPTxCount(USB_SERIAL_ENDP_TX,offset); - _SetEPTxValid(USB_SERIAL_ENDP_TX); +} + +void usbResume(RESUME_STATE eResumeSetVal) { + u16 wCNTR; + if (eResumeSetVal != RESUME_ESOF) + ResumeS.eState = eResumeSetVal; + + switch (ResumeS.eState) + { + case RESUME_EXTERNAL: + usbResumeInit(); + ResumeS.eState = RESUME_OFF; + break; + case RESUME_INTERNAL: + usbResumeInit(); + ResumeS.eState = RESUME_START; + break; + case RESUME_LATER: + ResumeS.bESOFcnt = 2; + ResumeS.eState = RESUME_WAIT; + break; + case RESUME_WAIT: + ResumeS.bESOFcnt--; + if (ResumeS.bESOFcnt == 0) + ResumeS.eState = RESUME_START; + break; + case RESUME_START: + wCNTR = _GetCNTR(); + wCNTR |= CNTR_RESUME; + _SetCNTR(wCNTR); + ResumeS.eState = RESUME_ON; + ResumeS.bESOFcnt = 10; + break; + case RESUME_ON: + ResumeS.bESOFcnt--; + if (ResumeS.bESOFcnt == 0) + { + wCNTR = _GetCNTR(); + wCNTR &= (~CNTR_RESUME); + _SetCNTR(wCNTR); + ResumeS.eState = RESUME_OFF; + } + break; + case RESUME_OFF: + case RESUME_ESOF: + default: + ResumeS.eState = RESUME_OFF; + break; + } } -void usb_serialWriteChar(unsigned char ch) { - BootVectTable *bootVector = ((BootVectTable*)BOOTLOADER_VECT_TABLE); +RESULT usbPowerOn(void) { + u16 wRegVal; + + wRegVal = CNTR_FRES; + _SetCNTR(wRegVal); + + wInterrupt_Mask = 0; + _SetCNTR(wInterrupt_Mask); + _SetISTR(0); + wInterrupt_Mask = CNTR_RESETM | CNTR_SUSPM | CNTR_WKUPM; /* the bare minimum */ + _SetCNTR(wInterrupt_Mask); - delay(1); + return USB_SUCCESS; +} + +RESULT usbPowerOff(void) { + _SetCNTR(CNTR_FRES); + _SetISTR(0); + _SetCNTR(CNTR_FRES + CNTR_PDWN); - *(bootVector->serial_count_in) = 1; - usb_userToPMABufferCopy((uint8*)(&ch),USB_SERIAL_ENDP_TXADDR,1); - _SetEPTxCount(USB_SERIAL_ENDP_TX,1); - _SetEPTxValid(USB_SERIAL_ENDP_TX); + /* note that all weve done here is powerdown the + usb peripheral. we have no disabled the clocks, + pulled the usb_disc pin back up, or reset the + application state machines */ + return USB_SUCCESS; } -uint8 usb_serialGetRecvLen() { - uint8 count_out =_GetEPRxCount(USB_SERIAL_ENDP_RX); - return count_out; +void usbEnbISR(void) { + NVIC_InitTypeDef NVIC_InitStructure; + + + NVIC_InitStructure.NVIC_IRQChannel = USB_LP_IRQ; + NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; + NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; + NVIC_InitStructure.NVIC_IRQChannelCmd = TRUE; + nvicInit(&NVIC_InitStructure); } -void usb_copyRecvBuffer(unsigned char* dest, uint8 len) { - ASSERT(len < USB_SERIAL_BUF_SIZE); - usb_PMAToUserBufferCopy((uint8*)(dest),USB_SERIAL_ENDP_RXADDR,len); - _SetEPRxValid(USB_SERIAL_ENDP_RX); +void usbDsbISR(void) { + NVIC_InitTypeDef NVIC_InitStructure; + NVIC_InitStructure.NVIC_IRQChannel = USB_LP_IRQ; + NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; + NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; + NVIC_InitStructure.NVIC_IRQChannelCmd = FALSE; + nvicInit(&NVIC_InitStructure); } +/* overloaded ISR routine, this is the main usb ISR */ +void usb_lpIRQHandler(void); +wIstr = _GetISTR(); + +/* go nuts with the preproc switches since this is an ISTR and must be FAST */ +#if (ISR_MSK & ISTR_RESET) +if (wIstr & ISTR_RESET & wInterrupt_Mask) + { + _SetISTR((u16)CLR_RESET); + Device_Property.Reset(); + } +#endif + + +#if (ISR_MSK & ISTR_DOVR) +if (wIstr & ISTR_DOVR & wInterrupt_Mask) + { + _SetISTR((u16)CLR_DOVR); + } +#endif + + +#if (ISR_MSK & ISTR_ERR) +if (wIstr & ISTR_ERR & wInterrupt_Mask) + { + _SetISTR((u16)CLR_ERR); + } +#endif + + +#if (ISR_MSK & ISTR_WKUP) +if (wIstr & ISTR_WKUP & wInterrupt_Mask) + { + _SetISTR((u16)CLR_WKUP); + usbResume(RESUME_EXTERNAL); + } +#endif + +/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ +#if (ISR_MSK & ISTR_SUSP) +if (wIstr & ISTR_SUSP & wInterrupt_Mask) + { + + /* check if SUSPEND is possible */ + if (F_SUSPEND_ENABLED) + { + usbSuspend(); + } + else + { + /* if not possible then resume after xx ms */ + usbResume(RESUME_LATER); + } + /* clear of the ISTR bit must be done after setting of CNTR_FSUSP */ + _SetISTR((u16)CLR_SUSP); + } +#endif + + +#if (ISR_MSK & ISTR_SOF) +if (wIstr & ISTR_SOF & wInterrupt_Mask) + { + _SetISTR((u16)CLR_SOF); + bIntPackSOF++; + } +#endif + + +#if (ISR_MSK & ISTR_ESOF) +if (wIstr & ISTR_ESOF & wInterrupt_Mask) + { + _SetISTR((u16)CLR_ESOF); + /* resume handling timing is made with ESOFs */ + usbResume(RESUME_ESOF); /* request without change of the machine state */ + } +#endif + +/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ +#if (ISR_MSK & ISTR_CTR) +if (wIstr & ISTR_CTR & wInterrupt_Mask) + { + /* servicing of the endpoint correct transfer interrupt */ + /* clear of the CTR flag into the sub */ + CTR_LP(); /* low priority ISR defined in the usb core lib */ + } +#endif + +} diff --git a/core/usb/usb.h b/core/usb/usb.h index fa40123..b2bf23c 100644 --- a/core/usb/usb.h +++ b/core/usb/usb.h @@ -1,24 +1,51 @@ -#ifndef _USB_H_ -#define _USB_H_ +/* insert license */ -#define USB_ISR_ADDR (0x08000090) -#define USB_SERIAL_ENDP_TXADDR ((uint32) 0xC0) -#define USB_SERIAL_ENDP_RXADDR ((uint32) 0x110) -#define USB_SERIAL_ENDP_TX ((uint16) 0x1) -#define USB_SERIAL_ENDP_RX ((uint16) 0x3) -#define USB_SERIAL_BUF_SIZE (0x40) +#ifndef __USB_H_ +#define __USB_H_ + +#include "usb_config.h" +#include "usb_callbacks.h" +#include "usb_lib.h" #ifdef __cplusplus extern "C" { #endif -void usb_lpIRQHandler(void); -void usb_userToPMABufferCopy(uint8 *pbUsrBuf,uint16 wPMABufAddr,uint16 wNBytes); -void usb_PMAToUserBufferCopy(uint8 *pbUsrBuf,uint16 wPMABufAddr,uint16 wNBytes); -void usb_serialWriteStr(const char *outStr); -void usb_serialWriteChar(unsigned char ch); -uint8_t usb_serialGetRecvLen(); -void usb_copyRecvBuffer(unsigned char* dest, uint8 len); +typedef enum + { + RESUME_EXTERNAL, + RESUME_INTERNAL, + RESUME_LATER, + RESUME_WAIT, + RESUME_START, + RESUME_ON, + RESUME_OFF, + RESUME_ESOF + } RESUME_STATE; + +typedef enum + { + UNCONNECTED, + ATTACHED, + POWERED, + SUSPENDED, + ADDRESSED, + CONFIGURED + } DEVICE_STATE; + + void setupUSB(void); + void usbSuspend(void); + void usbResumeInit(void); + void usbResume(RESUME_STATE); + + RESULT usbPowerOn(void); + RESULT usbPowerOff(void); + + void usbDsbISR(void); + void usbEnbISR(void); + + /* overloaded ISR routine, this is the main usb ISR */ + void usb_lpIRQHandler(void); #ifdef __cplusplus } // extern "C" diff --git a/core/usb/usb_callbacks.c b/core/usb/usb_callbacks.c new file mode 100644 index 0000000..a3febed --- /dev/null +++ b/core/usb/usb_callbacks.c @@ -0,0 +1,193 @@ +/* insert license */ + +#include "usb_callbacks.h" +#include "usb_lib.h" +#include "usb_descriptors.h" + +ONE_DESCRIPTOR Device_Descriptor = { + (uint8*)usbVcomDescriptor_Device, + sizeof(USB_Descriptor_Device) +}; + +ONE_DESCRIPTOR Config_Descriptor = { + (uint8*)usbVcomDescriptor_Config, + sizeof(USB_Descriptor_Config) +}; + +ONE_DESCRIPTOR String_Descriptor[3] = { + {(uint8*)usbVcomDescriptor_LangID, USB_DESCRIPTOR_STRING_LEN(1)}, + {(uint8*)usbVcomDescriptor_iManufacturer,USB_DESCRIPTOR_STRING_LEN(8)}, + {(uint8*)usbVcomDescriptor_iProduct, USB_DESCRIPTOR_STRING_LEN(8)} +}; + +uint8 last_request = 0; + +USB_Line_Coding line_coding = { + bitrate: 115200, + format: 0x00, /* stop bits-1 */ + paritytype: 0x00, + datatype: 0x08 +}; + +void vcomDataTxCb(void) { + /* do whatever after data has been sent to host */ +} + +void vcomDataRxCb(void) { + /* do whatever after data has been received from host */ +} + +void vcomManagementCb(void) { + /* unused. This enpoint would callback if we had sent a linestate + changed notification */ +} + +u8* vcomGetSetLineCoding(uint16 length) { + if (length == 0) { + pInformation->Ctrl_Info.Usb_wLength = sizeof(Line_Coding); + } + return (uint8*)&line_coding; +} + +void vcomSetLineSate(uint16 wValue); + +void usbInit(void) { + pInformation->Current_Configuration = 0; + usbPowerOn(); + + _SetISTR(0); + wInterrupt_Mas = ISR_MSK; + _SetCNTR(wInterrupt_Mask); + + usbEnbISR(); + bDeviceState = UNCONNECTED; +} + +void usbReset(void) { + pInformation->Current_Configuration = 0; + + /* current feature is current bmAttributes */ + pInformation->Current_Feature = (USB_CONFIG_ATTR_BUSPOWERED | USB_CONFIG_ATTR_SELFPOWERED); + + _SetBTABLE(USB_BTABLE_ADDRESS); + + /* setup control endpoint 0 */ + _SetEPType(ENDP0, EP_CONTROL); + _SetEPTxStatus(ENDP0, EP_TX_STALL); + _SetEPRxAddr(ENDP0,VCOM_CTRL_RX_ADDR); + _SetEpTxAddr(ENDP0,VCOM_CTRL_TX_ADDR); + Clear_Status_Out(ENDP0); + + SetEPRxCount(ENDP0, pProperty->MaxPacketSize); + SetEPRxValid(ENDP0); + + /* setup management endpoint 1 */ + SetEPType (VCOM_NOTIFICATION_ENDP, EP_INTERRUPT); + SetEPTxAddr (VCOM_NOTIFICATION_ENDP, VCOM_NOTIFICATION_ADDR); + SetEPTxStatus (VCOM_NOTIFICATION_ENDP, EP_TX_NAK); + SetEPRxStatus (VCOM_NOTIFICATION_ENDP, EP_RX_DIS); + + /* setup data endpoint OUT (rx) */ + SetEPType (VCOM_RX_ENDP, EP_BULK); + SetEPRxAddr (VCOM_RX_ENDP, VCOM_RX_ADDR); + SetEPRxCount (VCOM_RX_ENDP, VCOM_RX_SIZE); + SetEPTxStatus (VCOM_RX_ENDP, EP_TX_DIS); + SetEPRxStatus (VCOM_RX_ENDP, EP_RX_VALID); + + /* setup data endpoint IN (tx) */ + SetEPType (VCOM_TX_ENDP, EP_BULK); + SetEPRxAddr (VCOM_TX_ENDP, VCOM_TX_ADDR); + SetEPRxCount (VCOM_TX_ENDP, VCOM_TX_SIZE); + SetEPTxStatus (VCOM_TX_ENDP, EP_TX_NAK); + SetEPRxStatus (VCOM_TX_ENDP, EP_RX_DIS); + + bDeviceState = ATTACHED; + SetDeviceAddress(0); +} + + +void usbStatusIn(void) { + /* adjust the usart line coding + if we wish to couple the CDC line coding + with the real usart port */ +} + +void usbStatusOut(void) { +} + +RESULT usbDataSetup(uint8 request) { + uint8 *(*CopyRoutine)(uint16); + CopyRoutine = NULL; + + if (Type_Recipient == (CLASS_REQUEST | INTERFACE_RECIPIENT)) { + switch (request) { + case (GET_LINE_CODING): + CopyRoutine = vcomGetSetLineCoding; + last_request = GET_LINE_CODING; + break; + case (SET_LINE_CODING): + CopyRoutine = vcomGetSetLineCoding; + last_request = SET_LINE_CODING; + break; + default: break; + } + } + + if (CopyRoutine == NULL) { + return USB_UNSUPPORT; + } + + pInformation->Ctrl_Info.CopyData = CopyRoutine; + pInformation->Ctrl_Info.Usb_wOffset = 0; + (*CopyRoutine)(0); + return USB_SUCCESS; +} + +RESULT usbNoDataSetup(u8 request) { + /* we support set com feature but dont handle it */ + if (Type_Recipient == (CLASS_REQUEST | INTERFACE_RECIPIENT)) { + switch (request) { + case (SET_COMM_FEATURE): + return USB_SUCCESS; + case (SET_CONTROL_LINE_STATE): + /* handle the control line status signal (reset?) */ + return USB_SUCCESS; + } + } + return USB_UNSUPPORT; +} + +RESULT usbGetInterfaceSetting(uint8 interface, uint8 alt_setting) { + if (alt_setting > 0) { + return USB_UNSUPPORT; + } else if (interface > 1) { + return USB_UNSUPPORT; + } + + return USB_SUCCESS; +} + + +u8* usbGetDeviceDescriptor(u16 length) { + return Standard_GetDescriptorData(length, &Device_Descriptor); +} + +u8* usbGetConfigDescriptor(u16 length) { + return Standard_GetDescriptorData(length, &Config_Descriptor); +} + +u8* usbGetStringDescriptor(u16 length) { + return Standard_GetDescriptorData(length, &String_Descriptor); +} + +/* internal callbacks to respond to standard requests */ +void usbSetConfiguration(void) { + if (pInformation->Current_Configuration != 0) { + bDeviceState = CONFIGURED; + } +} + +void usbSetDeviceAddress(void) { + bDeviceState = ADDRESSED; +} + diff --git a/core/usb/usb_callbacks.h b/core/usb/usb_callbacks.h new file mode 100644 index 0000000..4fe287f --- /dev/null +++ b/core/usb/usb_callbacks.h @@ -0,0 +1,47 @@ +#define SET_LINE_CODING 0x20 +#define GET_LINE_CODING 0x21 +#define SET_CONTROL_LINE_STATE 0x22 +#define CONTROL_LINE_DTR (1 << 0) +#define CONTROL_LINE_RTS (1 << 1) + +typedef struct { + uint32 bitrate; + uint8 format; + uint8 paritytype; + uint8 datatype; +} USB_Line_Coding; + +void vcomDataTxCb(void); +void vcomDataRxCb(void); +void vcomManagementCb(void); + +u8* vcomGetSetLineCoding(uint16 length); +void vcomSetLineSate(uint16 wValue); + +void usbInit(void); +/* internal functions (as per the usb_core pProperty structure) */ +void usbInit(void); +void usbReset(void); +void usbStatusIn(void); +void usbStatusOut(void); + +RESULT usbDataSetup(u8 request); +RESULT usbNoDataSetup(u8 request); +RESULT usbGetInterfaceSetting(u8,u8); + +u8* usbGetDeviceDescriptor(u16 length); +u8* usbGetConfigDescriptor(u16 length); +u8* usbGetStringDescriptor(u16 length); +u8* usbGetFunctionalDescriptor(u16 length); + +/* internal callbacks to respond to standard requests */ +void usbGetConfiguration(void); +void usbSetConfiguration(void); +void usbGetInterface(void); +void usbSetInterface(void); +void usbGetStatus(void); +void usbClearFeature(void); +void usbSetEndpointFeature(void); +void usbSetDeviceFeature(void); +void usbSetDeviceAddress(void); + diff --git a/core/usb/usb_config.h b/core/usb/usb_config.h index bf5f4ff..b457677 100644 --- a/core/usb/usb_config.h +++ b/core/usb/usb_config.h @@ -3,6 +3,8 @@ #ifndef __USB_CONFIG_H #define __USB_CONFIG_H +#include "usb_lib.h" + #define VCOM_ID_VENDOR 0x0110 #define VCOM_ID_PRODUCT 0x1003 @@ -11,20 +13,42 @@ /* choose addresses to give endpoints the max 64 byte buffers */ #define USB_BTABLE_ADDRESS 0x00 #define VCOM_CTRL_EPNUM 0x00 -#define VCOM_CTRL_RX_ADDR 0x40 -#define VCOM_CTRL_TX_ADDR 0x80 +#define VCOM_CTRL_TX_ADDR 0x40 +#define VCOM_CTRL_RX_ADDR 0x80 #define VCOM_CTRL_EPSIZE 0x40 +#define VCOM_NOTIFICATION_ENDP ENDP1 #define VCOM_NOTIFICATION_EPNUM 0x01 #define VCOM_NOTIFICATION_ADDR 0xC0 #define VCOM_NOTIFICATION_EPSIZE 0x40 +#define VCOM_TX_ENDP ENDP2 #define VCOM_TX_EPNUM 0x02 #define VCOM_TX_ADDR 0x100 #define VCOM_TX_SIZE 0x040 +#define VCOM_RX_ENDP ENDP3 #define VCOM_RX_EPNUM 0x03 #define VCOM_RX_ADDR 0x140 #define VCOM_RX_EPSIZE 0x40 +#define bMaxPacketSize 0x40 /* 64B, maximum for USB FS Devices */ + +#define NUM_ENDPTS 0x03 + +/* handle all usb interrupts */ +#define ISR_MSK (CNTR_CTRM | \ + CNTR_WKUPM | \ + CNTR_SUSPM | \ + CNTR_ERRM | \ + CNTR_SOFM | \ + CNTR_ESOFM | \ + CNTR_RESETM | \ + ) + +#define USB_DISC_BANK GPIOC_BASE +#define USB_DISC_PIN 12 + +#define F_SUSPEND_ENABLED 1 + #endif diff --git a/core/usb/usb_hardware.c b/core/usb/usb_hardware.c new file mode 100644 index 0000000..10918ca --- /dev/null +++ b/core/usb/usb_hardware.c @@ -0,0 +1,132 @@ +/* ***************************************************************************** + * The MIT License + * + * Copyright (c) 2010 LeafLabs LLC. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * ****************************************************************************/ + +/** + * @file hardware.c + * + * @brief init routines to setup clocks and interrupts for usb. + * + */ + +#include "hardware.h" + +void setPin(u32 bank, u8 pin) { + u32 pinMask = 0x1 << (pin); + SET_REG(GPIO_BSRR(bank),pinMask); +} + +void resetPin(u32 bank, u8 pin) { + u32 pinMask = 0x1 << (16+pin); + SET_REG(GPIO_BSRR(bank),pinMask); +} + +void systemReset(void) { + SET_REG(RCC_CR, GET_REG(RCC_CR) | 0x00000001); + SET_REG(RCC_CFGR, GET_REG(RCC_CFGR) & 0xF8FF0000); + SET_REG(RCC_CR, GET_REG(RCC_CR) & 0xFEF6FFFF); + SET_REG(RCC_CR, GET_REG(RCC_CR) & 0xFFFBFFFF); + SET_REG(RCC_CFGR, GET_REG(RCC_CFGR) & 0xFF80FFFF); + + SET_REG(RCC_CIR, 0x00000000); /* disable all RCC interrupts */ +} + +void setupCLK (void) { + /* enable HSE */ + SET_REG(RCC_CR,GET_REG(RCC_CR) | 0x00010001); + while ((GET_REG(RCC_CR) & 0x00020000) == 0); /* for it to come on */ + + /* enable flash prefetch buffer */ + SET_REG(FLASH_ACR, 0x00000012); + + /* Configure PLL */ + SET_REG(RCC_CFGR,GET_REG(RCC_CFGR) | 0x001D0400); /* pll=72Mhz,APB1=36Mhz,AHB=72Mhz */ + SET_REG(RCC_CR,GET_REG(RCC_CR) | 0x01000000); /* enable the pll */ + while ((GET_REG(RCC_CR) & 0x03000000) == 0); /* wait for it to come on */ + + /* Set SYSCLK as PLL */ + SET_REG(RCC_CFGR,GET_REG(RCC_CFGR) | 0x00000002); + while ((GET_REG(RCC_CFGR) & 0x00000008) == 0); /* wait for it to come on */ +} + + +void nvicInit(NVIC_InitTypeDef* NVIC_InitStruct) { + u32 tmppriority = 0x00; + u32 tmpreg = 0x00; + u32 tmpmask = 0x00; + u32 tmppre = 0; + u32 tmpsub = 0x0F; + + SCB_TypeDef* rSCB = (SCB_TypeDef *) SCB_BASE; + NVIC_TypeDef* rNVIC = (NVIC_TypeDef *) NVIC_BASE; + + + /* Compute the Corresponding IRQ Priority --------------------------------*/ + tmppriority = (0x700 - (rSCB->AIRCR & (u32)0x700))>> 0x08; + tmppre = (0x4 - tmppriority); + tmpsub = tmpsub >> tmppriority; + + tmppriority = (u32)NVIC_InitStruct->NVIC_IRQChannelPreemptionPriority << tmppre; + tmppriority |= NVIC_InitStruct->NVIC_IRQChannelSubPriority & tmpsub; + + tmppriority = tmppriority << 0x04; + tmppriority = ((u32)tmppriority) << ((NVIC_InitStruct->NVIC_IRQChannel & (u8)0x03) * 0x08); + + tmpreg = rNVIC->IPR[(NVIC_InitStruct->NVIC_IRQChannel >> 0x02)]; + tmpmask = (u32)0xFF << ((NVIC_InitStruct->NVIC_IRQChannel & (u8)0x03) * 0x08); + tmpreg &= ~tmpmask; + tmppriority &= tmpmask; + tmpreg |= tmppriority; + + rNVIC->IPR[(NVIC_InitStruct->NVIC_IRQChannel >> 0x02)] = tmpreg; + + /* Enable the Selected IRQ Channels --------------------------------------*/ + rNVIC->ISER[(NVIC_InitStruct->NVIC_IRQChannel >> 0x05)] = + (u32)0x01 << (NVIC_InitStruct->NVIC_IRQChannel & (u8)0x1F); +} + +void nvicDisableInterrupts() { + NVIC_TypeDef* rNVIC = (NVIC_TypeDef *) NVIC_BASE; + rNVIC->ICER[0] = 0xFFFFFFFF; + rNVIC->ICER[1] = 0xFFFFFFFF; + rNVIC->ICPR[0] = 0xFFFFFFFF; + rNVIC->ICPR[1] = 0xFFFFFFFF; + + SET_REG(STK_CTRL,0x04); /* disable the systick, which operates separately from nvic */ +} + +void systemHardReset(void) { + SCB_TypeDef* rSCB = (SCB_TypeDef *) SCB_BASE; + typedef void (*funcPtr)(void); + + /* Reset */ + rSCB->AIRCR = (u32)AIRCR_RESET_REQ; + + /* should never get here */ + while (1) { + asm volatile("nop"); + } +} + + + diff --git a/core/usb/usb_hardware.h b/core/usb/usb_hardware.h new file mode 100644 index 0000000..e60567d --- /dev/null +++ b/core/usb/usb_hardware.h @@ -0,0 +1,145 @@ +/* ***************************************************************************** + * The MIT License + * + * Copyright (c) 2010 LeafLabs LLC. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * ****************************************************************************/ + +#ifndef __HARDWARE_H +#define __HARDWARE_H + +#include "stm32f10x_type.h" +#include "cortexm3_macro.h" + +/* macro'd register and peripheral definitions */ +#define RCC ((u32)0x40021000) +#define FLASH ((u32)0x40022000) +#define GPIOA ((u32)0x40010800) +#define GPIOC ((u32)0x40011000) + +#define RCC_CR RCC +#define RCC_CFGR RCC + 0x04 +#define RCC_CIR RCC + 0x08 +#define RCC_AHBENR RCC + 0x14 +#define RCC_APB2ENR RCC + 0x18 +#define RCC_APB1ENR RCC + 0x16 + +#define GPIO_CRL(port) port +#define GPIO_CRH(port) port+0x04 +#define GPIO_ODR(port) port+0x0c +#define GPIO_BSRR(port) port+0x10 + +#define SCS_BASE ((u32)0xE000E000) +#define NVIC_BASE (SCS_BASE + 0x0100) +#define SCB_BASE (SCS_BASE + 0x0D00) + +#define SCS 0xE000E000 +#define NVIC (SCS+0x100) +#define SCB (SCS+0xD00) +#define STK (SCS+0x10) + +#define SCB_VTOR (SCB+0x08) +#define STK_CTRL (STK+0x00) + +#define USB_HP_IRQ ((u8)0x13) +#define USB_LP_IRQ ((u8)0x14) + +/* AIRCR */ +#define AIRCR_RESET 0x05FA0000 +#define AIRCR_RESET_REQ (AIRCR_RESET | (u32)0x04); + +/* temporary copyage of example from kiel */ +#define __VAL(__TIMCLK, __PERIOD) ((__TIMCLK/1000000UL)*__PERIOD) +#define __PSC(__TIMCLK, __PERIOD) (((__VAL(__TIMCLK, __PERIOD)+49999UL)/50000UL) - 1) +#define __ARR(__TIMCLK, __PERIOD) ((__VAL(__TIMCLK, __PERIOD)/(__PSC(__TIMCLK, __PERIOD)+1)) - 1) + +/* todo, wrap in do whiles for the natural ; */ +#define SET_REG(addr,val) *(vu32*)(addr)=val +#define GET_REG(addr) *(vu32*)(addr) + + +/* todo: there must be some major misunderstanding in how we access regs. The direct access approach (GET_REG) + causes the usb init to fail upon trying to activate RCC_APB1 |= 0x00800000. However, using the struct approach + from ST, it works fine...temporarily switching to that approach */ +typedef struct +{ + vu32 CR; + vu32 CFGR; + vu32 CIR; + vu32 APB2RSTR; + vu32 APB1RSTR; + vu32 AHBENR; + vu32 APB2ENR; + vu32 APB1ENR; + vu32 BDCR; + vu32 CSR; +} RCC_RegStruct; +#define pRCC ((RCC_RegStruct *) RCC) + +typedef struct { + vu32 ISER[2]; + u32 RESERVED0[30]; + vu32 ICER[2]; + u32 RSERVED1[30]; + vu32 ISPR[2]; + u32 RESERVED2[30]; + vu32 ICPR[2]; + u32 RESERVED3[30]; + vu32 IABR[2]; + u32 RESERVED4[62]; + vu32 IPR[15]; +} NVIC_TypeDef; + +typedef struct { + u8 NVIC_IRQChannel; + u8 NVIC_IRQChannelPreemptionPriority; + u8 NVIC_IRQChannelSubPriority; + bool NVIC_IRQChannelCmd; /* TRUE for enable */ +} NVIC_InitTypeDef; + +typedef struct { + vuc32 CPUID; + vu32 ICSR; + vu32 VTOR; + vu32 AIRCR; + vu32 SCR; + vu32 CCR; + vu32 SHPR[3]; + vu32 SHCSR; + vu32 CFSR; + vu32 HFSR; + vu32 DFSR; + vu32 MMFAR; + vu32 BFAR; + vu32 AFSR; +} SCB_TypeDef; + + +void setPin (u32 bank, u8 pin); +void resetPin (u32 bank, u8 pin); + +void systemHardReset(void); +void systemReset (void); +void setupCLK (void); + +void nvicInit (NVIC_InitTypeDef*); +void nvicDisableInterrupts(void); + +#endif |