Forum: Mikrocontroller und Digitale Elektronik kein SOF-Interrupt im USB-Moduls beim XMega AU (kein ASF)


von Marius S. (phobius)


Lesenswert?

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

von Gerhard G. (g_g)


Lesenswert?

Hallo,

hier findest du eine laufähige USB-CDC Anwendung:

Beitrag "CDC für xmega"

Schau dir mal die USB-Init an. Der Takt wie beschrieben, funktioniert 
mit einem 16Mhz Quarz astrein.

Habe die Schaltung/Programm auf einem Atxmega128a3U selbst getestet.


Gruß G.G.

von Marius S. (phobius)


Lesenswert?

Hallo Herr Gehlert,

der Hinweis war sehr wertvoll für mich. Der Code dieses Beitrags ist 
genau das, was ich gesucht habe. Gefunden hatte ich sonst nur stark 
abstrahierten Code, z.B. in Frameworks (ASF) oder sonstigen stark 
'verschleiernden', ins unendlich reichende Verschachtelungen.
Manchmal auch einfach 'magische Zahlen' die hin- und her übergeben 
wurden, um eine einfache Sache zu erledigen.

Vielen Dank schonmal.
Gruß
Marius

von Marius S. (phobius)


Lesenswert?

Scheinbar ist es für den USB-Controller notwendig, dass auch der PullUp 
mit USB.CTRLB |= USB_ATTACH_bm; gesetzt wird.
Obwohl dieser extern gesetzt wird, möchte das USB-Modul dieses Bit 
gesetzt haben.
Nun da es gesetzt ist, funktioniert es....


Der Thread kann gelöscht werden.

: Bearbeitet durch User
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.