Forum: Mikrocontroller und Digitale Elektronik STM32F4 Discovery Board - PWM Signal einlesen


von Felix K. (felix133711)


Lesenswert?

Hallo,

ich versuche ein PWM-Signal mithilfe des STM32 auszuwerten. Dazu lege 
ich am PIN F0 (EXTI0-line) ein 1000us Signal an. Ich nutze dabei diesen 
PIN als Interrupt Eingang (RISING EDGE). Sobald der Interrupt ausgelöst 
wird springt er in den "void EXTI0_IRQHandler(void)". In dieser 
Interrupt Routine werte ich dabei die Flanke aus und schalte dann direkt 
den Interrupt "um" (von RISING auf FALLING und auch wieder umgekehrt). 
Ich setze vorher den TIM10 zurück (0) und lese beim nächsten Aufruf 
seinen Wert aus und speichere diesen direkt in ein Array (rx[7]).

Später soll damit dann ein PPM Signal von einem Receiver ausgewertet 
werden. (Die gleiche Funktionalität habe ich bereits in einem Atmega328p 
implementiert und dort funktioniert es super und wirklich sehr genau. 
Ich verzichte dabei bewusst auf die Funktionalität des "INPUT CAPTURE", 
da damit kein Summensignal verarbeitet werden kann.

Kommen wir nun zu meinem eigentlichen Problem:
Das angelegte 1000us Signal ist sehr genau. Nun erhalte ich in meinem 
Array rx[0] extrem schwankende Werte:

(Auszug aus der Console)
7895
9448
9448
7527
7527
7617
7617
7579
7579
7919

Dazu ist zu sagen, dass mein TIM10 mit einer Clock von 84Mhz betrieben 
wird und mit einem Prescaler von 9 auf 8.4Mhz runtertrimmt wird. Damit 
sollte ich bei 1000us auf einen Zählwert vom TIM10 von ca. 8400 kommen.

Takt: 168MHZ mit HSE = 8Mhz.
Board: STM32F429ZITx Disc1
Entwicklungsumgebung: Eclipse
Debugger: openOCD
Erstellt mit: CubeMX (Initialisierung)

Jetzt wäre vielleicht noch der vollständige Code interresant ;-)

https://codeshare.io/7m20E

Ich bin mittlerweile echt ratlos, woran es liegen könnte. Könnte mir da 
jemand bei dieser Problematik weiterhelfen?

Habt jetzt schon einmal vielen Dank!

von stm32lover (Gast)


Lesenswert?

>aus und schalte dann direkt den Interrupt "um" (von RISING auf FALLING und auch 
>wieder umgekehrt).

>Die gleiche Funktionalität habe ich bereits in einem Atmega328p
>implementiert und dort funktioniert es super

Der STM32 kann das viel eleganter. Da brauchst Du nix umzuschalten.

Hier ein Beispiel, wie ein RC Summensignal ausgewertet wird. Das 
Resultat aller Kanäle steht dann in rc_in_sigs[]:
1
void TIM1_CC_IRQHandler(void)
2
{
3
  /* Clear TIM1 Capture compare interrupt pending bit */
4
  TIM_ClearITPendingBit(TIM1, TIM_IT_CC1);
5
  periode = TIM_GetCapture1(TIM1);
6
  duty = TIM_GetCapture2(TIM1);
7
  rc_captured(duty, periode);
8
 }

1
/**
2
 * IRQ callback function that decodes the duty and the
3
 * periode and sort it into the channel number
4
 */
5
void rc_captured(uint16_t duty, uint16_t periode) {
6
7
  // If the periode is >600 (3ms), it is a new sequence
8
  if (periode > 600 ) {
9
    rc_in_ix = 0;
10
  }
11
  // Put the value into the next field of the array
12
  else if (rc_in_ix < 6) {
13
    rc_in_sigs[rc_in_ix] = periode;
14
    rc_in_ix++;
15
  }
16
17
}

Quelle:
https://github.com/gerdb/bumblecopter/blob/master/bumblecopter/src/it.c
https://github.com/gerdb/bumblecopter/blob/master/bumblecopter/src/rc.c

von Felix K. (felix133711)


Lesenswert?

Vielen Dank für den Hinweis :-)
Werde ich direkt mal probieren.
Aber rein zum Verständnis, Woran könnte die von mir beschriebene 
Ungenauigkeit liegen? Wird vielleicht der Interrupt selbst zu oft 
unterbrochen und damit der Zählwert schwankt?

Gruß,
Felix

von stm32lover (Gast)


Lesenswert?

>Aber rein zum Verständnis, Woran könnte die von mir beschriebene
>Ungenauigkeit liegen?

>Ich setze vorher den TIM10 zurück (0) und lese beim nächsten Aufruf
>seinen Wert aus und speichere diesen direkt in ein Array (rx[7]).

Man liest nicht den Timer aus, sondern immder das InputCapture Register. 
Das macht man auch beim ATMega so.

von Felix K. (felix133711)


Lesenswert?

Ich bins nochmal:

ich habe mir direkt mal die PWM INPUT MODE Geschichte angeschaut...nette 
Funktionalität. Dein Github Beispiel erscheint mir allerdings ein wenig 
verwirrend. Er initialisiert den Timer nicht so, wie es im Datenblatt 
angegeben ist:

http://www.st.com/content/ccc/resource/technical/document/reference_manual/3d/6d/5a/66/b4/99/40/d4/DM00031020.pdf/files/DM00031020.pdf/jcr:content/translations/en.DM00031020.pdf

"17.3.7 PWM input mode"

Ich habe das ganze jetzt mal versucht umzusetzen, leider komme ich jetzt 
nicht mehr wirklich weiter. Eigentlich arbeite ich mit der HAL-Lib, dort 
finde ich die Einstellungen allerdings sehr wirr. Nun habe ich es mal 
mit direkten Registerzugriffen probiert (Abfolge laut Datenblatt):
1
TIM1->CCMR1 |= (1 << 1); // select TI1 (CC1S = 01 [1,0])
2
TIM1->CCER   &= ~((1 << 1) | (1 << 3)); // select active polarity => rising edge (CC1S = 01 [1,0])
3
4
TIM1->CCMR1 |= (1 << 9); // select TI1 (CC2S = 10 [9,8])
5
TIM1->CCER   |= (1 << 5) | (1 << 7);
6
7
TIM1->SMCR   &= ~(1 << 5); // (TS = 101 6:4)
8
TIM1->SMCR   |= (1 << 6) | (1 << 4); // (TS = 101 6:4)
9
10
TIM1->SMCR  &= ~((1 << 0) | (1 << 1));
11
TIM1->SMCR  |= (1 << 2);
12
13
TIM1->CCER  = 0x07;

Was müsste nun noch getan werden, damit ich letztendlich meine Werte aus 
TIM1->CCR1 (Frequenz), TIM1->CCR2 (Duty Cycle) auslesen kann.
Was auch sehr merkwürdig ist:

wenn ich direkt ein Register beschreibe und mir direkt danach den Inhalt 
anzeigen lassen möchte, ist dieses "0"
1
TIM1->CCER  = 0x07;
2
trace_printf("Inhalt TIM1_CCER: %d", TIM1->CCER);

Mache ich hier einen grundsätzlichen Fehler?


Vielen Dank im Voraus!

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.