Forum: Mikrocontroller und Digitale Elektronik ARM7 + Crossworks: Interrupt Beispiel gesucht


von Christian J. (elektroniker1968)


Lesenswert?

Hallo,

hat jemand einen funktionierenden Code für den ARM7, idealerweise mit 
Crossworks geschrieben, damit die Header einheitlich sind, der zB eine 
LED über die Timer zum blinken bringt? Aus mir unerfindlichen Gründen 
laufen meine IRQ nicht, sie werden einfach nicht "gezündet", dabei 
verwende ich fertige Beispiele, die eigentlich klipp und klar sein 
sollten. Nun ja, so ganz blicke ich durch die vielen Vektoren noch nicht 
durch aber wenigstens sollte es erstmal blinken.



Gruss,
Christian

von Stefan B. (stefan) Benutzerseite


Lesenswert?

"Den ARM7" gibt es nicht.

Jedenfalls aus Sicht der verschiedenen Komponenten der Übersetzungstools 
und Laufzeitbibliotheken. Die sind immer auf ein spezielles µC-Modell 
(mit ARM7 Kern und Herstellerspezifischer Periferie auf dem µC) 
abgestimmt.

Welchen µC hast du konkret?

von Christian J. (elektroniker1968)


Lesenswert?

Den ARM7TDMI Core in der Variante LPC2138 von NXP.

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Die zusätzlichen Beispiele auf 
http://www.rowleydownload.co.uk/arm/packages/ hast du schon gesichtet? 
Ich sehe zwar im Moment keins speziell zum Timer-Interrupt, aber die 
Beschreibungen der Pakete sind auch nicht sehr ausführlich.

von Christian J. (elektroniker1968)


Lesenswert?

Hallo,

ja, die habe ich schon, wenngleich es mein Board dort nicht gibt. Das 
Beispiel zum RTC IRQ ist dermassen kompliziert, dass ich da nur Bahnhof 
verstehe, weil die mit Funktionen in der Parameterliste arbeiten und 
kiloweise Zeigern, die alles noch unübersichtlicher machen, wenn man 
nicht der war, der das Programm erstellt hat. Passt ausserdem wohl nur 
für die Keil Oberfläche, Crossworks hat andere Spezialwörter um zB eine 
Funktion als IRQ zu definieren.
1
//interrupts.c
2
#include "interrupts.h"
3
4
/**** INTERRUPTS FUNCTION ****/
5
void (*UART0_function)(unsigned char);
6
void (*UART1_function)(unsigned char);
7
void (*EINT0_function)();
8
void (*EINT1_function)();
9
void (*EINT2_function)();
10
void (*RTC_function)();
11
12
void VIC_EnableInt(unsigned int IntType)
13
{
14
  VICIntEnable |= IntType;            //Enable inerrupt
15
}
16
17
void VIC_DisableInt(unsigned int IntType)
18
{
19
  VICIntEnClear |= IntType;           //Disable interrupt
20
}
21
22
void Vic_Init()
23
{
24
  VICProtection = 0;                  // Setup interrupt controller.
25
  VICIntEnClear = 0xffffffff;         // Disable all interrupts
26
}
27
28
void InitUART0Interrupt(void(*UART0_func)(unsigned char))
29
{
30
31
  UART0_function = UART0_func;        // Setup UART0 callback function.
32
  VICIntSelect &= ~VIC_UART0_bit;     // IRQ on UART0 line.
33
  VICVectAddr0 = (unsigned int)&UART0Interrupt;
34
  VICVectCntl0 = 0x20 | VIC_UART0;    // Enable vector interrupt for UART0.
35
  VICIntEnable |= VIC_UART0_bit;      // Enable UART0 interrupt.
36
37
}
38
39
/**** INTERRUPTS HANDLERS ****/
40
// IRQ interrupt handler.
41
//__irq __arm void irq_handler(void)
42
#pragma vector=0x18
43
__irq __arm void IRQ_ISR_Handler (void)
44
{
45
  void (*interrupt_function)();
46
  unsigned int vector;
47
48
  // Called at 1000 Hz rate.
49
  vector = VICVectAddr; // Get interrupt vector.
50
  interrupt_function = (void(*)())vector;
51
  (*interrupt_function)(); // Call vectored interrupt function.
52
53
  VICVectAddr = 0; // Clear interrupt in VIC.
54
}

von Nils B. (nordlicht_nils)


Lesenswert?

Hallo Christian,

