Timer Finder Opta (STM32H747XI)

OP #7730242
Lesenswert?

Hallo, ich versuche auf einer Finder Opta einen Timer zu programmieren.Prozessor der Steuerung ist ein STM32H747XI.

Umgebung ist Arduino.

Ich bin ziemlicher Anfaenger und fuer jede Hilfe dankbar.

  1. Problem. Wieso brauch ich einen Delay bevor ich was in das ARR bzw. PSC Register schreibe.

  2. Problem. Wenn ich den Interrupt fuer den Timer aktiviere (Zeile39) geht das Programm in die Wueste.Ich bin nicht sicher ob der Name fuer den Interrupt Handler korrekt ist. Ich bin auch nicht sicher ob ich den irgendwie als ISR Kennzeichnen muss. Wie ich das verstehe wird der im Startup in der Interrupt Vektor Tabelle definiert. Wie ist die Verbinung von meinem Handler zur Tabelle?

Ohne Interrupt laeuft das Programm. Die While schleife wird durchlaufen, Micros sind etwa 1 Million. Im Anschluss geht die LED aus.

1
#include "stm32h747xx.h"
2
#include "timer.h"
3

4
void TIM14_IRQHandler(void) {
5
  if (TIM14->SR & TIM_SR_UIF) {
6
    digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
7
    TIM14->SR &= ~(TIM_SR_UIF);
8
  }
9
}
10

11
//---------------------------------------------------------
12
void setup()
13
{
14
// configure pin in output mode
15
  pinMode(LED_BUILTIN,  OUTPUT);
16
  pinMode(LED_USER, OUTPUT);
17
  digitalWrite(LED_USER, HIGH);  // laeuft
18
  
19
  Serial.begin(115200);
20
  while (!Serial); // warte bis terminal offen
21
  delay(100);
22
  Serial.print(F("\nStart "));
23

24
  digitalWrite(LED_BUILTIN, LOW);  
25
//---------------------------------------------------------
26
  RCC->APB1LENR |= RCC_APB1LENR_TIM14EN;        // enable timer14 clock
27
  TIM14->CR1 &= ~(TIM_CR1_CEN);                 // Timercount disable
28
  RCC->APB1LRSTR |= (RCC_APB1LRSTR_TIM14RST);   // reset timerblock14
29
  RCC->APB1LRSTR &= ~(RCC_APB1LRSTR_TIM14RST);
30
delay(10);
31
  TIM14->ARR = 10000;                            // 10000 * 0.1 ms = 1sec
32
  TIM14->PSC = 19999;                           // prescale -> frequenz =16000000 / 16000 = 1KHz  so ist es 0.1ms??
33
  Serial.println("--0");
34
  TIM14->EGR |= TIM_EGR_UG;                     // update psc und arr
35
  TIM14->DIER |= TIM_DIER_UIE;                  // enable timer irq
36
  Serial.println("--1");
37
  TIM14->SR &= ~TIM_SR_UIF;                     // clear interrupt flag
38
  Serial.println("--2");
39
//  NVIC_EnableIRQ(TIM14_IRQn);                   // Enable the NVIC interrupt for TIM14
40
  Serial.println("--3");
41
  TIM14->CR1 |= TIM_CR1_CEN;                    // enable timer
42

43
Serial.println(TIM14->PSC);
44
Serial.println(TIM14->ARR);
45

46
  uint32_t t1=0,t2=0;
47

48
  while(t2 < 20){
49
    while ((TIM14->SR & TIM_SR_UIF) == 0);
50
    TIM14->SR &= ~TIM_SR_UIF;
51
    Serial.println(micros() - t1);
52
    t1=micros();
53
    t2++;
54
  }
55
  digitalWrite(LED_USER, LOW);
56
}
57

58
void loop()
59
{
60

61
}
Persönliche Seite #7730261
Lesenswert?

Holger schrieb:

Wieso brauch ich einen Delay bevor ich was in das ARR bzw. PSC Register schreibe.

Nachdem du den Timer im RCC aktiviert hast, dauert es ein paar Takte bis sich das auswirkt, weil die CPU schneller als der Bus ist. Füge dazwischen ein

