Forum: Mikrocontroller und Digitale Elektronik Interrupt Vector + "Module Base"?


von Markus (Gast)


Lesenswert?

Hallo Zusammen,

Ich versuche gerade herrauszufinden wie Adresse des Sequence complete 
Interrupt des ADC vom MC9S12C lautet. Also die Adresse im Speicher wo er 
nach auslösen hinspringt. Hab das Datenblatt schon x-mal durchforstet 
und es gelingt mir nicht.
Zudem stosse ich immer wieder auf Adressangaben wie "Module Base + 
0x001" - Was ist die "Module Base"?

Danke für eure Hilfe!

von Markus (Gast)


Lesenswert?

Ok, Nachtrag.
Ich habe jetzt doch etwas gefunden, macht mich aber nicht wirklich 
Schlauer. Es müsste laut Datenblatt diese Adresse sein, oder: 0xFFD2, 
0xFFD3 ATD.
Ok, das sind 2 Speicherstellen aber wie passt da noch ein Jumpbefehl 
davor? Oder ist da beim HCs12 nicht mehr nötig und ich bin noch etwas 
Odlscool?
Des weiteren verstehe ich den Code eines Kollegen nicht welcher für 
einen Timer-interrupt folgenden Code geschrieben hat:
1
void initTimer(void) {
2
  // timer enable, freeze while BDM
3
  *((unsigned char *) 0x0fe2) = 0x06; 
4
  *((void(**)(void))  0x0fe3) = timer_interrupt;  
5
  TSCR1   = 0x80;  // Timer enable
6
  TSCR2  = 0x07;  // Prescaler = 128 (1 timer tick every 16µs)
7
  TCTL2  = 0x00;  // TC2 disconnected from Pin
8
  TIOS  |= 0x04;  // TC2 is Output Compare
9
  TIE |= 0x04;  // TC2 Interrupt enable
10
}
Ich dachte bissher immer die "0x0fe3" wäre die Adresse für den 
Timmerinterrupt. Passt dan aber nicht mit der Tabelle im Datenblatt 
zusammen.

von Karl H. (kbuchegg)


Lesenswert?

Markus schrieb:

>   *((unsigned char *) 0x0fe2) = 0x06;
>   *((void(**)(void))  0x0fe3) = timer_interrupt;


> Ich dachte bissher immer die "0x0fe3" wäre die Adresse für den
> Timmerinterrupt. Passt dan aber nicht mit der Tabelle im Datenblatt
> zusammen.

Wieso? Passt doch wunderbar:

>   *((void(**)(void))  0x0fe3) = timer_interrupt;

timer_interrupt wird wohl die aufzurufende Funktion sein. Deren Adresse 
wird beginnend ab 0x0fe3 abgelegt. Der cast links sieht etwas seltsam 
aus (eigentlich müsste es ein Stern alleine auch tun), ist aber dem 
Datentyp nach ein Pointer auf eine Funktion.

>   *((unsigned char *) 0x0fe2) = 0x06;

das wird dann wohl der 'Jump' sein. Schau doch mal ins Datenblatt deines 
Prozessors welcher OpCode sich hinter 0x06 verbirgt.

von Markus (Gast)


Lesenswert?

Passt wunderbar? - Dann bin ich zu doof.
Im datenblatt steht was von Adresse 0xFFDE, 0xFFDF für Standard 
timer overflow TMSK2 (TOI), das ist aber weit entfernt von 0x0FE3.

>das wird dann wohl der 'Jump' sein.
Richtig, ist ein Jump aber ich bin immer noch verwirrtt wegen der 
Adresse. Der Code mit Funktioniert aber ich komm nicht dahinter wo mein 
Kollege diese Adressangaben herhat.

von Karl H. (kbuchegg)


Lesenswert?

Markus schrieb:
> Passt wunderbar? - Dann bin ich zu doof.
> Im datenblatt steht was von Adresse 0xFFDE, 0xFFDF für Standard
> timer overflow TMSK2 (TOI), das ist aber weit entfernt von 0x0FE3.
>
>>das wird dann wohl der 'Jump' sein.
> Richtig, ist ein Jump aber ich bin immer noch verwirrtt wegen der
> Adresse. Der Code mit Funktioniert aber ich komm nicht dahinter wo mein
> Kollege diese Adressangaben herhat.

