Forum: Compiler & IDEs wie schreibt man eine Vektortabelle für Cortex-M4?


von Bauform B. (bauformb)


Lesenswert?

1
// vector-table.c
2
  
3
#include <stddef.h>
4
#include "irqn.h"
5
#include "vectortable.h"
6
#include "syslib.h"
7
8
extern crt0_type  crt0;
9
extern isr_type   crash;  // All-purpose fault handler
10
extern isr_type   syscall_isr, pendsv_isr, systick_isr;
11
extern isr_type   pvd_isr;
12
extern isr_type   uart0_isr, uart1_isr, uart2_isr, uart3_isr, uart4_isr;
13
extern uint32_t   tos;
14
15
#pragma GCC diagnostic ignored "-Woverride-init"
16
#pragma GCC diagnostic ignored "-pedantic"
17
const vector_struct __attribute__ ((aligned (512), section ".vector_table")))
18
vector_table = {
19
   &tos,                  //   0   0  Initial SP, defined in linker script
20
   crt0,                  //   1   4  Initial PC = Reset-"Handler"
21
   crash,                 //   2   8  CSS Clock security system, NMI
22
   crash,                 //   3   c  Hard fault (double fault)
23
   crash,                 //   4  10  Memory protection
24
   crash,                 //   5  14  Bus fault
25
   crash,                 //   6  18  Usage fault
26
   crash,                 //   7  1c  -
27
   crash,                 //   8  20  -
28
   crash,                 //   9  24  -
29
   crash,                 //  10  28  -
30
   syscall_isr,           //  11  2c  SVC instruction
31
   crash,                 //  12  30  Debug monitor
32
   crash,                 //  13  34  -
33
   pendsv_isr,            //  14  38  Pendable request for system service
34
   systick_isr,           //  15  3c  System tick timer
35
   {  
36
      [__extension__ 0 ... 111] = crash,
37
      [PVD_PVM_IRQn] = pvd_isr,   // PVD thru EXTI line detection
38
      [UART0_IRQn] = uart0_isr,
39
      [UART1_IRQn] = uart1_isr,
40
      [UART2_IRQn] = uart2_isr,
41
      [UART3_IRQn] = uart3_isr,
42
      [UART4_IRQn] = uart4_isr
43
   }
44
};
Also so geht es schon mal nicht. Und ohne die #pragma geht es noch 
schlechter. Aber wirklich übel ist die Warnung, obwohl ich _extension_ 
dazu schreibe:
1
warning: ISO C forbids specifying range of elements to initialize
ISO C meint also, ich sollte über 100 mal crash schreiben? Damit man 
dann die uart_isr mittendrin nicht wiederfindet?

Wie macht ihr das?

von Jim M. (turboj)


Lesenswert?

Das Linker Skript ist der entscheidende Teil, und den haste natürlich 
nicht gepostet. So kann das nicht tun.

Bauform B. schrieb:
> warning: ISO C forbids specifying range of elements to initialize

Was haste denn als C-Dialekt eingestellt? Ich verwende i.d.R. -std=gnu99 
oder -std=gnu11 je nach GCC Version. Ohne das "gnu" sind Extensions 
nicht aktiv IMHO (oder erzeugen Warnings).

von Bauform B. (bauformb)


Lesenswert?

Jim M. schrieb:
> Das Linker Skript ist der entscheidende Teil, und den haste natürlich
> nicht gepostet. So kann das nicht tun.

??? Hier geht's doch um C-Syntax oder maximal -Semantik ???

> Was haste denn als C-Dialekt eingestellt? Ich verwende i.d.R. -std=gnu99
> oder -std=gnu11 je nach GCC Version.
-std=c2x

> Ohne das "gnu" sind Extensions nicht aktiv IMHO (oder erzeugen Warnings).

Eigentlich logisch, aber für 0b01010101 hat extension funktioniert? 
Rätselhaft.

von Bernd K. (prof7bit)


Lesenswert?