1
__DSB();
2
__ISB();

ein, damit die CPU die Vervollständigung des Schreibzugriffs abwartet.

Holger schrieb:

ch bin nicht sicher ob der Name fuer den Interrupt Handler korrekt ist

Der korrekte Name lautet "TIM8_TRG_COM_TIM14_IRQHandler". Ist im Startup Code definiert:

https://github.com/STMicroelectronics/cmsis_device_h7/blob/13ba9da797a30e1563a8795f974425fb26dd0457/Source/Templates/gcc/startup_stm32h747xx.s#L191

Der Name kommt daher, dass sich manchmal mehrere Peripherals den selben Interrupt teilen. Im Handler musst du dann prüfen, ob der gewünschte Interrupt aufgetreten ist.

Schreibe den Interrupt besser so: [C]void TIM14_IRQHandler(void) { if (TIM14->SR & TIM_SR_UIF) { TIM14->SR = ~(TIM_SR_UIF);

1
digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));

} }[/c]

Man sollte das UIF Flag so schnell wie möglich löschen, weil auch dieser Zugriff etwas dauert; macht man das am Ende der ISR, kann die ISR eventuell direkt noch einmal auslösen. Außerdem ist kein Read-Modify-Write ( "&=" ) nötig, es reicht einfach der direkte Schreibzugriff, weil die Bits im Register als "rc_w0" definiert sind (1 schreiben = keine Wirkung, 0 schreiben = löschen).

OP #7730271
Lesenswert?

Hallo, danke fuer die schnelle Antwort.

Das mit dem Delay habe ich mir so halb gedacht.

Den Handler habe ich jetzt geaendert zu

1
void TIM8_TRG_COM_TIM14_IRQHandler(void) {
2
  if (TIM14->SR & TIM_SR_UIF) {
3
    TIM14->SR = ~(TIM_SR_UIF);
4
    digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
5
  }
6
}

aber das Programm haengt immer noch. Startup werde ich mir jetzt anschauen.

Ich verstehe den Zusammenhang von der Vektortabelle und meinem Handler nicht. Zu DOS Zeiten war in der Vektortabelle direkt die Einsprungadresse des Handlers

#7730283
Lesenswert?

Der startup code steckt kompiliert in einer library drin, den kannst du nicht einfach ersetzen oder verändern. Es wird auch nicht der aus dem CMSIS Beispiel verwendet, sondern der steckt im ArduinoCore-mbed drin.

Wichtig ist aber den Handler als 'extern "C"' zu definieren, jetzt wird der als C++ Unit übersetzt und durch das Name mangeling passt der tatsächliche Funktionsname nicht zu der Definition im Startup Code.

OP #7730287
Lesenswert?

Herzlichen Dank

und so

1
extern "C"{
2
  void TIM8_TRG_COM_TIM14_IRQHandler(void) {
3

4
    if (TIM14->SR & TIM_SR_UIF) {
5
      TIM14->SR = ~(TIM_SR_UIF);
6
      digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
7
    }
8
  }
9
}

funktioniert das jetzt einwandfrei.

Kann ich mir morgen mal das extern "C" zu Gemuete ziehen

Danke Holger

#7730290
Lesenswert?

C++ name mangeling ist das Stichwort. In C++ sind ja mehre Signaturen für Funktionen mit gleichen Namen erlaubt, z.B.

1
void foo(int a);
2
void foo(float a);

Dadurch würde der Linker bei C meckern, in C++ werden die Argumente in den Funktionsnamen reinkodiert und damit sind die wieder eindeutig. Mit 'extern "C"' verhindert man dieses name mangeling um es C kompatibel zu machen.

Aber auch obwohl ich das weiß habe ich an dem blöden fehlenden extern "C" auch schon lange den Fehler gesucht :) Und deshalb ich das 'weak' nicht besonders, der Linker kann solche Fehler nicht erkennen weil er ja nicht weiß ob die Funktion ersetzt werden soll oder nicht. Aber es ist eben ein Mittel um eine generisches Modul zu haben wo die Funktion beim Linken ersetzt werden kann.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren