Hallo Mikrocontroller'ler,
da ich nun Wochen mit recherchieren und suchen verbracht habe um mein
Problem zu lösen, frage ich hier mal nach Rat.
Ich möchte bei einer vorhandenen USB-Verbindung zwischen PC und Device
mit dem dazwischen 'durchgeschliffenen' XMega AU einen SOF-Interrupt
nutzen. Die Kommunikation findet statt, es sind SOF-Pakete auf den
USB-Signalleitungen, aber der SOF-Interrupt (innerhalb
ISR(USB_BUSEVENT_vect)) wird nicht ausgelöst und das entsprechende
SOF-Flag (USB_SOFIF in Register USB.INTCTRLB) wird auch nicht gesetzt.
Das ASF (Atmel Software Framework) soll nicht verwendet werden.
Ich benutze einen externen Quarz (16Mhz), der durch die interne PLL
zunächst auf 128MHz hochgesetzt wird (für die interne
schnellst-Peripherie Clk_per4), dann durch zwei Prescaler jeweils
nochmal geteilt wird, sodass 64MHz für die interne schnelle Peripherie
(Clk_per2) bleibt und die 32MHz als Systemtakt. Das scheint zu
funktionieren, eine LED blinkt in der Geschwindigkeit wie eingestellt.
1 | void Clock_Init(void){
|
2 | // SysClock: 16MHz XTAL -> PLL -> 128MHz (ClkPer4) -> 64Mhz (ClkPer2) -> 32Mhz SysClk
|
3 | OSC.XOSCCTRL = OSC_FRQRANGE_12TO16_gc|OSC_XOSCPWR_bm| // Config Xtal: Range 12Mhz to 16MHz, more swing,
|
4 | OSC_XOSCSEL_XTAL_16KCLK_gc; // 0.4MHz to 16MHz ext. Xtal
|
5 | OSC.CTRL = OSC_XOSCEN_bm; // Enable XTal
|
6 | OSC.PLLCTRL = OSC_PLLSRC_XOSC_gc|(8<<OSC_PLLFAC_gp); // Config PLL: PLL-Source = XTal, PLL-Factor = 2 (16Mhz*2=32MHz)
|
7 | while(!((OSC.STATUS & OSC_XOSCRDY_bm))); // Wait until XTal is Ready
|
8 | CCP = CCP_IOREG_gc; // unlock IO-Register for next Instruction ("Configuration Change Protection", see Page 13,XMega AU Manual)
|
9 | CLK.PSCTRL = CLK_PSBCDIV_2_2_gc; // 128MHz (ClkPer4) div 2 -> 64Mhz (ClkPer2) div 2 -> 32Mhz SysClk
|
10 | OSC.CTRL |= OSC_PLLEN_bm; // Enable PLL
|
11 | while(!((OSC.STATUS & OSC_PLLRDY_bm))); // Wait until PLL is Ready
|
12 | CCP = CCP_IOREG_gc; // unlock IO-Register for next Instruction ("Configuration Change Protection", see Page 13,XMega AU Manual)
|
13 | CLK.CTRL = CLK_SCLKSEL_PLL_gc; // Use PLL as System Clock
|
Für das USB-Modul möchte ich den internen 32MHz Ringoszillator
verwenden. Dazu soll dieser mit Hilfe der DFLL über Kalibrier- und
Compare-Werte auf 48MHz gebracht werden und mit dem SOF-Paket als
Referenz stetig nachkalibriert werden.
1 | // USBClock: RC32MHz (@ 48MHz) <- DFLL calibration for 48MHz (default 32MHz) <- DFLL Frq.Ratio for 48MHz(COMP-Reg) <- (DFLL32 Source USB SOF)
|
2 | OSC.CTRL |= OSC_RC32MEN_bm; // Enable 32MHz Ring-Osc
|
3 |
|
4 | NVM.CMD = NVM_CMD_READ_CALIB_ROW_gc;
|
5 | //DFLLRC32M.CALB = pgm_read_byte(PRODSIGNATURES_USBRCOSC); // Config DFLL: DFLL32M calibration for 48MHz (default 32MHz) (exist in Signature Row)
|
6 | DFLLRC32M.CALB = pgm_read_byte(offsetof(NVM_PROD_SIGNATURES_t, USBRCOSC));
|
7 | DFLLRC32M.CALA = pgm_read_byte(offsetof(NVM_PROD_SIGNATURES_t, USBRCOSCA)); ///////////////// not really necessary
|
8 | NVM.CMD = NVM_CMD_NO_OPERATION_gc;
|
9 | DFLLRC32M.COMP2 = 0xB7;DFLLRC32M.COMP1 = 0x1B; // DFLL32M Frq.Ratio for 48MHz(COMP-Reg)
|
10 | OSC.DFLLCTRL = OSC_RC32MCREF_USBSOF_gc; // DFLL32M Source = USB SOF
|
11 | while(!(OSC.STATUS & OSC_RC32MRDY_bm)); // Wait until 32MHz Ring-Osc is Ready
|
12 | DFLLRC32M.CTRL = DFLL_ENABLE_bm; // Enable DFLL32M
|
13 | CLK.USBCTRL = CLK_USBSRC_RC32M_gc; // No Prescaler, Use 32MHz Ring-Osc as USBClock-Source = 32MHz (at 48MHz) Ring-Osc
|
14 | CLK.USBCTRL |= CLK_USBSEN_bm; // enable selected Clock Source for USB Module
|
15 | }
|
Das war bereits schwierig genug, da ich wenig Dokumentation über die
konkrete Nutzung der Signatur-Werte gefunden habe.
Nun habe ich noch das USB-Modul in eine Grundkonfiguration gebracht:
1 | void USB_Init(){
|
2 | NVM.CMD = NVM_CMD_READ_CALIB_ROW_gc;
|
3 | //USB.CAL0 = pgm_read_byte(PRODSIGNATURES_USBCAL0);
|
4 | //USB.CAL1 = pgm_read_byte(PRODSIGNATURES_USBCAL1);
|
5 | USB.CAL0 = pgm_read_byte(offsetof(NVM_PROD_SIGNATURES_t, USBCAL0));
|
6 | USB.CAL1 = pgm_read_byte(offsetof(NVM_PROD_SIGNATURES_t, USBCAL1));
|
7 | NVM.CMD = NVM_CMD_NO_OPERATION_gc;
|
8 |
|
9 | USB.CTRLA = USB_ENABLE_bm | USB_SPEED_bm | USB_STFRNUM_bm | // enable USB Interface, full-speed, enable Store Frame Number
|
10 | USB_MAXEP1_bm; // max. Endpoint is EP1
|
11 | USB.ADDR = USB_ADDRESS;
|
12 |
|
13 | USB.INTCTRLA = USB_SOFIE_bm | USB_INTLVL_HI_gc; // enable Start of Frame (SOF) Interrupt at IntLevel HI
|
14 | USB.INTCTRLB = USB_TRNIE_bm | USB_SETUPIE_bm; // enable IN/OUT Transaction and SETUP Transaction Complete Interrupt
|
15 | USB.EPPTR = (uint16_t) &EPC_Table; // set Endpoint Configuration Table Pointer
|
16 | EPC_Table.IN0.AUXDATA = 0; // must be 0 before each transaction
|
17 | EPC_Table.IN0.DATAPTR = (uint16_t) ep0_in_buf;
|
18 | EPC_Table.IN0.CNT = sizeof(ep0_in_buf);
|
19 | EPC_Table.IN0.CTRL = USB_EP_BUFSIZE_32_gc | // max. Buffer size allowed 256byte
|
20 | USB_EP_TYPE_CONTROL_gc; // Endpoint IN0 Control EP
|
21 | EPC_Table.IN0.STATUS = 0;
|
22 | USB.INTFLAGSACLR = USB.INTFLAGSACLR;//USB_SOFIF_bm;
|
23 | USB.INTFLAGSBCLR = USB.INTFLAGSBCLR;//USB_TRNIF_bm|USB_SETUPIF_bm;
|
24 | }
|
"ep0_in_buf" ist
1 | uint8_t ep0_in_buf[32]; // incoming usb payload data (at endpoint IN0)
|
Dabei ist die Endpoint-Konfiguration folgend strukturiert:
1 | typedef struct{
|
2 | register8_t STATUS;
|
3 | register8_t CTRL;
|
4 | _WORDREGISTER(CNT);
|
5 | _WORDREGISTER(DATAPTR);
|
6 | _WORDREGISTER(AUXDATA);
|
7 | } EP_t;
|
8 |
|
9 | typedef struct{
|
10 | EP_t OUT0;
|
11 | EP_t IN0;
|
12 | EP_t OUT1;
|
13 | EP_t IN1;
|
14 | EP_t OUT2;
|
15 | EP_t IN2;
|
16 | EP_t OUT3;
|
17 | EP_t IN3;
|
18 | } EPS_t;
|
19 |
|
20 | EPS_t EPC_Table; // Create Endpoint Configuration Table in SRAM
|
Die USB-Interrupts sind 'enabled' in USB_Init und im PMIC freigegeben:
1 | void PMIC_Init(void){
|
2 | PMIC.CTRL = PMIC_MEDLVLEN_bm|PMIC_HILVLEN_bm; // enable Med-/High-Lvl Ints
|
3 | sei();
|
4 | }
|
Das Signal auf der Leitung liegt an, aber weder der entsprechende
Interrupt ISR(USB_BUSEVENT_vect) wird aufgerufen, noch wird das
entsprechende Flag gesetzt, welches ich in der Hauptschleife durch
1 | if(USB.INTCTRLB & USB_SOFIF_bm){
|
2 | ..
|
3 | }
|
prüfe. Ich weiß keinen Rat mehr. Sind hier noch Fehler in der
Initialisierung des USB-Taktes, oder muss über die Grundkonfiguration
des USB-Moduls hinaus noch weiteres erfolgen, damit dieses auf die SOF
mit Interrupts reagiert?
Womöglich ist es nur ein kleiner Fehler, eine falsche Reihenfolge bei
den ganzen Clock- und Osc-Einstellungen oder sonst was....
Ich bin wirklich verzweifelt und weiß nicht weiter, ich bin für jede
Hilfe sehr dankbar.
vielen Dank im Voraus.
Marius