1
#define SECT_VECTABLE           __attribute__((section(".isr_vector"), __used__))
2
#define WEAK_DEFAULT            __attribute__((weak, alias("Default_Handler")))
3
4
5
void Default_Handler(void) {
6
    while(1);
7
}
8
9
10
WEAK_DEFAULT void NMI_Handler(void);
11
WEAK_DEFAULT void HardFault_Handler(void);
12
WEAK_DEFAULT void MemManage_Handler(void);
13
WEAK_DEFAULT void BusFault_Handler(void);
14
WEAK_DEFAULT void UsageFault_Handler(void);
15
WEAK_DEFAULT void SVC_Handler(void);
16
WEAK_DEFAULT void DebugMon_Handler(void);
17
WEAK_DEFAULT void PendSV_Handler(void);
18
WEAK_DEFAULT void SysTick_Handler(void);
19
WEAK_DEFAULT void WWDG_IRQHandler(void);                /* Window WatchDog              */
20
WEAK_DEFAULT void PVD_IRQHandler(void);                 /* PVD through EXTI Line detection */
21
WEAK_DEFAULT void TAMP_STAMP_IRQHandler(void);          /* Tamper and TimeStamps through the EXTI line */
22
WEAK_DEFAULT void RTC_WKUP_IRQHandler(void);            /* RTC Wakeup through the EXTI line */
23
WEAK_DEFAULT void FLASH_IRQHandler(void);               /* FLASH                        */
24
WEAK_DEFAULT void RCC_IRQHandler(void);                 /* RCC                          */
25
WEAK_DEFAULT void EXTI0_IRQHandler(void);               /* EXTI Line0                   */
26
WEAK_DEFAULT void EXTI1_IRQHandler(void);               /* EXTI Line1                   */
27
WEAK_DEFAULT void EXTI2_IRQHandler(void);               /* EXTI Line2                   */
28
WEAK_DEFAULT void EXTI3_IRQHandler(void);               /* EXTI Line3                   */
29
WEAK_DEFAULT void EXTI4_IRQHandler(void);               /* EXTI Line4                   */
30
WEAK_DEFAULT void DMA1_Stream0_IRQHandler(void);        /* DMA1 Stream 0                */
31
WEAK_DEFAULT void DMA1_Stream1_IRQHandler(void);        /* DMA1 Stream 1                */
32
WEAK_DEFAULT void DMA1_Stream2_IRQHandler(void);        /* DMA1 Stream 2                */
33
WEAK_DEFAULT void DMA1_Stream3_IRQHandler(void);        /* DMA1 Stream 3                */
34
WEAK_DEFAULT void DMA1_Stream4_IRQHandler(void);        /* DMA1 Stream 4                */
35
WEAK_DEFAULT void DMA1_Stream5_IRQHandler(void);        /* DMA1 Stream 5                */
36
WEAK_DEFAULT void DMA1_Stream6_IRQHandler(void);        /* DMA1 Stream 6                */
37
WEAK_DEFAULT void ADC_IRQHandler(void);                 /* ADC1(void); ADC2 and ADC3s   */
38
WEAK_DEFAULT void EXTI9_5_IRQHandler(void);             /* External Line[9:5]s          */
39
WEAK_DEFAULT void TIM1_BRK_TIM9_IRQHandler(void);       /* TIM1 Break and TIM9          */
40
WEAK_DEFAULT void TIM1_UP_TIM10_IRQHandler(void);       /* TIM1 Update and TIM10        */
41
WEAK_DEFAULT void TIM1_TRG_COM_TIM11_IRQHandler(void);  /* TIM1 Trigger and Commutation and TIM11 */
42
WEAK_DEFAULT void TIM1_CC_IRQHandler(void);             /* TIM1 Capture Compare         */
43
WEAK_DEFAULT void TIM2_IRQHandler(void);                /* TIM2                         */
44
WEAK_DEFAULT void TIM3_IRQHandler(void);                /* TIM3                         */
45
WEAK_DEFAULT void TIM4_IRQHandler(void);                /* TIM4                         */
46
WEAK_DEFAULT void I2C1_EV_IRQHandler(void);             /* I2C1 Event                   */
47
WEAK_DEFAULT void I2C1_ER_IRQHandler(void);             /* I2C1 Error                   */
48
WEAK_DEFAULT void I2C2_EV_IRQHandler(void);             /* I2C2 Event                   */
49
WEAK_DEFAULT void I2C2_ER_IRQHandler(void);             /* I2C2 Error                   */
50
WEAK_DEFAULT void SPI1_IRQHandler(void);                /* SPI1                         */
51
WEAK_DEFAULT void SPI2_IRQHandler(void);                /* SPI2                         */
52
WEAK_DEFAULT void USART1_IRQHandler(void);              /* USART1                       */
53
WEAK_DEFAULT void USART2_IRQHandler(void);              /* USART2                       */
54
WEAK_DEFAULT void EXTI15_10_IRQHandler(void);           /* External Line[15:10]s        */
55
WEAK_DEFAULT void RTC_Alarm_IRQHandler(void);           /* RTC Alarm (A and B) through EXTI Line */
56
WEAK_DEFAULT void OTG_FS_WKUP_IRQHandler(void);         /* USB OTG FS Wakeup through EXTI line */
57
WEAK_DEFAULT void DMA1_Stream7_IRQHandler(void);        /* DMA1 Stream7                 */
58
WEAK_DEFAULT void SDIO_IRQHandler(void);                /* SDIO                         */
59
WEAK_DEFAULT void TIM5_IRQHandler(void);                /* TIM5                         */
60
WEAK_DEFAULT void SPI3_IRQHandler(void);                /* SPI3                         */
61
WEAK_DEFAULT void DMA2_Stream0_IRQHandler(void);        /* DMA2 Stream 0                */
62
WEAK_DEFAULT void DMA2_Stream1_IRQHandler(void);        /* DMA2 Stream 1                */
63
WEAK_DEFAULT void DMA2_Stream2_IRQHandler(void);        /* DMA2 Stream 2                */
64
WEAK_DEFAULT void DMA2_Stream3_IRQHandler(void);        /* DMA2 Stream 3                */
65
WEAK_DEFAULT void DMA2_Stream4_IRQHandler(void);        /* DMA2 Stream 4                */
66
WEAK_DEFAULT void OTG_FS_IRQHandler(void);              /* USB OTG FS                   */
67
WEAK_DEFAULT void DMA2_Stream5_IRQHandler(void);        /* DMA2 Stream 5                */
68
WEAK_DEFAULT void DMA2_Stream6_IRQHandler(void);        /* DMA2 Stream 6                */
69
WEAK_DEFAULT void DMA2_Stream7_IRQHandler(void);        /* DMA2 Stream 7                */
70
WEAK_DEFAULT void USART6_IRQHandler(void);              /* USART6                       */
71
WEAK_DEFAULT void I2C3_EV_IRQHandler(void);             /* I2C3 event                   */
72
WEAK_DEFAULT void I2C3_ER_IRQHandler(void);             /* I2C3 error                   */
73
WEAK_DEFAULT void FPU_IRQHandler(void);                 /* FPU                          */
74
WEAK_DEFAULT void SPI4_IRQHandler(void);                /* SPI4                         */
75
76
77
typedef struct {
78
    long* initial_stack;
79
    void(*vectors[])(void);
80
} vector_table_t;
81
82
83
SECT_VECTABLE const vector_table_t __vector_table = {
84
    .initial_stack = __stack,
85
    .vectors = {
86
        /*
87
         * Exception handlers that belong to the ARM core itself
88
         */
89
        Reset_Handler,
90
        NMI_Handler,
91
        HardFault_Handler,
92
        MemManage_Handler,
93
        BusFault_Handler,
94
        UsageFault_Handler,
95
        0,
96
        0,
97
        0,
98
        0,
99
        SVC_Handler,
100
        DebugMon_Handler,
101
        0,
102
        PendSV_Handler,
103
        SysTick_Handler,
104
105
        /* External Interrupts */
106
        WWDG_IRQHandler,                    /* Window WatchDog              */
107
        PVD_IRQHandler,                     /* PVD through EXTI Line detection */
108
        TAMP_STAMP_IRQHandler,              /* Tamper and TimeStamps through the EXTI line */
109
        RTC_WKUP_IRQHandler,                /* RTC Wakeup through the EXTI line */
110
        FLASH_IRQHandler,                   /* FLASH                        */
111
        RCC_IRQHandler,                     /* RCC                          */
112
        EXTI0_IRQHandler,                   /* EXTI Line0                   */
113
        EXTI1_IRQHandler,                   /* EXTI Line1                   */
114
        EXTI2_IRQHandler,                   /* EXTI Line2                   */
115
        EXTI3_IRQHandler,                   /* EXTI Line3                   */
116
        EXTI4_IRQHandler,                   /* EXTI Line4                   */
117
        DMA1_Stream0_IRQHandler,            /* DMA1 Stream 0                */
118
        DMA1_Stream1_IRQHandler,            /* DMA1 Stream 1                */
119
        DMA1_Stream2_IRQHandler,            /* DMA1 Stream 2                */
120
        DMA1_Stream3_IRQHandler,            /* DMA1 Stream 3                */
121
        DMA1_Stream4_IRQHandler,            /* DMA1 Stream 4                */
122
        DMA1_Stream5_IRQHandler,            /* DMA1 Stream 5                */
123
        DMA1_Stream6_IRQHandler,            /* DMA1 Stream 6                */
124
        ADC_IRQHandler,                     /* ADC1, ADC2 and ADC3s         */
125
        0,                                  /* Reserved                     */
126
        0,                                  /* Reserved                     */
127
        0,                                  /* Reserved                     */
128
        0,                                  /* Reserved                     */
129
        EXTI9_5_IRQHandler,                 /* External Line[9:5]s          */
130
        TIM1_BRK_TIM9_IRQHandler,           /* TIM1 Break and TIM9          */
131
        TIM1_UP_TIM10_IRQHandler,           /* TIM1 Update and TIM10        */
132
        TIM1_TRG_COM_TIM11_IRQHandler,      /* TIM1 Trigger and Commutation and TIM11 */
133
        TIM1_CC_IRQHandler,                 /* TIM1 Capture Compare         */
134
        TIM2_IRQHandler,                    /* TIM2                         */
135
        TIM3_IRQHandler,                    /* TIM3                         */
136
        TIM4_IRQHandler,                    /* TIM4                         */
137
        I2C1_EV_IRQHandler,                 /* I2C1 Event                   */
138
        I2C1_ER_IRQHandler,                 /* I2C1 Error                   */
139
        I2C2_EV_IRQHandler,                 /* I2C2 Event                   */
140
        I2C2_ER_IRQHandler,                 /* I2C2 Error                   */
141
        SPI1_IRQHandler,                    /* SPI1                         */
142
        SPI2_IRQHandler,                    /* SPI2                         */
143
        USART1_IRQHandler,                  /* USART1                       */
144
        USART2_IRQHandler,                  /* USART2                       */
145
        0,                                  /* Reserved                     */
146
        EXTI15_10_IRQHandler,               /* External Line[15:10]s        */
147
        RTC_Alarm_IRQHandler,               /* RTC Alarm (A and B) through EXTI Line */
148
        OTG_FS_WKUP_IRQHandler,             /* USB OTG FS Wakeup through EXTI line */
149
        0,                                  /* Reserved                     */
150
        0,                                  /* Reserved                     */
151
        0,                                  /* Reserved                     */
152
        0,                                  /* Reserved                     */
153
        DMA1_Stream7_IRQHandler,            /* DMA1 Stream7                 */
154
        0,                                  /* Reserved                     */
155
        SDIO_IRQHandler,                    /* SDIO                         */
156
        TIM5_IRQHandler,                    /* TIM5                         */
157
        SPI3_IRQHandler,                    /* SPI3                         */
158
        0,                                  /* Reserved                     */
159
        0,                                  /* Reserved                     */
160
        0,                                  /* Reserved                     */
161
        0,                                  /* Reserved                     */
162
        DMA2_Stream0_IRQHandler,            /* DMA2 Stream 0                */
163
        DMA2_Stream1_IRQHandler,            /* DMA2 Stream 1                */
164
        DMA2_Stream2_IRQHandler,            /* DMA2 Stream 2                */
165
        DMA2_Stream3_IRQHandler,            /* DMA2 Stream 3                */
166
        DMA2_Stream4_IRQHandler,            /* DMA2 Stream 4                */
167
        0,                                  /* Reserved                     */
168
        0,                                  /* Reserved                     */
169
        0,                                  /* Reserved                     */
170
        0,                                  /* Reserved                     */
171
        0,                                  /* Reserved                     */
172
        0,                                  /* Reserved                     */
173
        OTG_FS_IRQHandler,                  /* USB OTG FS                   */
174
        DMA2_Stream5_IRQHandler,            /* DMA2 Stream 5                */
175
        DMA2_Stream6_IRQHandler,            /* DMA2 Stream 6                */
176
        DMA2_Stream7_IRQHandler,            /* DMA2 Stream 7                */
177
        USART6_IRQHandler,                  /* USART6                       */
178
        I2C3_EV_IRQHandler,                 /* I2C3 event                   */
179
        I2C3_ER_IRQHandler,                 /* I2C3 error                   */
180
        0,                                  /* Reserved                     */
181
        0,                                  /* Reserved                     */
182
        0,                                  /* Reserved                     */
183
        0,                                  /* Reserved                     */
184
        0,                                  /* Reserved                     */
185
        0,                                  /* Reserved                     */
186
        0,                                  /* Reserved                     */
187
        FPU_IRQHandler,                     /* FPU                          */
188
        0,                                  /* Reserved                     */
189
        0,                                  /* Reserved                     */
190
        SPI4_IRQHandler                     /* SPI4                         */
191
    }
192
};

