Hallo,
das AVR-GCC Tutorial sagt mir da leider nicht genug. Soweit ich das
verstanden habe, heißt die eigentliche Interruptroutine
ISR(vectorname){}.
In meinem Fall sollen Interrupts von PIOC Bit 8 und 9 behandelt werden.
Leider finde ich aber nicht heraus, wie der dazugehörige Vektorname
heißt. Es ist weder PIOC_Handler noch PIOC_IRQn, die ich in sam3x8e.h
finde, damit bekomme ich nur Fehlermeldungen, daß z.B. der PIOC_Handler
schon definiert ist. Das ist tatsächlich auch der Fall, ich fand eine
entsprechende Funktion, die schon vorgegeben war. Die fragt
offensichtlich alle 32 möglichen Bits ab und macht dann abhängig davon
was, was ich nicht mehr verstehe (in pio_handler.c ab Zeile 86, da mein
Atmel Studio auf einem PC ohne Internetanschluß ist und ich nur fürs
Intrernet einen alten Linux-PC benutze, ist es extrem umständlich, Code
herüber zu kopieren).
Gibt es irgendwo ein kleines Beispielprojekt, das eine Interruptroutine
benutzt, so daß man mal sehen kann, wie das gemacht wird? Es muß nicht
unbedingt ein PIO-Interrupt sein, als Beispiel tut es z.B. auch ein
Timer- oder UART-Interrupt oder sonst einer. Wichtig ist nur noch eine
Angabe, wo man alle Vektornamen für die Interruptroutinen finden kann.
Gruß
Andy
Hallo Andy,
Andreas W. schrieb:> das AVR-GCC Tutorial sagt mir da leider nicht genug. Soweit ich das> verstanden habe, heißt die eigentliche Interruptroutine> ISR(vectorname){}.
Das gilt aber nur fuer AVR, nicht fuer die ARM-Controller von Atmel. Das
hast du ja aber schon festgestellt. :)
Andreas W. schrieb:> Leider finde ich aber nicht heraus, wie der dazugehörige Vektorname> heißt.
Einen Vektornamen brauchst du nicht, da jeder IRQ seinen eigenen Handler
hat, und es keine "universal" Funktion wie bei den AVR ist.
Andreas W. schrieb:> ibt es irgendwo ein kleines Beispielprojekt, das eine Interruptroutine> benutzt, so daß man mal sehen kann, wie das gemacht wird?
Das ist eigentlich total einfach (wie immer: nur dann, wenn man weiss
wie :) )
1
#include"sam.h"
2
3
// Interrupt fuer Timer 0
4
voidTC0_Handler(void)
5
{
6
7
}
8
9
intmain(void)
10
{
11
/* Initialize the SAM system */
12
SystemInit();
13
14
// Globaler Interrupt einschalten
15
NVIC_EnableIRQ(TC0_IRQn);
16
17
// Interrupt prioritaet setzen, niedrige nummer == hohe prio
18
NVIC_SetPriority(TC0_IRQn,6);
19
20
// Globaler Interrupt abschalten
21
//NVIC_DisableIRQ(TC0_IRQn);
22
23
while(1)
24
{
25
//TODO:: Please write your application code
26
}
27
}
Natuerlich muesste der Timer vorher noch konfiguriert werden :)
Andreas W. schrieb:> Wichtig ist nur noch eine> Angabe, wo man alle Vektornamen für die Interruptroutinen finden kann.
Der Name des IRQ-Handlers ergibt sich einfach aus dem Modul das du
benutzen moechtest.
UART0 --> UART0_Handler --> UART0_IRQn
USART3 --> USART3_Handler --> USART3_IRQn
PIOC --> PIOC_Handler --> PIOC_IRQn
TC5 --> TC5_Handler --> TC5_IRQn
usw.
Hinweise
========
Watchdog
========
Du musst den Watchdog abschalten, da dieser standardmaessig
eingeschaltet ist. ansonsten startet sich der Controller ca. alle 18
sek. neu.
Heap/Stack
==========
In Atmel Studio findest du im Solution Explorer unter cmsis ->
linkerScripts die Linker Scripte. Darin ist die max. groesse fuer Heap
und Stack definiert! Die musst du vielleicht an deine Beduerfnisse
anpassen.
UART/USART
==========
Im gegensatz zu den AVR hast du hier keine getrennten Interrupts zum
senden und empfangen! Das heisst du musst in der ISR abfragen, was jetzt
den IRQ ausgeloest hat.
1
voidUSART1_Handler(void)
2
{
3
uint32_tirq_status=USART1->US_CSR;
4
5
if(irq_status&empfangs_interrupt_bit_maske)
6
{
7
8
}
9
10
if(irq_status&sende_interrupt_bit_maske)
11
{
12
13
}
14
}
Peripherie
==========
Atmel stellt dir Pointer auf Strukturen zur verfuegung. Da das bei den
Timern am anfang vielleicht etwas verwirrend sein kann, hier eine
aufschluesselung fuer die Timer:
1
TC0[0].TC_CHANNEL->TC_SR;// Timer 0 Status Register --> Timer 0 Kanal 0
2
TC0[1].TC_CHANNEL->TC_SR;// Timer 1 Status Register --> Timer 0 Kanal 1
3
TC0[2].TC_CHANNEL->TC_SR;// Timer 2 Status Register --> Timer 0 Kanal 2
4
5
TC1[0].TC_CHANNEL->TC_SR;// Timer 3 Status Register --> Timer 1 Kanal 0
6
TC1[1].TC_CHANNEL->TC_SR;// Timer 4 Status Register --> Timer 1 Kanal 1
7
TC1[2].TC_CHANNEL->TC_SR;// Timer 5 Status Register --> Timer 1 Kanal 2
8
9
TC2[0].TC_CHANNEL->TC_SR;// Timer 6 Status Register --> Timer 2 Kanal 0
10
TC2[1].TC_CHANNEL->TC_SR;// Timer 7 Status Register --> Timer 2 Kanal 1
11
TC2[2].TC_CHANNEL->TC_SR;// Timer 8 Status Register --> Timer 2 Kanal 2
Andere Peripherie ist nicht als "Array" angeordent, wie die Timer, aber
der aufruf fuer die Strukturen ist analog.
1
PIOA->PIO_PSR;
2
PIOB->PIO_PSR;
3
PIOC->PIO_PSR;
4
PIOD->PIO_PSR;
5
6
TRNG->...
7
UART0->..
8
USART3->..
usw.
Du musst die Peripherie einzeln einschalten. das Kapitel im Datenlbatt
dazu ist "29. Power Managment Controller (PMC)", Seite 535.
Die ID fuer ein Peripheriemodul findest du in Kapitel "11. Peripherals",
Seite 47.
PIO - Pins setzen
=================
Um einen Pin auf 1 zu setzen musst du das entsprechende Bit im "Set
Output Data Register" auf 1 setzen.
1
// Setze Pin 0 von PIOA auf 1
2
PIOA->PIO_SODR=0x00000001;
Um den Pin wieder auf 0 zu setzen musst du das entsprechende Bit im
"Clear Output Data Register" auf 1 setzen.
1
// Setze Pin 0 von PIOA auf 0
2
PIOA->PIO_CODR=0x00000001;
Auch das unterscheidet sich also von den AVR, wo man setzen und loeschen
uber ein Register macht. Du hast hier also getrennte register um einen
Pin auf High oder Low zu setzen, und du musst jeweils eine 1 an die
entsprechende Stelle schreiben.
So, ich hoffe das hilft dir erstmal ein bisschen :)
Wenn du konkreten Code brauchst, am Montag kann ich dir Code geben, z.B.
fuer die initialisierung von Timer/Usart und die IRQ-Handler.
Ich glaub ich koennte dazu mal einen entsprechenden Artikel schreiben.
:)
Gruesse
Hallo,
das sieht so aus, als wird es mir weiterhelfen. Kann sein, daß es noch
etwas dauert, bis ich das ausprobieren kann. Die Sache mit dem Watchdog
und dem PMC Power Management Controller habe ich selber schon
herausgefunden. Die Interruptroutine selbst mit Namen von z.B.
TC0_Handler habe ich auch schon probiert, allerdings fehlten mir die
funktionen zum Einschalten des Interrupts. Also war ich wohl gar nicht
so weit weg von der Lösung. Daß man z.B. den Timer zuerst initialisieren
muß, ist klar.
Was nicht funktioniert, ist auf diese Weise eine Interruptroutine für
einen einzelnen Portpin, z.B. PIOC_Handler, da meckert der
Compiler/Linker, daß diese Funktion schon vorhanden ist und hier doppelt
ist. Allerdings brauche ich wohl erst einmal keinen Portpin-Interrupt.
Wie man die Portpins normal bedient, habe ich schon heraus, ich habe
auch eigene Funktionen dafür geschrieben, um z.B. auch mehrere Pins auf
einen Rutsch (z.B. PD0-PD7 für einen 8-Bit Bus für ein 7"-LCD) direkt
beschreiben zu können. Ohne Interrupt geht das ja. Auch das
Konfigurieren von Ports für andere Hardware (z.B: Timer, SPI usw.
funktioniert.
Zumindest sind die Tipps hier schon einmal hilfreich, mit google hatte
ich nur teilweise diese Informationen finden können.
Gruß
Andy
Andreas W. schrieb:> Zumindest sind die Tipps hier schon einmal hilfreich,
Das freut mich :)
Andreas W. schrieb:> mit google hatte> ich nur teilweise diese Informationen finden können.
Ging mir auch so, als ich mit den SAM angefangen hatte. Fuer die gibt es
im vergleich zu STM32 praktisch gar nichts im Internet :-/
Andreas W. schrieb:> Was nicht funktioniert, ist auf diese Weise eine Interruptroutine für> einen einzelnen Portpin,
Das gibt es so auch nicht fuer einen einzelnen Pin. Du nimmst den
Handler fuer den Port, und dann musst du abfragen welcher Pin den IRQ
ausgeloest hat.
Hallo,
ja genau so habe ich das versucht, aber das geht nicht. Bei der Funktion
PIOC_Handler mosert der Compiler/Linker, daß die Funktion doppelt ist,
während z.B. TC0_Handler problemlos compilierbar ist. PIOC_Handler ist
irgendwo hart codiert, das hatte ich auch gefunden (find in all files),
werde da aber nicht schlau, was man damit dann weiter machen soll.
Irgendwo ist da auch ein Funktionspointer, aber ich bekam nichts
funktionierendes hin.
Gruß
Andy
Hallo,
ich glaub ich kann mich hier mal anhängen, wenns OK ist.
Wärst du so freundlich mal ein Beispiel für den USART0 ( init, senden,
lesen per interrupt ) einzustellen?
Ich muss mich grad mit dem Controller befassen, habe mit ARM aber noch
nicht soviel gemacht. Ich hab ein Beispiel aus dem ASF übernommen aber
es gehen keine Daten raus bzw. rein...
enable ich den TX interrupt, läuft er permanent rein, obwohl pro Sekunde
ein Zeichen gesendet werden sollte.
Hallo Kay
Ist schon ne weile her, aber da ich auf das selbe Problem gestossen bin
dachte ich ich lass die Infos mal für zukünftige Googler hier:
Der Grund warum dein Code nicht kompiliert ist weil der pio-Driver den
Handler bereits implementiert. Du kannst dem Driver aber deinen eigenen
Handler als Function-Pointer mitteilen:
Moin moin,
ich schlage mich auch gerade damit rum und versuche das noch mal hoch zu
holen. Die Arduino IDE meckert auch bei dem PIO Handler rum (mehrfache
Definition). Jetzt würde ich gerne den Tipp von Simon einbauen. Das sind
für mich aber ehrlich gesagt böhmische Dörfer was in dem ersten
Codeschnipsel von ihm steht. Wo baue ich das denn in dem genannten
Beispiel von Kaj G. oben ein?
Was steht denn dann in den beiden Parametern id_source und mask_source
drin?
Ich hoffe ihr könnt mir da noch helfen.
Grüße
Sven
Hallo,
ich muss leider das Thema aufgreifen. Ich möchte mmit Atmel Studio 7
möglichst ohne die ASF Bibliothek (pio_handler_set_pin etc.) 3 externe
Interrupts auf der steigenden Flanke zum laufen bekommen.
Da wenig Pins genutzt werden würde nicht mal eine Abfrage nach der
genauen ID von Nöten sein.
Das Problem ist in dem Moment gegeben in dem ich versuche sam.h
einzubinden. Kann mir jemand bitte sagen was ich machen muss.
Gruß Philipp