Forum: Mikrocontroller und Digitale Elektronik STM32F446RE - Timer 4 PB7 geht nicht


von Walter T. (nicolas)


Angehängte Dateien:

Lesenswert?

Hallo zusamme,

ich brauche die Hilfe eines weiteren Augenpaars. Ich habe hier ein 
Nucleo64 mit einem STM32F446RE. Auf PB5 mit Timer TIM3 kann ich eine PWM 
ausgeben, auf PB7 mit TIM4 nicht.

Toggle ich PB7 über das GPIOx->ODR - Register, erhalte ich ein sauberes 
Rechtecksignal. Der MCU-Pin hängt also am richtigen Pin der Stiftleiste, 
und es ist auch keine andere Hardwarekomponente auf dem Eval-Board, die 
mein Anliegen verhindert.

Zum Testen habe ich die Initialisierung der PWM fast komplett nach vorn 
gezogen. Der Quelltext ist angehängt. Im Beitrag wird er zu sehr 
auseinandergezogen.

Hat das globale Define BUZZER_PWM den Wert buzzer_STM32F4XX_TIM3_PB5, 
bekomme ich ein schönes Rechtecksignal an PB5. Hat es dagegen den Wert 
buzzer_STM32F4XX_TIM4_PB7, ist nichts an PB7 vorhanden.

TIM3 und TIM4 sind beide an APB1 und beide an GPIOB. Bei beiden ist es 
die alternative Pin-Funktion AF2. Bei beiden ist es CH2 (nicht, dass das 
wichtig wäre - es werden eh alle beschrieben).

Und jetzt bin ich an dem Punkt angekommen, an dem zwei Augen nicht mehr 
ausreichen. Siehst Du mehr?

Nachtrag: Ich habe die Ursache gefunden, verstehe sie aber nicht.

In Headern ist definiert:
1
    #define BUZZER_PWM   buzzer_STM32F4XX_TIM4_PB7
2
3
    /** Summer: Auswahl Ports und Pins */
4
    enum buzzertype_e
5
    {
6
        buzzer_STM32F4XX_TIM3_PB5,
7
        buzzer_STM32F4XX_TIM4_PB7,
8
    };
(In welcher Reihenfolge die beiden "includiert" werden, muss ich noch 
schauen.)

In der Auswahl
1
  #if( BUZZER_PWM == buzzer_STM32F4XX_TIM3_PB5 )
2
    [...]
3
    TIMx = TIM3;
4
    [...]
5
6
  #elif( BUZZER_PWM == buzzer_STM32F4XX_TIM4_PB7 )
7
    [...]
8
    TIMx = TIM4;
9
    [...]
10
  #else
11
    #error "Invalid config for buzzer pwm"
12
  #endif
wird trotzdem TIMx die Adresse von TIM3 zugeordnet - also der falsche 
Zweig durchlaufen.

Ändere ich die Präprozessorweiche in ein switch-case, funktioniert es 
wie erwartet.

: Bearbeitet durch User
von Mark B. (markbrandis)


Lesenswert?

Der Code ist logisch falsch, da in der Präprozessor-Direktive etwas 
vorausgesetzt wird, das aber erst dem Compiler bekannt ist. Der kommt 
bekanntlich erst nach dem Präprozessor dran.

von Walter Tarpan (Gast) (Gast)


Lesenswert?

Die höchste Form der Expertise ist es, im Nachhinein alles vorher 
gewusst zu haben.

von Mark B. (markbrandis)


Lesenswert?

Je nun - die Idee, enums mit #ifdefs zu vermischen ist schon etwas 
skurril. Kann mich nicht erinnern, das so in der Form schon mal gesehen 
zu haben. Und ich habe viel fragwürdigen Code gesehen in den letzten 
zehn, fünfzehn Jahren. ;-)

Beitrag #6700844 wurde von einem Moderator gelöscht.
von Walter T. (nicolas)


Lesenswert?

Man sieht bei den unteren Funktionen die Auswahl einer benannten 
Variante mit switch/case. Da sind enums für die Benennung erst einmal 
"natürlich".

Oben in der init()-Funktion ist switch/case so lange möglich, wie der 
Teil dazwischen für alle enum-Werte kompiliert. Für die beiden benannten 
Werte ist das kein Problem. Bestünde das enum aus einem Wert mehr, z.B.
1
    enum buzzertype_e
2
    {
3
        buzzer_STM32F10x_TIM3_PB5,
4
        buzzer_STM32F4XX_TIM3_PB5,
5
        buzzer_STM32F4XX_TIM4_PB7,
6
    };
müsste ich innerhalb jedes "case" noch zusätzlich im Präprozessor die 
MCU abfragen.

Deswegen behaupte ich: Skurril ist es nicht. Es funktioniert nur nicht 
(und die Ursache ist die interne Funktionsweise des Compilers). Würde es 
funktionieren, wäre es sinnvoll.

: Bearbeitet durch User
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.