Jump to content


Photo

Cortex M4 - întreruperi


  • Please log in to reply
12 replies to this topic

#1 OFFLINE   ratza

ratza

    Lepră

  • Membri
  • PipPipPipPipPip
  • 4,962 posts
  • Locatie:Vîlcean în Sibiu

Posted 03 December 2015 - 03:39 PM

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.



Cu_reclama

Cu_reclama
  • Membri

#2 OFFLINE   godFather89

godFather89

    Membru

  • Membri
  • PipPip
  • 816 posts
  • Locatie:Timisoara

Posted 03 December 2015 - 04:16 PM

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


Edited by godFather89, 03 December 2015 - 04:22 PM.


#3 OFFLINE   ratza

ratza

    Lepră

  • Membri
  • PipPipPipPipPip
  • 4,962 posts
  • Locatie:Vîlcean în Sibiu

Posted 03 December 2015 - 04:44 PM

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


#4 OFFLINE   godFather89

godFather89

    Membru

  • Membri
  • PipPip
  • 816 posts
  • Locatie:Timisoara

Posted 03 December 2015 - 05:06 PM

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?

Edited by godFather89, 03 December 2015 - 05:08 PM.


#5 OFFLINE   Liviu M

Liviu M

    -

  • Membri
  • PipPipPipPipPip
  • 3,072 posts
  • Locatie:In sat cu Doru

Posted 03 December 2015 - 05:21 PM

Salut,

in ce programezi? N-au si ei un mediu mai prietenos, cu biblioteci mai "umane"?
Am vazut acum ca pluginul eclipse pentru ARM suporta si niste kinex. Ai incercat sa vezi poate e mai prietenos?

Uite, ca idee, cum se folosesc intreruperile pentru STM32, pe baza bibliotecilor oferite de ST.

 

Spor,

Liviu



#6 OFFLINE   Liviu M

Liviu M

    -

  • Membri
  • PipPipPipPipPip
  • 3,072 posts
  • Locatie:In sat cu Doru

Posted 03 December 2015 - 08:40 PM

Salut,

tocmai am generat cu pluginul susamintit un proiect in eclipse un (dummy) pentru Kinetix KLxx.

Pluginul pare sa vina cu si sa includa si unele biblioteci pentru programat Kineticul. Poate chiar merita sa-i acorzi o sansa (pluginul, adica).

 

Spor,

Liviu

Attached Files



#7 OFFLINE   ratza

ratza

    Lepră

  • Membri
  • PipPipPipPipPip
  • 4,962 posts
  • Locatie:Vîlcean în Sibiu

Posted 03 December 2015 - 08:50 PM

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.

#8 OFFLINE   Liviu M

Liviu M

    -

  • Membri
  • PipPipPipPipPip
  • 3,072 posts
  • Locatie:In sat cu Doru

Posted 03 December 2015 - 09:12 PM

In cel mai rau caz, daca nu merge si nu merge, incearca sa-l contactezi pe autorul pluginului. Daca-l iei cu frumosul, asa, ca de la roman la roman,  :rade:  poate te ajuta, ca am senzatia ca stie.


Edited by Liviu M, 03 December 2015 - 09:12 PM.


#9 OFFLINE   Liviu M

Liviu M

    -

  • Membri
  • PipPipPipPipPip
  • 3,072 posts
  • Locatie:In sat cu Doru

Posted 03 December 2015 - 11:08 PM

Tocmai am descoperit ca cei de la Atollic ofera versiunea lite gratis *) si fara limitari. Tot atollic are printre parteneri si pe freescale.

Poate astia odera suport mai bun?

 

*) Gratis in sensul ca dai click pe link si se descarca. Nu trebuie nici macar inregistrare, nimic.


Edited by Liviu M, 03 December 2015 - 11:09 PM.


#10 OFFLINE   godFather89

godFather89

    Membru

  • Membri
  • PipPip
  • 816 posts
  • Locatie:Timisoara

Posted 04 December 2015 - 09:12 AM

Uita-te si peste CodeWarrior care are plugin-ul Processor Expert. E tot Eclipse, tot gratis, dar e facut de Freescale.



#11 OFFLINE   ratza

ratza

    Lepră

  • Membri
  • PipPipPipPipPip
  • 4,962 posts
  • Locatie:Vîlcean în Sibiu

Posted 04 December 2015 - 10:00 AM

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.



#12 OFFLINE   ratza

ratza

    Lepră

  • Membri
  • PipPipPipPipPip
  • 4,962 posts
  • Locatie:Vîlcean în Sibiu

Posted 11 December 2015 - 02:29 PM

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.



Cu_reclama

Cu_reclama
  • Membri

#13 OFFLINE   ratza

ratza

    Lepră

  • Membri
  • PipPipPipPipPip
  • 4,962 posts
  • Locatie:Vîlcean în Sibiu

Posted 14 December 2015 - 01:07 PM

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_TABLE
void 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()





0 user(s) are reading this topic

0 members, 0 guests, 0 anonymous users