der folgende Code ist in Crossworks erstellt und benutzt die Crossworks 
tasking library (ctl_api.h). Er ist für den AT91SAM7S64, aber die 
Benutzung der ctl_api sollte daraus klar werden.

Eigentlich benötigst Du nur folgende Funktionen:
1
ctl_set_isr(PIOA_ID, 0, CTL_ISR_TRIGGER_POSITIVE_EDGE, isr, 0);
2
ctl_unmask_isr(PIOA_ID);
3
ctl_global_interrupts_enable();

isr ist der Interrupt-Handler
PIOA_ID ist die ID der Interruptquelle

Eine relativ gute Beschreibung der library findest Du auch unter:
http://www.rowley.co.uk/documentation/arm_1_7/index.htm

Hier ein Programmausschnitt. Bei Tastendruck wird ein Interrupt 
ausgelöst, ein Flag wird gesetzt und in main() wird darauf mit 
LED-Leuchten reagiert.
1
#include <ctl_api.h>
2
#include <targets/AT91SAM7.h>
3
4
//bits
5
#define   BIT17       0x00020000
6
#define   BIT18       0x00040000
7
#define   BIT19       0x00080000
8
#define   BIT20       0x00100000
9
#define   LED_OFFSET  (17)
10
11
static volatile int flag_PIO_changed;
12
static volatile int status_PDSR_interrupt;
13
14
static void buttonPressed(void) {  
15
  //Clear Interrupt flag
16
  unsigned long isr = PIOA_ISR;
17
  
18
  //Get PDSR Status and Set Flag for main
19
  status_PDSR_interrupt = PIOA_PDSR;
20
  flag_PIO_changed = 1;   
21
}
22
23
int main(void) {
24
  unsigned int v = 0;
25
26
  ctl_board_init();
27
  ctl_board_on_button_pressed(buttonPressed);
28
  ctl_global_interrupts_enable();
29
30
  while(1)
31
32
    if(flag_PIO_changed) {
33
34
      if(!(status_PDSR_interrupt & BIT19))
35
        ctl_board_set_leds(0x2);
36
      if(!(status_PDSR_interrupt & BIT20))
37
        ctl_board_set_leds(0x1);
38
         
39
      flag_PIO_changed = 0;
40
    }
41
42
    v++;
43
    // do something
44
  
45
  return 0;
46
}
47
48
void ctl_board_on_button_pressed(CTL_ISR_FN_t isr){
49
  // Setup PIO
50
  PIOA_ODR = BUTTONS;
51
  PIOA_PER = BUTTONS;
52
  PIOA_MDDR = ~BUTTONS;
53
  PIOA_MDER = BUTTONS;
54
  PIOA_IER = BUTTONS;
55
  ctl_set_isr(PIOA_ID, 0, CTL_ISR_TRIGGER_POSITIVE_EDGE, isr, 0);
56
  ctl_unmask_isr(PIOA_ID);
57
}

Ist nicht vollständig, aber die wesentlichen Teile sind dabei. Hoffe, 
dass es Dir hilft.

Gruß Nils

von Stefan B. (stefan) Benutzerseite


Lesenswert?

@  Christian

