Sari la conținut
ELFORUM - Forumul electronistilor

Cortex M4 - întreruperi


Postări Recomandate

Am de scris un cod pentru un nenorocit de Treerunner (Freescale, pentacore, poate să facă d-astea). Din fericire, codul pe care-l scriu e doar pentru nucleul Cortex M4, iar aici intervin problemele.

 

N-am mai lucrat niciodată cu băşitul ăsta de procesor, cu atît mai puţin cu NVIC, şi se pare că sînt incapabil să fac întreruperile să funcţioneze. Vectorii de întrerupere sînt declaraţi în fişierul de startup, arătînd ceva de genul:

.globl __isr_vector.section .isr_vector.align 2   // 2^2 = 4 byte = 32 bit__isr_vector:  .long _StackTop_          // 00 Initial Stack Pointer  .long Reset_Handler       // 01 Initial Program Counter  .long NMI_Handler         // 02 Non-Maskable Interrupt  .long HardFault_Handler   // 03 Hard Fault  .long ReservedHandler     // 04 reserved  .long BusFault_Handler    // 05 Bus Fault  .long UsageFault_Handler  // 06 Usage Fault  .long ReservedHandler     // 07 reserved  .long ReservedHandler     // 08 reserved  .long ReservedHandler     // 09 reserved  .long ReservedHandler     // 10 reserved  .long SVC_Handler         // 11 Service Call  .long DebugMon_Handler    // 12 Debug Monitor  .long ReservedHandler     // 13 reserved  .long PendSV_Handler      // 14 Pendable Service Request  .long SysTick_Handler     // 15 SysTick  // Interrupt vectors  .long ISR_CPU_INT0                         // ISR 0  .long ISR_CPU_INT1                         // ISR 1  .long ISR_CPU_INT2                         // ISR 2

Primii 16 vectori sînt declaraţi în fişierul de startup, fiind practic bucle infinite:

Reset_Handler:  b Reset_Handler

Rutinele de tratat întreruperile sînt într-un fişier C şi arată ceva de genul:

#pragma INTERRUPT (ISR_CPU_INT0, 0)void ISR_CPU_INT0(void){while(1);}  // ISR 0

Deşi sînt declarate rutine pentru absolut toţi vectorii posibili (176 la număr), niciuna nu merge. Toate întreruperile sînt activate, iar atunci cînd încerc să forţez o întrerupere SW, căcatul ăsta de Cortex forţează un SW reset, care nu are nicio legătură cu ce am eu definit prin cod. SW reset se face cu alt registru şi watchdogu' nu e activ.

 

Jegoşii de la Freescale nu se obosesc să răspundă la mailuri, iar eu încep să-mi pierd răbdarea şi s-ar putea ca placa de evaluare să trateze cît de curînd o întrerupere cauzată de topor.

 

Întrebările mele: a mai lucrat cineva cu NVIC-ul din M4 şi poate să-mi explice cum dracu' se face legătura dintre vectorul de întrerupere şi rutina de tratare? Accept şi linkuri, bucăţi de cod care funcţionează etc.

 

PS: Am epuizat google, deja îmi cere cod de verificare ca să declar că nu sînt bot.

Link spre comentariu

Flag-urile respective ale intreruperilot sunt setate pe undeva (in registrii corespunzatori)?

Daca sunt setate si nu se executa codul specific intreruperii, atunci nu sunt active intreruperile.

Eu m-am mai jucat cu Cortex M0+ de la Freescale dar foloseam CodeWarrior ce genera tot codul specific pe baza unor configurari in "Processor Expert". Te scapa de multe batai de cap dar mai dadea si rateuri...

 

In mare e cam asa (fara ordinea asta in mod necesar):

- activezi intreruperile globale

- activezi intreruperea care te intereseaza

- configurezi perifericul sa genereze intreruperea

- iti inregistrezi handlerul la adresa specifica in vectorul de intreruperi

Editat de godFather89
Link spre comentariu

Am setat şi flagurile din regiştii respectivi (UART-ul a fost cel mai la îndemînă), fără rezultat. Astea nu fac absolut nimic. Ce ai pus tu în listă am făcut deja, iar compilatorul e arm-none-eabi.

 

