Voor mijn afstudeeropdracht heb ik een LPC1766 gekregen. Deze moet aangesloten kunnen worden op de PC via usb (zonder een FTDI chip).
Op deze ARM Cortex M3 zit een interne USB Device controller. Op blz 250 van de Datasheet staat de initialisatie procedure van de USB controller:
Na dit te volgen heb ik de volgende code geschreven:
Ik heb nu dus alleen Endpoints 0 en 1 in gebruik (Command endpoints). Zoals ik begrepen en gelezen heb (USB in a NutShell) begint de host altijd met zenden, de slave (in dit geval mijn microcontroller) dient de vragen van de host te beantwoorden. Nu is mijn vraag, hoe moet ik verder? Hoe ontvang ik het 'setup' pakketje die de host dient te sturen waar ik op kan antwoorden?
Heeft iemand ervaring met interne USB controllers?
Op deze ARM Cortex M3 zit een interne USB Device controller. Op blz 250 van de Datasheet staat de initialisatie procedure van de USB controller:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
| The LPC17xx USB device controller initialization includes the following steps: 1. Enable the device controller by setting the PCUSB bit of PCONP. 2. Configure and enable the PLL and Clock Dividers to provide 48 MHz for usbclk and the desired frequency for cclk. For correct operation of synchronization logic in the device controller, the minimum cclk frequency is 18 MHz. For the procedure for determining the PLL setting and configuration, see Section 4-5.11 "Procedure for determining PLL0 settings". 3. Enable the device controller clocks by setting DEV_CLK_EN and AHB_CLK_EN bits in the USBClkCtrl register. Poll the respective clock bits in the USBClkSt register until they are set. 4. Enable the USB pin functions by writing to the corresponding PINSEL register. 5. Disable the pull-ups and pull-downs on the VBUS pin using the corresponding PINMODE register by putting the pin in the "pin has neither pull-up nor pull-down resistor enabled" mode. See Section 8-4 "Pin mode select register values". 6. Set USBEpIn and USBMaxPSize registers for EP0 and EP1, and wait until the EP_RLZED bit in USBDevIntSt is set so that EP0 and EP1 are realized. 7. Enable endpoint interrupts (Slave mode): - Clear all endpoint interrupts using USBEpIntClr. - Clear any device interrupts using USBDevIntClr. - Enable Slave mode for the desired endpoints by setting the corresponding bits in USBEpIntEn. - Set the priority of each enabled interrupt using USBEpIntPri. - Configure the desired interrupt mode using the SIE Set Mode command. - Enable device interrupts using USBDevIntEn (normally DEV_STAT, EP_SLOW, and possibly EP_FAST). 8. Configure the DMA (DMA mode): - Disable DMA operation for all endpoints using USBEpDMADis. - Clear any pending DMA requests using USBDMARClr. - Clear all DMA interrupts using USBEoTIntClr, USBNDDRIntClr, and USBSysErrIntClr. - Prepare the UDCA in system memory. - Write the desired address for the UDCA to USBUDCAH (for example 0x7FD0 0000). - Enable the desired endpoints for DMA operation using USBEpDMAEn. - Set EOT, DDR, and ERR bits in USBDMAIntEn. 9. Install USB interrupt handler in the NVIC by writing its address to the appropriate vector table location and enabling the USB interrupt in the NVIC. 10. Set default USB address to 0x0 and DEV_EN to 1 using the SIE Set Address command. A bus reset will also cause this to happen. 11. Set CON bit to 1 to make CONNECT active using the SIE Set Device Status command. The configuration of the endpoints varies depending on the software application. By default, all the endpoints are disabled except control endpoints EP0 and EP1. Additional endpoints are enabled and configured by software after a SET_CONFIGURATION or SET_INTERFACE device request is received from the host. |
Na dit te volgen heb ik de volgende code geschreven:
C:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
| void usb_init() { int EP[nrEP] = {0,1}; LPC_SC->PCONP |= (1<<31); //Power-up USB interface pll1_init(); //Set PLL1 for USBCLK LPC_USB->USBClkCtrl |= (1<<4)|(1<<1); //Enable clock for USB LPC_PINCON->PINSEL1 |= (1<<28)|(1<<26); //SET USB+, USB- LPC_PINCON->PINSEL3 |= (2<<28)|(1<<4); //SET VBUS & USB_UP_LED LPC_PINCON->PINSEL4 |= (1<<18); //SET USB_CONNECT LPC_PINCON->PINMODE3 |= (2<<28); //VBUS has neither pull-up nor pull-down resistor enabled LPC_NVIC->ISER0 |= (1<<24); LPC_NVIC->ISER1 |= (1<<1); int i; for(i=0; i<nrEP-1; i++) //For all endpoints { LPC_USB->USBReEp |= (1<<EP[i]); //Realize endpoint LPC_USB->USBEpInd |= EP[i]; //Select endpoint LPC_USB->USBMaxPSize = 64; //Set maximum packet size of selected endpoint } while(!(LPC_USB->USBDevIntSt & (1<<8))); //wait until the EP_RLZED bit in USBDevIntSt is set so that EP0 and EP1 are realized LPC_USB->USBDevIntClr = (1<<8); //Clear EP_RLZED LPC_USB->USBEpIntClr = 0xFFFFFFFF; //Clear all endpoint interrupts LPC_USB->USBDevIntClr = 0x3FF; //Clear any device interrupts LPC_USB->USBEpIntEn = 0b11; //Enable EP interrupts 0,1 LPC_USB->USBEpIntPri = 0b11; //Set EP0,1 to HIGH priority /****************SET MODE COMMAND****************/ LPC_USB->USBDevIntClr = (1<<4)|(1<<5); //Clear CCEMPTY, CDFULL interrupt LPC_USB->USBCmdCode = (CMD_COMMAND<<CMD_PHASE)|(SET_MODE<<CMD_WDATA); //Set Mode command while(!(LPC_USB->USBDevIntSt & (1<<4))); //While CCEMPTY is set LPC_USB->USBDevIntClr = (1<<4); //Clear CCEMPTY interrupt LPC_USB->USBCmdCode = (CMD_WRITE<<CMD_PHASE)|(1<<CMD_WDATA); while(!(LPC_USB->USBDevIntSt & (1<<4))); //While CCEMPTY is set LPC_USB->USBDevIntClr = (1<<4); //Clear CCEMPTY interrupt /************************************************/ LPC_USB->USBDevIntEn = 0b1110; //Enable device interrupts using USBDevIntEn (normally DEV_STAT, EP_SLOW, and possibly EP_FAST) /**************SET ADDRESS COMMAND***************/ LPC_USB->USBDevIntClr = (1<<4)|(1<<5); //Clear CCEMPTY, CDFULL interrupt LPC_USB->USBCmdCode = (CMD_COMMAND<<CMD_PHASE)|(SET_ADDRESS<<CMD_WDATA); //Set Mode command while(!(LPC_USB->USBDevIntSt & (1<<4))); //While CCEMPTY is set LPC_USB->USBDevIntClr = (1<<4); //Clear CCEMPTY interrupt LPC_USB->USBCmdCode = (CMD_WRITE<<CMD_PHASE)|(0b10000000<<CMD_WDATA); while(!(LPC_USB->USBDevIntSt & (1<<4))); //While CCEMPTY is set LPC_USB->USBDevIntClr = (1<<4); //Clear CCEMPTY interrupt /************************************************/ /***************SET DEVICE COMMAND***************/ LPC_USB->USBDevIntClr = (1<<4)|(1<<5); //Clear CCEMPTY, CDFULL interrupt LPC_USB->USBCmdCode = (CMD_COMMAND<<CMD_PHASE)|(SET_DEV_STATUS<<CMD_WDATA); //Set Mode command while(!(LPC_USB->USBDevIntSt & (1<<4))); //While CCEMPTY is set LPC_USB->USBDevIntClr = (1<<4); //Clear CCEMPTY interrupt LPC_USB->USBCmdCode = (CMD_WRITE<<CMD_PHASE)|(1<<CMD_WDATA); while(!(LPC_USB->USBDevIntSt & (1<<4))); //While CCEMPTY is set LPC_USB->USBDevIntClr = (1<<4); //Clear CCEMPTY interrupt /************************************************/ } |
Ik heb nu dus alleen Endpoints 0 en 1 in gebruik (Command endpoints). Zoals ik begrepen en gelezen heb (USB in a NutShell) begint de host altijd met zenden, de slave (in dit geval mijn microcontroller) dient de vragen van de host te beantwoorden. Nu is mijn vraag, hoe moet ik verder? Hoe ontvang ik het 'setup' pakketje die de host dient te sturen waar ik op kan antwoorden?
Heeft iemand ervaring met interne USB controllers?
[ Voor 26% gewijzigd door Verwijderd op 16-03-2010 16:53 ]