Komplettes Beispiel hier: 
https://github.com/prof7bit/bare_metal_stm32f401xe

: Bearbeitet durch User
von Bauform B. (bauformb)


Lesenswert?

Bernd K. schrieb:
>   SVC_Handler,
>   DebugMon_Handler,
>   0,
>   PendSV_Handler,

Die Nuller sind ja äußerst interessant. Dann könnte ich ja die [0...111] 
Initialisierung weglassen und es wäre perfekt -- keine Warnungen, auch 
ohne #pragma usw.

Aber: führt 0 wirklich zu einem Usage Fault? Ja, weil das T-Bit nicht 
gesetzt ist; nein, weil das eine Adresse ist und deshalb die 
Stack-Adresse als Befehl ausgeführt würde. Das allerdings mit T-Bit = 0, 
hmm.

Also vermutlich ist es definiert aber reicht mir das? Dass irgendjemand 
bei ST (oder wer war das?) das so richtig findet heißt ja nun garnichts. 
Und wenn das Verhalten mit 0 definiert wäre, könnte man doch die ganzen 
weak-Einträge weglassen?

Ich hasse es, wenn es so verlockende Angebote gibt, die man dann doch 
nicht nutzen kann.

von Bernd K. (prof7bit)


Lesenswert?

Diese Vektoren existieren nicht, die werden nie aufgerufen, also kann da 
stehen was will.