Toate întreruperile sînt activate aici:

  // 176 interrupts, no system reset request  CM4_0.AIRCR.R = 0x05FA0000 | (176 << 11);  CM4_0.NVIC_ISER[0].B.SETENA = 0xFFFFFFFF; // all crap enabled  CM4_0.NVIC_ISER[1].B.SETENA = 0xFFFFFFFF; // all crap enabled  CM4_0.NVIC_ISER[2].B.SETENA = 0xFFFFFFFF; // all crap enabled  CM4_0.NVIC_ISER[3].B.SETENA = 0xFFFFFFFF; // all crap enabled  CM4_0.NVIC_ISER[4].B.SETENA = 0xFFFFFFFF; // all crap enabled  CM4_0.NVIC_ISER[5].B.SETENA = 0xFFFFFFFF; // all crap enabled  CM4_0.NVIC_ISER[6].B.SETENA = 0xFFFFFFFF; // all crap enabled  CM4_0.NVIC_ISER[7].B.SETENA = 0xFFFFFFFF; // all crap enabled  CM4_0.ICTR.B.INTLINESNUM = 0x5; // 0b0101 = 161...192 interrupt lines

Ca să generez întreruperea din soft, adică să forţez una, folosesc codul de jos:

  // Set pending state for interrupt  CM4_0.NVIC_ISPR[0].B.SETPEND = 1; // ISR0 = bit0  // Enable access to STIR register  CM4_0.CCR.B.USERSETMPEND = 1;  // Trigger SWI (privileged register)  CM4_0.STIR.B.INTID = 0; // IRQ vector number
Link spre comentariu

Primii 16 vectori sînt declaraţi în fişierul de startup, fiind practic bucle infinite:

Reset_Handler:  b Reset_Handler

 

Asta nu suna prea corect. Prima intrerupere (Reset handler), ignorand StackTop, e ce se executa imediat dupa reset. Aici ar trebui sa fie adresa main-ului tau (sau unde incepe initializarea).Si daca activezi intreruperea pentru un IO (rising edge, sau ceva), se seteaza flag-ul corespunzator cand se modifica starea? Editat de godFather89
Link spre comentariu

Nașule, handlerele alea sînt puse la oha, dacă ajunge vreodată în ele mă aleg cu watchdog reset. Ăla e scopul buclei infinite și toate handlerele sînt la fel, inclusiv pentru întreruperi. Da' crezi că ajunge în ele? Nu, scîrba sare direct în bootloaderul din ROM, abia după ăla ajunge în stack top și execută main. Deocamdată nu mă interesează zona aia. La pini nu am acces, deși cică folosesc o placă de dezvoltare.Liviu, eram extrem de mulțumit dacă îmi dădeau și un hello_world.c cu care să mă duc mai departe cu implementarea. Nici vorbă de librării, am doar headerul cu definițiile regiștrilor, un manual incomplet și fără vreo garanție că e corect, plus un car de draci cu care să-mi fac treaba. Practic programez pînă la nivel de bit.Pînă în momentul de față am implementat un UART prin polling, dar vreau neapărat întreruperi. În funcție de parametrii primiți, vita se uită printr-o matrice de funcții și activează watchdogu', abuzează regiștrii și RAM-ul intern etc după care trimite înapoi cîtă mentă a frecat.Edit: mi-ai dat o idee bună cu pluginul ăla. Mîine caut să văd ce e de el. E nasol rău cînd nu mai știu ce să caut.

Link spre comentariu

Partea proastă e că-mi trebuie pentru serviciu, deci o să fie cam complicat cu instalările. În clipa de faţă folosesc un editor de text, compilatorul (comenzi date din command line) şi un debugger (Trace32). Fiindcă azi m-am trezit vesel, le-am mai trimis un mail ălora de la Freescale, escalînd problema cu vreo trei nivele de management mai sus. Poate aşa răspund.

Link spre comentariu

