openpilot is an open source driver assistance system. openpilot performs the functions of Automated Lane Centering and Adaptive Cruise Control for over 200 supported car makes and models.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

510 lines
15 KiB

// **** supporting defines ****
typedef struct
{
__IO uint32_t HPRT;
}
USB_OTG_HostPortTypeDef;
#define USBx_HOST ((USB_OTG_HostTypeDef *)((uint32_t)USBx + USB_OTG_HOST_BASE))
#define USBx_HOST_PORT ((USB_OTG_HostPortTypeDef *)((uint32_t)USBx + USB_OTG_HOST_PORT_BASE))
#define USBx_DEVICE ((USB_OTG_DeviceTypeDef *)((uint32_t)USBx + USB_OTG_DEVICE_BASE))
#define USBx_INEP(i) ((USB_OTG_INEndpointTypeDef *)((uint32_t)USBx + USB_OTG_IN_ENDPOINT_BASE + (i)*USB_OTG_EP_REG_SIZE))
#define USBx_OUTEP(i) ((USB_OTG_OUTEndpointTypeDef *)((uint32_t)USBx + USB_OTG_OUT_ENDPOINT_BASE + (i)*USB_OTG_EP_REG_SIZE))
#define USBx_DFIFO(i) *(__IO uint32_t *)((uint32_t)USBx + USB_OTG_FIFO_BASE + (i) * USB_OTG_FIFO_SIZE)
#define USBx_PCGCCTL *(__IO uint32_t *)((uint32_t)USBx + USB_OTG_PCGCCTL_BASE)
#define USB_REQ_GET_STATUS 0x00
#define USB_REQ_CLEAR_FEATURE 0x01
#define USB_REQ_SET_FEATURE 0x03
#define USB_REQ_SET_ADDRESS 0x05
#define USB_REQ_GET_DESCRIPTOR 0x06
#define USB_REQ_SET_DESCRIPTOR 0x07
#define USB_REQ_GET_CONFIGURATION 0x08
#define USB_REQ_SET_CONFIGURATION 0x09
#define USB_REQ_GET_INTERFACE 0x0A
#define USB_REQ_SET_INTERFACE 0x0B
#define USB_REQ_SYNCH_FRAME 0x0C
#define USB_DESC_TYPE_DEVICE 1
#define USB_DESC_TYPE_CONFIGURATION 2
#define USB_DESC_TYPE_STRING 3
#define USB_DESC_TYPE_INTERFACE 4
#define USB_DESC_TYPE_ENDPOINT 5
#define USB_DESC_TYPE_DEVICE_QUALIFIER 6
#define USB_DESC_TYPE_OTHER_SPEED_CONFIGURATION 7
#define STS_GOUT_NAK 1
#define STS_DATA_UPDT 2
#define STS_XFER_COMP 3
#define STS_SETUP_COMP 4
#define STS_SETUP_UPDT 6
#define USBD_FS_TRDT_VALUE 5
// interfaces
void usb_cb_control_msg();
void usb_cb_ep1_in(int len);
void usb_cb_ep2_out(uint8_t *usbdata, int len);
void usb_cb_ep3_out(uint8_t *usbdata, int len);
uint8_t device_desc[] = {
0x12,0x01,0x00,0x01,
0xFF,0xFF,0xFF,0x40,
(USB_VID>>0)&0xFF,(USB_VID>>8)&0xFF,
(USB_PID>>0)&0xFF,(USB_PID>>8)&0xFF,
0x00,0x22,0x00,0x00,
0x00,0x01};
uint8_t configuration_desc[] = {
0x09, 0x02, 0x27, 0x00,
0x01, 0x01, 0x00, 0xc0,
0x32,
// interface 0
0x09, 0x04, 0x00, 0x00,
0x03, 0xff, 0xFF, 0xFF,
0x00,
// endpoint 1, read CAN
0x07, 0x05, 0x81, 0x02, 0x40, 0x00, 0x00,
// endpoint 2, AES load
0x07, 0x05, 0x02, 0x02, 0x10, 0x00, 0x00,
// endpoint 3, send CAN
0x07, 0x05, 0x03, 0x02, 0x40, 0x00, 0x00,
};
typedef union
{
uint16_t w;
struct BW
{
uint8_t msb;
uint8_t lsb;
}
bw;
}
uint16_t_uint8_t;
typedef union _USB_Setup
{
uint32_t d8[2];
struct _SetupPkt_Struc
{
uint8_t bmRequestType;
uint8_t bRequest;
uint16_t_uint8_t wValue;
uint16_t_uint8_t wIndex;
uint16_t_uint8_t wLength;
} b;
}
USB_Setup_TypeDef;
// current packet
USB_Setup_TypeDef setup;
uint8_t usbdata[0x100];
// packet read and write
void *USB_ReadPacket(void *dest, uint16_t len) {
uint32_t i=0;
uint32_t count32b = (len + 3) / 4;
for ( i = 0; i < count32b; i++, dest += 4 ) {
// packed?
*(__attribute__((__packed__)) uint32_t *)dest = USBx_DFIFO(0);
}
return ((void *)dest);
}
void USB_WritePacket(const uint8_t *src, uint16_t len, uint32_t ep) {
#ifdef DEBUG
puts("writing ");
hexdump(src, len);
#endif
uint32_t count32b = 0, i = 0;
count32b = (len + 3) / 4;
// bullshit
USBx_INEP(ep)->DIEPTSIZ = (USB_OTG_DIEPTSIZ_PKTCNT & (1 << 19)) | (len & USB_OTG_DIEPTSIZ_XFRSIZ);
USBx_INEP(ep)->DIEPCTL |= (USB_OTG_DIEPCTL_CNAK | USB_OTG_DIEPCTL_EPENA);
// load the FIFO
for (i = 0; i < count32b; i++, src += 4) {
USBx_DFIFO(ep) = *((__attribute__((__packed__)) uint32_t *)src);
}
}
void usb_reset() {
// unmask endpoint interrupts, so many sets
USBx_DEVICE->DAINT = 0xFFFFFFFF;
USBx_DEVICE->DAINTMSK = 0xFFFFFFFF;
//USBx_DEVICE->DOEPMSK = (USB_OTG_DOEPMSK_STUPM | USB_OTG_DOEPMSK_XFRCM | USB_OTG_DOEPMSK_EPDM);
//USBx_DEVICE->DIEPMSK = (USB_OTG_DIEPMSK_TOM | USB_OTG_DIEPMSK_XFRCM | USB_OTG_DIEPMSK_EPDM | USB_OTG_DIEPMSK_ITTXFEMSK);
//USBx_DEVICE->DIEPMSK = (USB_OTG_DIEPMSK_TOM | USB_OTG_DIEPMSK_XFRCM | USB_OTG_DIEPMSK_EPDM);
// all interrupts for debugging
USBx_DEVICE->DIEPMSK = 0xFFFFFFFF;
USBx_DEVICE->DOEPMSK = 0xFFFFFFFF;
// clear interrupts
USBx_INEP(0)->DIEPINT = 0xFF;
USBx_OUTEP(0)->DOEPINT = 0xFF;
// unset the address
USBx_DEVICE->DCFG &= ~USB_OTG_DCFG_DAD;
// set up USB FIFOs
// RX start address is fixed to 0
USBx->GRXFSIZ = 0x40;
// 0x100 to offset past GRXFSIZ
USBx->DIEPTXF0_HNPTXFSIZ = (0x40 << 16) | 0x40;
// EP1, massive
USBx->DIEPTXF[0] = (0x40 << 16) | 0x80;
// flush TX fifo
USBx->GRSTCTL = USB_OTG_GRSTCTL_TXFFLSH | USB_OTG_GRSTCTL_TXFNUM_4;
while ((USBx->GRSTCTL & USB_OTG_GRSTCTL_TXFFLSH) == USB_OTG_GRSTCTL_TXFFLSH);
// flush RX FIFO
USBx->GRSTCTL = USB_OTG_GRSTCTL_RXFFLSH;
while ((USBx->GRSTCTL & USB_OTG_GRSTCTL_RXFFLSH) == USB_OTG_GRSTCTL_RXFFLSH);
// no global NAK
USBx_DEVICE->DCTL |= USB_OTG_DCTL_CGINAK;
// ready to receive setup packets
USBx_OUTEP(0)->DOEPTSIZ = USB_OTG_DOEPTSIZ_STUPCNT | (USB_OTG_DOEPTSIZ_PKTCNT & (1 << 19)) | (3 * 8);
}
void usb_setup() {
uint8_t resp[0x20];
// setup packet is ready
switch (setup.b.bRequest) {
case USB_REQ_SET_CONFIGURATION:
// enable other endpoints, has to be here?
USBx_INEP(1)->DIEPCTL = (0x40 & USB_OTG_DIEPCTL_MPSIZ) | (2 << 18) | (1 << 22) |
USB_OTG_DIEPCTL_SD0PID_SEVNFRM | USB_OTG_DIEPCTL_USBAEP;
USBx_INEP(1)->DIEPINT = 0xFF;
USBx_OUTEP(2)->DOEPTSIZ = (1 << 19) | 0x10;
USBx_OUTEP(2)->DOEPCTL = (0x10 & USB_OTG_DOEPCTL_MPSIZ) | (2 << 18) |
USB_OTG_DOEPCTL_SD0PID_SEVNFRM | USB_OTG_DOEPCTL_USBAEP;
USBx_OUTEP(2)->DOEPINT = 0xFF;
USBx_OUTEP(3)->DOEPTSIZ = (1 << 19) | 0x40;
USBx_OUTEP(3)->DOEPCTL = (0x40 & USB_OTG_DOEPCTL_MPSIZ) | (2 << 18) |
USB_OTG_DOEPCTL_SD0PID_SEVNFRM | USB_OTG_DOEPCTL_USBAEP;
USBx_OUTEP(3)->DOEPINT = 0xFF;
// mark ready to receive
USBx_OUTEP(2)->DOEPCTL |= USB_OTG_DOEPCTL_EPENA | USB_OTG_DOEPCTL_CNAK;
USBx_OUTEP(3)->DOEPCTL |= USB_OTG_DOEPCTL_EPENA | USB_OTG_DOEPCTL_CNAK;
USB_WritePacket(0, 0, 0);
USBx_OUTEP(0)->DOEPCTL |= USB_OTG_DOEPCTL_CNAK;
break;
case USB_REQ_SET_ADDRESS:
// set now?
USBx_DEVICE->DCFG |= ((setup.b.wValue.w & 0x7f) << 4);
#ifdef DEBUG
puts(" set address\n");
#endif
USB_WritePacket(0, 0, 0);
USBx_OUTEP(0)->DOEPCTL |= USB_OTG_DOEPCTL_CNAK;
break;
case USB_REQ_GET_DESCRIPTOR:
switch (setup.b.wValue.bw.lsb) {
case USB_DESC_TYPE_DEVICE:
//puts(" writing device descriptor\n");
// setup transfer
USB_WritePacket(device_desc, min(sizeof(device_desc), setup.b.wLength.w), 0);
USBx_OUTEP(0)->DOEPCTL |= USB_OTG_DOEPCTL_CNAK;
//puts("D");
break;
case USB_DESC_TYPE_CONFIGURATION:
USB_WritePacket(configuration_desc, min(sizeof(configuration_desc), setup.b.wLength.w), 0);
USBx_OUTEP(0)->DOEPCTL |= USB_OTG_DOEPCTL_CNAK;
break;
default:
// nothing here?
USB_WritePacket(0, 0, 0);
USBx_OUTEP(0)->DOEPCTL |= USB_OTG_DOEPCTL_CNAK;
break;
}
break;
case USB_REQ_GET_STATUS:
// empty resp?
resp[0] = 0;
resp[1] = 0;
USB_WritePacket((void*)&resp, 2, 0);
USBx_OUTEP(0)->DOEPCTL |= USB_OTG_DOEPCTL_CNAK;
break;
default:
usb_cb_control_msg();
}
}
void usb_init() {
// internal PHY set before reset
USBx->GUSBCFG |= USB_OTG_GUSBCFG_PHYSEL;
// full speed PHY, do reset and remove power down
puth(USBx->GRSTCTL);
puts(" resetting PHY\n");
while ((USBx->GRSTCTL & USB_OTG_GRSTCTL_AHBIDL) == 0);
puts("AHB idle\n");
// reset PHY here?
USBx->GRSTCTL |= USB_OTG_GRSTCTL_CSRST;
while ((USBx->GRSTCTL & USB_OTG_GRSTCTL_CSRST) == USB_OTG_GRSTCTL_CSRST);
puts("reset done\n");
// power up the PHY
USBx->GCCFG = USB_OTG_GCCFG_PWRDWN | USB_OTG_GCCFG_NOVBUSSENS;
// be a device, slowest timings
//USBx->GUSBCFG = USB_OTG_GUSBCFG_FDMOD | USB_OTG_GUSBCFG_PHYSEL | USB_OTG_GUSBCFG_TRDT | USB_OTG_GUSBCFG_TOCAL;
USBx->GUSBCFG = USB_OTG_GUSBCFG_FDMOD | USB_OTG_GUSBCFG_PHYSEL;
USBx->GUSBCFG |= (uint32_t)((USBD_FS_TRDT_VALUE << 10) & USB_OTG_GUSBCFG_TRDT);
//USBx->GUSBCFG = USB_OTG_GUSBCFG_PHYSEL | USB_OTG_GUSBCFG_TRDT | USB_OTG_GUSBCFG_TOCAL;
// **** for debugging, doesn't seem to work ****
//USBx->GUSBCFG |= USB_OTG_GUSBCFG_CTXPKT;
// reset PHY clock
USBx_PCGCCTL = 0;
// enable the fancy OTG things
USBx->GUSBCFG |= USB_OTG_GUSBCFG_HNPCAP | USB_OTG_GUSBCFG_SRPCAP;
USBx_DEVICE->DCFG = USB_OTG_DCFG_NZLSOHSK | USB_OTG_DCFG_DSPD;
//USBx_DEVICE->DCFG = USB_OTG_DCFG_DSPD;
// setup USB interrupts
// all interrupts except TXFIFO EMPTY
//USBx->GINTMSK = 0xFFFFFFFF & ~(USB_OTG_GINTMSK_NPTXFEM | USB_OTG_GINTMSK_PTXFEM | USB_OTG_GINTSTS_SOF | USB_OTG_GINTSTS_EOPF);
USBx->GINTMSK = 0xFFFFFFFF & ~(USB_OTG_GINTMSK_NPTXFEM | USB_OTG_GINTMSK_PTXFEM);
USBx->GAHBCFG = USB_OTG_GAHBCFG_GINT;
USBx->GINTSTS = 0;
}
// ***************************** USB port *****************************
void usb_irqhandler(void) {
USBx->GINTMSK = 0;
unsigned int gintsts = USBx->GINTSTS;
// gintsts SUSPEND? 04008428
#ifdef DEBUG
unsigned int daint = USBx_DEVICE->DAINT;
puth(gintsts);
puts(" ep ");
puth(daint);
puts(" USB interrupt!\n");
#endif
if (gintsts & USB_OTG_GINTSTS_ESUSP) {
puts("ESUSP detected\n");
}
if (gintsts & USB_OTG_GINTSTS_USBRST) {
puts("USB reset\n");
usb_reset();
}
if (gintsts & USB_OTG_GINTSTS_ENUMDNE) {
puts("enumeration done ");
// Full speed, ENUMSPD
puth(USBx_DEVICE->DSTS);
puts("\n");
}
if (gintsts & USB_OTG_GINTSTS_OTGINT) {
puts("OTG int:");
puth(USBx->GOTGINT);
puts("\n");
// getting ADTOCHG
USBx->GOTGINT = USBx->GOTGINT;
}
// RX FIFO first
if (gintsts & USB_OTG_GINTSTS_RXFLVL) {
// 1. Read the Receive status pop register
volatile unsigned int rxst = USBx->GRXSTSP;
#ifdef DEBUG
puts(" RX FIFO:");
puth(rxst);
puts(" status: ");
puth((rxst & USB_OTG_GRXSTSP_PKTSTS) >> 17);
puts(" len: ");
puth((rxst & USB_OTG_GRXSTSP_BCNT) >> 4);
puts("\n");
#endif
if (((rxst & USB_OTG_GRXSTSP_PKTSTS) >> 17) == STS_DATA_UPDT) {
int endpoint = (rxst & USB_OTG_GRXSTSP_EPNUM);
int len = (rxst & USB_OTG_GRXSTSP_BCNT) >> 4;
USB_ReadPacket(&usbdata, len);
#ifdef DEBUG
puts(" data ");
puth(len);
puts("\n");
hexdump(&usbdata, len);
#endif
if (endpoint == 2) {
usb_cb_ep2_out(usbdata, len);
}
if (endpoint == 3) {
usb_cb_ep3_out(usbdata, len);
}
} else if (((rxst & USB_OTG_GRXSTSP_PKTSTS) >> 17) == STS_SETUP_UPDT) {
USB_ReadPacket(&setup, 8);
#ifdef DEBUG
puts(" setup ");
hexdump(&setup, 8);
puts("\n");
#endif
}
}
if (gintsts & USB_OTG_GINTSTS_HPRTINT) {
// host
puts("HPRT:");
puth(USBx_HOST_PORT->HPRT);
puts("\n");
if (USBx_HOST_PORT->HPRT & USB_OTG_HPRT_PCDET) {
USBx_HOST_PORT->HPRT |= USB_OTG_HPRT_PRST;
USBx_HOST_PORT->HPRT |= USB_OTG_HPRT_PCDET;
}
}
if (gintsts & USB_OTG_GINTSTS_BOUTNAKEFF) {
// no global NAK, why is this getting set?
#ifdef DEBUG
puts("GLOBAL NAK\n");
#endif
USBx_DEVICE->DCTL |= USB_OTG_DCTL_CGONAK | USB_OTG_DCTL_CGINAK;
}
if (gintsts & USB_OTG_GINTSTS_SRQINT) {
// we want to do "A-device host negotiation protocol" since we are the A-device
puts("start request\n");
//USBx->GUSBCFG |= USB_OTG_GUSBCFG_FDMOD;
//USBx_HOST_PORT->HPRT = USB_OTG_HPRT_PPWR | USB_OTG_HPRT_PENA;
}
// out endpoint hit
if (gintsts & USB_OTG_GINTSTS_OEPINT) {
#ifdef DEBUG
puts(" 0:");
puth(USBx_OUTEP(0)->DOEPINT);
puts(" 2:");
puth(USBx_OUTEP(2)->DOEPINT);
puts(" 3:");
puth(USBx_OUTEP(3)->DOEPINT);
puts(" ");
puth(USBx_OUTEP(3)->DOEPCTL);
puts(" 4:");
puth(USBx_OUTEP(4)->DOEPINT);
puts(" OUT ENDPOINT\n");
#endif
if (USBx_OUTEP(2)->DOEPINT & USB_OTG_DOEPINT_XFRC) {
#ifdef DEBUG
puts(" OUT2 PACKET XFRC\n");
#endif
USBx_OUTEP(2)->DOEPTSIZ = (1 << 19) | 0x10;
USBx_OUTEP(2)->DOEPCTL |= USB_OTG_DOEPCTL_EPENA | USB_OTG_DOEPCTL_CNAK;
}
if (USBx_OUTEP(3)->DOEPINT & USB_OTG_DOEPINT_XFRC) {
#ifdef DEBUG
puts(" OUT3 PACKET XFRC\n");
#endif
USBx_OUTEP(3)->DOEPTSIZ = (1 << 19) | 0x40;
USBx_OUTEP(3)->DOEPCTL |= USB_OTG_DOEPCTL_EPENA | USB_OTG_DOEPCTL_CNAK;
} else if (USBx_OUTEP(3)->DOEPINT & 0x2000) {
#ifdef DEBUG
puts(" OUT3 PACKET WTF\n");
#endif
// if NAK was set trigger this, unknown interrupt
USBx_OUTEP(3)->DOEPTSIZ = (1 << 19) | 0x40;
USBx_OUTEP(3)->DOEPCTL |= USB_OTG_DOEPCTL_CNAK;
} else if (USBx_OUTEP(3)->DOEPINT) {
puts("OUTEP3 error ");
puth(USBx_OUTEP(3)->DOEPINT);
puts("\n");
}
if (USBx_OUTEP(0)->DOEPINT & USB_OTG_DIEPINT_XFRC) {
// ready for next packet
USBx_OUTEP(0)->DOEPTSIZ = USB_OTG_DOEPTSIZ_STUPCNT | (USB_OTG_DOEPTSIZ_PKTCNT & (1 << 19)) | (1 * 8);
}
// respond to setup packets
if (USBx_OUTEP(0)->DOEPINT & USB_OTG_DOEPINT_STUP) {
usb_setup();
}
USBx_OUTEP(0)->DOEPINT = USBx_OUTEP(0)->DOEPINT;
USBx_OUTEP(2)->DOEPINT = USBx_OUTEP(2)->DOEPINT;
USBx_OUTEP(3)->DOEPINT = USBx_OUTEP(3)->DOEPINT;
}
// in endpoint hit
if (gintsts & USB_OTG_GINTSTS_IEPINT) {
#ifdef DEBUG
puts(" ");
puth(USBx_INEP(0)->DIEPINT);
puts(" ");
puth(USBx_INEP(1)->DIEPINT);
puts(" IN ENDPOINT\n");
#endif
// this happens first
if (USBx_INEP(1)->DIEPINT & USB_OTG_DIEPINT_XFRC) {
#ifdef DEBUG
puts(" IN PACKET SEND\n");
#endif
//USBx_DEVICE->DIEPEMPMSK = ~(1 << 1);
}
// *** IN token received when TxFIFO is empty
if (USBx_INEP(1)->DIEPINT & USB_OTG_DIEPMSK_ITTXFEMSK) {
#ifdef DEBUG
puts(" IN PACKET QUEUE\n");
#endif
// TODO: always assuming max len, can we get the length?
usb_cb_ep1_in(0x40);
}
// clear interrupts
USBx_INEP(0)->DIEPINT = USBx_INEP(0)->DIEPINT;
USBx_INEP(1)->DIEPINT = USBx_INEP(1)->DIEPINT;
}
// clear all interrupts
USBx_DEVICE->DAINT = USBx_DEVICE->DAINT;
USBx->GINTSTS = USBx->GINTSTS;
USBx->GINTMSK = 0xFFFFFFFF & ~(USB_OTG_GINTMSK_NPTXFEM | USB_OTG_GINTMSK_PTXFEM | USB_OTG_GINTSTS_SOF | USB_OTG_GINTSTS_EOPF);
}