von Bernd K. (prof7bit)


Lesenswert?

Bauform B. schrieb:
> könnte man doch die ganzen weak-Einträge weglassen?

Die welche nicht Null sind existieren, könnten also aufgerufen werden, 
also braucht man einen Mechanismus mit dem sich die Anwendung da bei 
Bedarf beim Linken einhaken kann, dieser Mechanismus ist weak.

Wenn die Anwendung keinen eigenen Handler mitbringt gilt der weiche 
Alias auf den Default Handler und dessen Adresse wird eingesetzt, 
andernfalls setzt der Linker die Adresse des starken Handlers aus der 
Anwendung ein.

: Bearbeitet durch User
von Bernd K. (prof7bit)


Lesenswert?

Bauform B. schrieb:
> Ich hasse es, wenn es so verlockende Angebote gibt, die man dann doch
> nicht nutzen kann.

Was laberst Du? Natürlich kannst du es nutzen, deshalb hab ich's doch 
geschrieben! Du kannst auch das vom Hersteller nutzen, das ist dann halt 
in Assembler, funktioniert aber nach dem exakt selben Prinzip.

von Bauform B. (bauformb)


Lesenswert?

Bernd K. schrieb:
> Diese Vektoren existieren nicht, die werden nie aufgerufen, also kann da
> stehen was will.