Una din probleme e rezolvată. Fiindcă mizeria aia de cip are cinci nuclee, idiotului trebuia să-i mai scriu într-un registru către care nucleu direcţionez întreruperea. Cînd activez o întrerupere acum mi se opreşte debuggerul şi la motiv am vector catch, deci sînt pe drumul cel bun. Partea proastă e că vectorii sînt definiţi în flash iar codul meu tre' să se execute din RAM, aşa că o să fie nevoie să copiez jegurile alea de vectori. Cel puţin acum am un punct de plecare.

Link spre comentariu

L-am rezolvat, fir-ar mă-sa a dracu'. Care era problema: placa de dezvoltare butează de pe un SD card. Eu am crezut că lansează codul direct de acolo, dar nu e aşa. Bootloaderul ia codul de pe SD şi îl încarcă în RAM, dar vectorii mei rămîn în ROM, neatinşi. Bineînţeles că la rulare caută nişte adrese care nu există. Soluţia? Remaparea vectorilor în RAM.

extern unsigned long M4_0_VECTOR_TABLE; // defined in linker file#define HW_REG(addr)     (*((volatile unsigned long *)(addr)))#define NEW_VECT_TABLE   (unsigned long)&M4_0_VECTOR_TABLEvoid init_interrupts(void){  unsigned char i, irq_vect;  // Initial vector table at code start  CM4_0.VTOR.R = 0x00000000;  // ---------- JUST FOR TEST! ------------  CM4_0.NVIC_ISER[0].B.SETENA = 0xFFFFFFFF; // all crap enabled  CM4_0.NVIC_ISER[1].B.SETENA = 0xFFFFFFFF; // all crap enabled  CM4_0.NVIC_ISER[2].B.SETENA = 0xFFFFFFFF; // all crap enabled  CM4_0.NVIC_ISER[3].B.SETENA = 0xFFFFFFFF; // all crap enabled  CM4_0.NVIC_ISER[4].B.SETENA = 0xFFFFFFFF; // all crap enabled  CM4_0.NVIC_ISER[5].B.SETENA = 0xFFFFFFFF; // all crap enabled  CM4_0.NVIC_ISER[6].B.SETENA = 0xFFFFFFFF; // all crap enabled  CM4_0.NVIC_ISER[7].B.SETENA = 0xFFFFFFFF; // all crap enabled  CM4_0.ICTR.B.INTLINESNUM = 0x5; // 0b0101 = 161...192 interrupt lines  // Copy exception vectors to RAM  HW_REG(NEW_VECT_TABLE + 0x0) = HW_REG(0x0);  HW_REG(NEW_VECT_TABLE + 0x4) = HW_REG(0x4);  HW_REG(NEW_VECT_TABLE + 0x8) = HW_REG(0x8);  HW_REG(NEW_VECT_TABLE + 0xC) = HW_REG(0xC);  irq_vect = 16;  // First ISR starts at offset 16  // Copy vector handlers to RAM  HW_REG(NEW_VECT_TABLE + 4*irq_vect++) = (unsigned)ISR_CPU_INT0;  // ISR 0  HW_REG(NEW_VECT_TABLE + 4*irq_vect++) = (unsigned)ISR_CPU_INT1;  // ISR 1  HW_REG(NEW_VECT_TABLE + 4*irq_vect++) = (unsigned)ISR_CPU_INT2;  // ISR 2  HW_REG(NEW_VECT_TABLE + 4*irq_vect++) = (unsigned)ISR_CPU_INT3;  // ISR 3  // ....  // Set vector table offset at the new RAM address  CM4_0.VTOR.R = NEW_VECT_TABLE;} // end function init_interrupts()
Link spre comentariu

Creează un cont sau autentifică-te pentru a adăuga comentariu

Trebuie să fi un membru pentru a putea lăsa un comentariu.

Creează un cont

Înregistrează-te pentru un nou cont în comunitatea nostră. Este simplu!

Înregistrează un nou cont

Autentificare

Ai deja un cont? Autentifică-te aici.

Autentifică-te acum
×
×
  • Creează nouă...

Informații Importante

Am plasat cookie-uri pe dispozitivul tău pentru a îmbunătății navigarea pe acest site. Poți modifica setările cookie, altfel considerăm că ești de acord să continui.Termeni de Utilizare si Ghidări