Jetzt bin ich verwirrt.

Dein Aussage:

"Ich dachte bissher immer die "0x0fe3" wäre die Adresse für den
Timmerinterrupt."

Und im Code schreibt er die Adresse einer Funktion namens 
"timer_interrupt" nach 0x0fe3.

Beides mal die gleiche Adresse - was verwirrt dich daher?


Was soll da nicht passen? (OK, die Frage bleibt, warum der eigentliche 
jump nach 0x0fe2 kommt, aber das kann ich dir nicht beantworten)


> Im datenblatt steht was von Adresse 0xFFDE, 0xFFDF für Standard
> timer overflow TMSK2 (TOI), das ist aber weit entfernt von 0x0FE3.

Da geb ich dir recht. Aber ohne das Datenblatt ist das schwer zu 
entscheiden.

von Christian G. (christiang)


Angehängte Dateien:

Lesenswert?

Hallo Markus,

leg dir eine Vektortabelle an und trage alle benutzten Interrupts dort 
ein. Für nicht benutzte Interrupts legts du dir einen DummyIsr an.
Damit brauchst du solche Häßlichkeiten wie
  *((unsigned char *) 0x0fe2) = 0x06;
  *((void(**)(void))  0x0fe3) = timer_interrupt;
nicht, das erledigt dann dein Linker. Bei deinem manuellem Konstrukt 
mußt du bei jeder Änderung diese Adressen kontrollieren und anpassen. 
Dann muss die Vektortabelle nur noch an die richtige Adresse des FLASH 
gelinkt werden. Bei den Frescale S12 ist das normalerweise ganz am Ende.

Im Anhang mal ein Beispiel des S12C32.

Zu deiner Frage mit dem Module Base: Du kannst bei dem S12 das RAM, das 
EEPROM und die Register verschieben, damit ändert sich dann (natürlich) 
die Module Base Adresse und du mußt die Registeradressen anpassen.

von Markus (Gast)


Lesenswert?

>Beides mal die gleiche Adresse - was verwirrt dich daher?
Mich verwirrt dass im Datenblatt etwas anderes steht und ich die Adresse 
"0x0fe3" dort niergens finden kann. Der Code funktioniert aber dennoch.

>Da geb ich dir recht. Aber ohne das Datenblatt ist das schwer zu
entscheiden.

Wäre jemand so nett und schaut mal ins Datenblatt des MC9S12C und sagt 
mit die Adresse für den "Sequence complete
Interrupt" des ADC? - Danke

>leg dir eine Vektortabelle an und trage alle benutzten Interrupts dort
ein.

Ist im Prinzip eine gute Idee aber dazu muss ich erstmal Verstehen wo 
den die Adressen der Interrupts liegen um so eine Tabelle anzulegen. 
Aber da bin ich im Augenblick noch nicht angekommen.

Was ich auch noch nicht verstehe: Im Datenblatt stehen 2 Adressen - Wie 
pack ich da eine neue Adresse und einen Jump Befehl rein - Ich dachte 
ich bräuchte da zumindest 3 freie Speicherstellen?

Danke Euch!

von Christian G. (christiang)


Lesenswert?

OK, dir fehlt ein klein wenig das Verständis, wie das mit den Interrupts 
so abläuft.

DIe Adresse des Sequence Complete Interrupts ist 0xFFD2, d.h. an dieser 
Adresse (16 Bit! 0xFFD2 und 0xFFD3) steht wo der erste Befehl der ATD 
Sequence complete Service Routine im Adressraum steht. Oder anders 
formuliert, der Inhalt diese Adresse zeigt auf eine andere Adresse, 
nämlich die der Serviceroutine.
Du brauchst hier also nicht mit Gewalt ein Jump hinzuschreiben, das geht 
dann immer schief.

Soweit verstanden?

Deshalb eine Vektortabelle anlegen, so ungefähr wie ich sie gepostet 
habe, Serviceroutine eintragen und den Rest vom Linken erledigen lassen.