Was ist mit dem Software trigger interrupt register (NVIC_STIR)? Darüber 
kann man doch jeden Interrupt per Software triggern? ST meint, alle von 
0 bis (256-16), das heißt, meine Tabelle muss noch doppelt so groß 
werden. Danke für den Tipp.

Bernd K. schrieb:
> Die welche nicht Null sind existieren, könnten also aufgerufen werden,
> also braucht man einen Mechanismus mit dem sich die Anwendung da bei
> Bedarf beim Linken einhaken kann, dieser Mechanismus ist weak.

Genau das mache ich ja auch, nur mit viel weniger Zeilen.
1
   [0 ... (128-16-1)] = crash
trägt überall den Default Handler ein und mit
1
   [PVD_PVM_IRQn] = pvd_isr,   // PVD thru EXTI line detection
2
   [UART0_IRQn] = uart0_isr,
klinkt sich die Anwendung mit ihrem Bedarf da ein.
Als Bonus ist auch bei denen, die nicht existieren, etwas eingetragen.

Leider meint der GCC, dass "array[0 ... n]=foo" auch in C2x noch nicht 
erlaubt ist und außerdem warnt er bei den folgenden Zeilen. Letztere 
Warnung kann ich einfach abschalten aber die erste nervt; vor allem, 
weil extension nichts nützt. Ideal wäre es, wenn 0 statt crash sauber 
funktionieren würde. Deswegen:
>> Ich hasse es, wenn es so verlockende Angebote gibt, die man dann doch
>> nicht nutzen kann.