Ah, es geht um den VIC (vector interrupt controller) und vectored 
interrupts (##).

Disclaimer: Ich bin Laie und spekuliere nur

U.a. dass man einen Zeiger auf deine Interruptfunktion (im Beispiel 
UART0_func) an eine Funktion (im Beispiel InitUART0Interrupt) übergibt 
und diese Funktion dann den global speichert (im Beispiel in 
UART0_function) und in den ersten Interruptvektor-Slot (im Beispiel 
VICVectAddr0) einträgt sowie den Kanal setzt für den dieser Vektor 
gelten soll (siehe #)

Und dann es einen globalen Interrupthandler (im Beispiel 
IRQ_ISR_Handler) gibt, der sich den aufgetretenen Interruptvektor (im 
Beispiel VICVectAddr) schnappt und ausführt.

Leider sieht man im Codeschnippsel mehrere Sachen nicht

* Wie wird deine Interruptfunktion definiert? Ich schätze dafür sind 
spezielle Schlüsselworte in der Definition nötig. Crossworks ist doch 
auf GCC Basis - da helfen vielleicht die Definitionen aus #

* Läuft das VIC immer oder müssen andere Sachen beachtet werden. Dazu 
habe ich 
http://ccgi.rowley.co.uk/support/faq.php?do=article&articleid=25 
gefunden. Das sieht für mich so aus, dass die VIC Unterstützung nicht 
defaultmässig mitkompiliert wird sondern dass speziell übersetzt werden 
muss. In # steht ähnliches mit speziellem Startupcode.

# 
http://www.mikrocontroller.net/articles/ARM-elf-GCC-Tutorial#Interrupts 
sowie die Beispiele bei WinARM ### und/oder GnuARM

## 
http://winarm.scienceprog.com/arm-mcu-types/interrupt-system-of-arm-lpc2000-microcontrollers.html

### Beispiel RTV für WinARM
http://winarm.scienceprog.com/winarm-gcc-tutorial/real-time-clock-of-lpc2148.html

von Christian J. (elektroniker1968)


Lesenswert?

Hallo,

danke, erstmal Eure Antworten ausgedruckt, bevor sie "weggetaucht" sind. 
Toll, dass sich Leute hier soviel Arbeit mit der Hilfe machen !!!! 
Grosses Dankeschön!

PS: Die nächste Frage kommt bestimmt.... warum bei Crossworks ein Brand 
mit "Flash release" das Programm nicht startet. Der mit "Flash debug" 
klappt nämlich, mit eingestecktem JTAG aber auch abgezogenen. Nur sind 
da eben die Debug Infos noch mit im Code.

Gute Nacht erstmal !

Christian

von Christian J. (elektroniker1968)


Lesenswert?

Hallo,

ich denke folgende Struktur würde für alle Fälle reichen, die bei mir 
vorkommen:

1. - IRQ Routine Timer 1
   - IRQ Routine UART
   - IRQ Routine SPI
   ......

2. Initialisierung der IRQ Routinen, Zuordnung der Hardware zum 
jeweiligen Handler.

3. IRQ freigeben und glücklich sein.

Bevor ich da tiefer reintauche muss ich jedoch erst mehr über diesen VIC 
lesen, wie der funktioniert. Beim PIC war das so schön einfach, nur ein 
IRQ Vektor, Bits abfragen und je nach Bit in die passende Routine 
verzweigen. Die Zeiten sind wohl vorbei.

Im ersten Ansatz wäre schon eine blinkende LED schön, die bei jedem 
Timer Match aufblinkt.

Gruss,
Christian

von Christian J. (elektroniker1968)


Lesenswert?

So... nun tuts das auch, nech? :-)

Das Zauberwörtchen VECTORED_IRQ_INTERRUPTS bei Preprozessor bewirkte 
das.
1
void __attribute__ ((interrupt("IRQ"))) timer0ISR(void);
2
3
void InitIRQ()
4
{
5
    #define TIMER0_IRQ    4
6
7
     // Timer 0 ist ein IRQ interrupt
8
    //VICIntSelect &= ~0x10;
9
    VICIntSelect&= ~(1<<TIMER0_IRQ);
10
    // Benutze slot 0 für timer 0 interrupt
11
    VICVectCntl0=(1<<5) | TIMER0_IRQ;
12
    // Enable timer 0 interrupt
13
    VICIntEnable = (1<<TIMER0_IRQ);
14
    // Setze die Adresse der ISR für slot 0
15
    VICVectAddr0 = (unsigned int)timer0ISR;
16
17
    // Reset timer 0
18
    T0TCR = 0;
19
    // Setze den Timer 0 prescale counter
20
    T0PR = 1000;
21
    /* Setze das Timer 0 match register */
22
    T0MR0 = 2000;
23
    // Match = IRQ auslösen und Timer resetten
24
    T0MCR |= T0MCR_Interrupt_on_MR0_MASK | T0MCR_Reset_on_MR0_MASK;
25
    /* Start timer 0 */
26
    T0TCR = T0TCR_Counter_Enable_MASK;
27
28
    /* Enable Interrupts */
29
    __ARMLIB_enableIRQ();
30
}
31
32
33
void __attribute__ ((interrupt("IRQ"))) timer0ISR(void){
34
  int counter;
35
  /*
36
  if (++counter %2 ==0)
37
    LEDOn();
38
  else
39
    LEDOff();
40
*/
41
   // IR Flag des M0 Match Registers löschen (=setzen)
42
   T0IR |= T0IR_MR0_MASK;
43
 
44
  VICVectAddr = 0;       // Acknowledge Interrupt
45
}

von Christian J. (elektroniker1968)


Lesenswert?

Nachwort:

Was bisher nicht funktioniert ist immer noch der "Flash release" bei 
Crossworks 1.7. (Anm: Die Release Version enthält keine Debug Infos mehr 
und ist wesentlich kleiner im Code) Ich habe da wirklich alles 
ausprobiert, der uC startet nicht von allein. Der besagte Schalter 
STARTUP_FROM_RESET für den Startup code wird im LPC210x.s gar nicht 
abgefragt, ist also nicht wirksam. Was ich mich frage ist, ob es 
vielleicht einen LPC213x.s Code gibt, der liegt jedoch der Eval Version 
nicht anbei.

Weiss da jemand einen Rat? Wie bringe ich dem uC bei, dass er bei 0 
starten soll? Ach ja, die Schalter für das Laden per RS232 auf dem 
Demoboard sind abgeschaltet, ers springt also nicht in die Bootloader 
Routine hinein.

Was ohne weiteres funktioniert ist das Starten, wenn ich "Flash debug" 
brenne, er bootet dann auch ohne JTAG Kabel und die Crossworks Umgebung.

Gruss,
Christian

von Christian J. (elektroniker1968)


Lesenswert?

@Nils:

Um das nochmal auszugraben (ich kann eh nicht schlafen bei Vollmond).
1
int main(void)
2
{
3
  
4
  ctl_set_isr(11, 11, CTL_ISR_TRIGGER_FIXED, isr, 0);
5
  ctl_unmask_isr(11);
6
  
7
}

ist mit der ersten 11 die Interruptquelle SPI gemeint? Beim LPC.... gibt 
es 16 Quellen, jede ist einer Hardware zugeordnet.

es gibt zudem zwei ctl Header, eine low-level und einen für 
"programmable interrupt controllers". weiterhin wird behauptet, dass der 
ARM keinen programmierbaren Controller hat, daher müsse man die bekannte 
Syntax anwenden:
1
Interrupt service routine (ARM example)
2
3
This example declares an ISR using the GCC syntax for declaring naked functions and accessing assembly code instructions.
4
5
void irq_handler(void) __attribute__((naked))


Bin da jetzt ein bisschen verwirrt, kann man wirklich nicht die 
komfortablen ctl Funktionen zur Interruptsteuerung verwenden?

von Christian J. (elektroniker1968)


Lesenswert?

PS:

Lüppt eh nicht...., kriege vom Linker die Meldungen, dass er die ctl 
Funktionen nicht referenzieren kann, obwohl die im Header eingebunden 
wurden.

grumpf

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

> kriege vom Linker die Meldungen, dass er die ctl
> Funktionen nicht referenzieren kann, obwohl die im Header eingebunden
> wurden.

Den Linker interessieren eingebundene Header nicht, Du musst schon 
angeben, welche Library gelinkt werden muss.

Das sollte bei CW unter Project Options -> Linker -> Additional Input 
Files möglich sein.

http://rowley.co.uk/documentation/arm_1_7/ide_property_linker_help.htm

von kumar (Gast)


Lesenswert?

Hi guys,

        I I just read the discussion here. I could abel to understand 
half of it. I have aproblem with the CTL . my code runs with JATAG , 
reset my board then the program hangs , bootloader boots and starts the 
application.but the application hangs.any sugestion would be helpfull.

cheers
Kumar

von Christian J. (elektroniker1968)


Lesenswert?

Read this, it helps :-)

http://ccgi.rowley.co.uk/support/faq.php?do=article&articleid=35

Please tell us what ARM7 you use and how it works with the ctl 
functions. I am not sure if the arm7 has a programmable IRQ controller 
or not. I get linker errors when trying to use the ctl functions.

von Ashok K. (kumar)


Lesenswert?

Hi Cristian,

             THanks for the reply.we use str71 processor, and it has the 
EIC(extended interreput controller). what kind of linker error you are 
getting.you could link the ctl library in to your project and need to do 
some porting stuff for your target like which timer to use for the 
ctl_tick.you can find the board support package for most of the target 
from crossworks where the ctl porting is done.

Cheers
kumar

von Christian J. (elektroniker1968)


Lesenswert?

Hello,

the question is: Has the LPC22xx from NXP a "programmable" IRQ System? 
In my opinion the VIC is not programmable, it is only a vectored IRQ 
system.

Maybe my error is, that I don not include the Library in the linker 
file. I only include the ctl.h File same way like I use other standard 
libearys. The linker knows the path to the standard libs.

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.