von Markus (Gast)


Lesenswert?

>OK, dir fehlt ein klein wenig das Verständis, wie das mit den Interrupts
>so abläuft.

Ja, ich hab noch wenig Erfahrung mit dem HCS12 und auch mit dem 
GNU-Compiler.
Ich weis nur das es beim 80c535 3 Speicherstellen waren, eine für einen 
"jmp" und 2 für die Adresse. Aber so wie ich dich verstehe ist der HCS12 
da schon etwas weiter und springt automatisch an die Adresse die er an 
0xFFD2 und 0xFFD3 findet. Bin halt schon etwas in die Jahre gekommen ;-)

Wie gesagt, auch mit dem Gnu-Compiler bin ich noch nicht wirklich 
vertraut darum noch eine Frage zur Vectortabelle.


Funktioniert das so? Hab es in der GNU-Documentation so gefunden. Wird
(".vectors") mit der ersten Adresse der Vectortabelle automatisch vom 
Compiler erstezt oder muss ich da noch etwas tun?
1
extern void _start(void);/* entry point in crt0.s */
2
extern void __attribute__((interrupt)) ADC_cov_complete (void);
3
void __attribute__((interrupt)) isr_empty(void){/* do nothing */}
4
5
void __attribute__ (( section (".vectors") )) (* const interrupt_vectors[])(void) = {
6
       isr_empty, /* $ffc0: reserved */
7
       isr_empty, /* $ffc2: reserved */
8
       isr_empty, /* $ffc4: reserved */
9
       isr_empty, /* $ffc6: reserved */
10
       isr_empty, /* $ffc8: reserved */
11
       isr_empty, /* $ffca: reserved */
12
       isr_empty, /* $ffcc: reserved */
13
       isr_empty, /* $ffce: reserved */
14
       isr_empty, /* $ffd0: reserved */
15
       ADC_cov_complete, /* $ffd2: ADC_cov_complete */
16
       isr_empty, /* $ffd4: reserved */
17
       isr_empty, /* $ffd6: SCI serial system */
18
       isr_empty, /* $ffd8: SPI serial transfer complete (SPIE) */
19
       isr_empty, /* $ffda: Pulse accumulator input edge (PAII) */
20
       isr_empty, /* $ffdc: Pulse accumulator overflow (PAOVI) */
21
       isr_empty, /* $ffde: Timer overflow (TOI) */
22
       isr_empty, /* $ffe0: Timer channel 7 */
23
       isr_empty, /* $ffe2: Timer channel 6 */
24
       isr_empty, /* $ffe4: Timer channel 5 */
25
       isr_empty, /* $ffe6: Timer channel 4 */
26
       isr_empty, /* $ffe8: Timer channel 3 */
27
       isr_empty, /* $ffea: Timer channel 2 */
28
       isr_empty, /* $ffec: Timer channel 1 */
29
       isr_empty, /* $ffee: Timer channel 0 */
30
       isr_empty, /* $fff0: Real-time interrupt (RTII) */
31
       isr_empty, /* $fff2: -IRQ (external pin) */
32
       isr_empty, /* $fff4: -XIRQ pin */
33
       isr_empty, /* $fff6: Software interrupt */
34
       _start, /* $fff8: Illegal opcode trap */
35
       _start, /* $fffa: COP failure (NOCOP) */
36
       _start, /* $fffc: Clock monitor fail (CME) */
37
       _start /* $fffe: -RESET (hardware reset) */
38
};
Danke und Gruß!

von Christian G. (christiang)


Lesenswert?

Hallo,

sieht gut aus. Sollte so funktionieren.
Der Ausdruck "( section (".vectors") )" markiert dieen Code als Sektion. 
Diese Sektion wiederum gibt an, wo der Code hin gelinkt werden soll. 
Deshalb muss im Linkerfile auch ein Label .vectors auftauchen und mit 
der richtigen Adresse verknüpft sein.
So ist es zumindest bei Metrowerks, Cosmic oder anderen Compilern. Den 
GNU kenne ich nicht, vermute aber mal, dass der auch so arbeitet.

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.