Bernd K. schrieb:
> Komplettes Beispiel hier:
> https://github.com/prof7bit/bare_metal_stm32f401xe

Irgendwie passt "bare_metal" und der weak-Mechanismus nicht zusammen. 
Solche Konstruktionen braucht man doch nur in IDE, wo möglichst viel vor 
dem Benutzer versteckt werden soll.

: Bearbeitet durch User
von Bernd K. (prof7bit)


Lesenswert?

Bauform B. schrieb:
> Irgendwie passt "bare_metal" und der weak-Mechanismus nicht zusammen.

Du redest wirr. Wie soll man es Deiner Meinung nach sonst machen wenn 
die Vektortabelle im ROM liegt? Die Tabelle ins RAM zu legen und 
kostbares RAM verschwenden auch wenn überhaupt kein zwingender Grund 
vorliegt das im RAM zu haben?

Ich glaub Du hast noch nicht recht verstanden was es mit weak auf sich 
hat und warum man genau das und nichts anderes an dieser Stelle 
verwendet denn genau für solche Sachen wurde das erfunden. Du wirst es 
sicherlich irgendwann verstehen wenn Du Dich noch ein wenig länger damit 
beschäftigst. Google einfach mit dem Stichwort und lies Dir alles durch, 
solange bis es "klick" macht.

> Darüber kann man doch jeden Interrupt per Software triggern?

Dann setz halt dort überall den Default_Handler ein statt 0 wenn Dir 
dabei wohler ist. Macht zwar sonst auch keiner aber schaden kanns auch 
nicht.

: Bearbeitet durch User
von Bernd K. (prof7bit)


Lesenswert?

Bauform B. schrieb:

>> dieser Mechanismus ist weak.
>
> Genau das mache ich ja auch, nur mit viel weniger Zeilen.

Ich seh kein einziges weak in Deinem geposteten Code. Wo soll die 
Anwendung ihre eigenen Handler einhängen? Willst Du jedesmal von Hand 
den Startup anpassen? Das ist doch Käse hoch 3!

von Squierrel (Gast)


Lesenswert?

Aber im Zusammenhang mit "weak" aufpassen, solltest du einen Handler 
über eine separat gebaute Library einführen!
Aber wenn das ganze Thema verstanden ist, ist das auch klar … nur 
manchmal denkt man ja nicht direkt an so Dinge.

von Bauform B. (bauformb)


Lesenswert?

Bernd K. schrieb:
> Bauform B. schrieb:
>> Irgendwie passt "bare_metal" und der weak-Mechanismus nicht zusammen.
>
> Du redest wirr.
Das tut mir leid, es ist nicht böse gemeint.

> Wie soll man es Deiner Meinung nach sonst machen wenn
> die Vektortabelle im ROM liegt?

Genau so wie ich es ganz oben geschrieben habe. Warum sollte das im 
Flash nicht funktionieren? RAM brauchst du doch nur, wenn du ISRs "im 
Flug" austauschen willst. Das kann sehr praktisch sein, keine Frage, 
aber meistens geht es doch ohne RAM.

Bernd K. schrieb:
> Ich glaub Du hast noch nicht recht verstanden was es mit weak auf sich
> hat und warum man genau das und nichts anderes an dieser Stelle
> verwendet denn genau für solche Sachen wurde das erfunden.

Den weak-Mechanismus habe ich schon im letzten Jahrtausend gerne 
benutzt. Warum man ihn hier verwendet ist mir nicht klar, aber es ist 
ja auch Geschmackssache. Es gibt mehrere Möglichkeiten und jede hat ihre 
Vor- und Nachteile. Wenn man die Tabelle im RAM haben will, wird man es 
evt. anders machen.

Bernd K. schrieb:
> Ich seh kein einziges weak in Deinem geposteten Code.

Da soll auch keins drin stehen. Warum soll ich einen spezial-Mechanismus 
nutzen, wenn es auch ohne geht?

> Wo soll die Anwendung ihre eigenen Handler einhängen?
1
[UART0_IRQn] = uart0_isr,
> Willst Du jedesmal von Hand den Startup anpassen?

Nicht den Startup, nur diese eine Tabelle, und nur, wenn eine neue ISR 
dazu kommt.

> Das ist doch Käse hoch 3!
Das ist ein angenehmer Nebeneffekt für jemand, der wenig Fleisch isst ;)

: Bearbeitet durch User
von Bauform B. (bauformb)


Lesenswert?

Squierrel schrieb:
> Aber im Zusammenhang mit "weak" aufpassen, solltest du einen
> Handler
> über eine separat gebaute Library einführen!

Danke, also hatte mein Bauch doch Recht, weak schmeckt uns nicht ;)
Im Ernst, wenn man mit weak aufpassen muss und ohne eine Fehlermeldung 
bekommt -- wer würde da freiwillig weak verwenden?

von Squierrel (Gast)


Lesenswert?

Bauform B. schrieb:
> Im Ernst, wenn man mit weak aufpassen muss und ohne eine Fehlermeldung
> bekommt -- wer würde da freiwillig weak verwenden?

Hier! ;)
Aber im ernst, ein großer Fan bin ich nicht. Es ist öfters einfach die 
beste/praktischste Variante. Bin auch kein Freund von Libs :D …

von Bernd K. (prof7bit)


Lesenswert?

Bauform B. schrieb:
>> Wo soll die Anwendung ihre eigenen Handler einhängen?[UART0_IRQn] = uart0_isr,>
> Willst Du jedesmal von Hand den Startup anpassen?
>
> Nicht den Startup, nur diese eine Tabelle, und nur, wenn eine neue ISR
> dazu kommt.

Naja gut, wenn Du das so umständlich haben willst, dann bitte. Niemand 
hindert Dich daran.

Aber Du hast ja explizit gefragt wie "man" das macht. Und "man" nimmt 
halt normalerweise den weak-Mechanismus der ja genau wie gemacht für 
diese Sache ist, sei es in Assembler oder in C, und es keinerlei Sinn 
oder Vorteil ergäbe darauf zu verzichten, im Gegenteil, ohne weak wirds 
auf jeden Fall unhandlicher, egal wie Du es drehst oder wendest.

von Nop (Gast)


Lesenswert?

Ich nehme dafür auch kein "weak", sondern kopiere N mal den 
Default-Handler da hart hin (N wie im zugehörigen Chip-Manual 
beschrieben), gruppiere die hübsch in Zehnergruppen und mache Kommentare 
dazu, welche Zehnergruppe gerade beginnt.

Bei Bedarf trage ich da an der richtigen Stelle den Interrupt ein, den 
das Manual dort vorsieht. Die richtige Dekade sehe ich am Kommentar, und 
zählen bis 10 bekomme ich gerade noch so hin.

Dann sehe ich wenigstens schon am Linker-Ergebnis, ob er den richtigen 
Handler da jetzt einträgt oder nicht. Außerdem sehe ich direkt an der 
Vektortabelle, was für Interrupts überhaupt genutzt werden.

von Johannes S. (Gast)


Lesenswert?

nur wenn der IRQ Handler in einem C++ Modul liegt und man das C Linkage 
vergißt, kann man lange am Laufzeitfehler suchen.

von Bauform B. (bauformb)


Lesenswert?

Bernd K. schrieb:
> Aber Du hast ja explizit gefragt wie "man" das macht. Und "man" nimmt
> halt normalerweise den weak-Mechanismus der ja genau wie gemacht für
> diese Sache ist

Ja, stimmt. Natürlich hatte ich gehofft, dass "man" das anders macht. 
Aber mit den Nullen in deiner Tabelle hast du den entscheidenden Tipp 
geliefert. Man muss keinen Default Handler eintragen, 0 tut es auch. Da 
0 automatisch eingetragen wird, reicht es, wenn man nur die benutzten 
ISRs hinschreibt.

Nop schrieb:
> Ich nehme dafür auch kein "weak", sondern kopiere N mal den
> Default-Handler da hart hin (...)
> Bei Bedarf trage ich da an der richtigen Stelle den Interrupt ein, den
> das Manual dort vorsieht.

Die richtige Stelle sagen einem die IRQn_enum, z.B. SPI1_IRQn. Das Array 
der vector_table kann man dann einfach mit
1
  [SPI1_IRQn] = spi_isr,
 intialisieren. Nix abzählen, nur genau so viele Zeilen wie nötig, keine 
magischen Zahlen, keine Mecker vom GCC, bei allen unbenutzten Interrupts 
steht automatisch die 0 drin. Das funktioniert so, als ob der Usage 
Fault Handler eingetragen wäre. Welcher Eintrag gefehlt hat, steht 
hinterher im IPSR.
1
Aus dem ARM v7-M Architecture ® Reference Manual, ARM DDI0403E.d
2
3
B1.5.3 The vector table
4
  All [other] entries must have bit[0] set to 1, because this bit
5
  defines the EPSR.T bit on exception entry.
6
  On exception entry, if bit[0] of the associated vector table entry
7
  is set to 0, execution of the first instruction causes an INVSTATE
8
  UsageFault, see The special-purpose Program Status Registers, xPSR
9
10
B1.5.6 Exception entry behavior
11
  (...)
12
  tmp = MemA[VectorTable+4*ExceptionNumber,4];
13
  BranchTo(tmp AND 0xFFFFFFFE<31:0>);
14
  tbit = tmp<0>;
15
  CurrentMode = Mode_Handler;
16
  APSR = bits(32) UNKNOWN;
17
  IPSR<8:0> = ExceptionNumber<8:0>;
18
  EPSR.T = tbit;
19
  (...)
20
21
B1.3.3 Execution state
22
  Setting EPSR.T to zero in an ARMv7-M processor causes a fault
23
  when the next instruction executes, because in this state all
24
  instructions are UNDEFINED.
Ich hätte gern noch den Pseudo-Code für die eigentliche 
Befehlsausführung gefunden, zwecks wann das T-Bit abgefragt wird. Aber 
ich glaube, es ist auch so überzeugend. Immerhin wird der "Befehl" auf 
Adresse 0 (nicht) ausgeführt, damit fallen viele andere 
Fehlermöglichkeiten weg. Und selbst wenn die Exception im Hard Fault 
Handler endet, kann man noch gut debuggen.

Rein theoretisch könnte es auch mit einem Lockup enden. Aber bis die 
Dekodierung von dem "Befehl" beginnt ist alles noch völlig normal und 
ohne Tricks. Also, was könnte schief gehen?

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.