Forum: Mikrocontroller und Digitale Elektronik Wie mit STM32F0 DMX Empfangen


von Peter (Gast)


Lesenswert?

Hallo,
ich versuche gerade einen DMX Empfänger mit einem STM32f072 zu bauen.

Hatte das zuvor mit einem AVR gemacht und hatte eigentlich nicht mit 
Problemen gerechnet. So kann man sich irren.

Der AVR reagiert auf Overflow, Frameerror und normalem Empfang.
Also das normale vorgehen beim DMX Empfang.

Jetzt wollte ich genau diese Interrupts auch beim STM einschalten.
Aber nach den ersten INT ist der Tot und macht nichts mehr.

Im Netz stolpere ich immer über 2 Projekte die aber total anders 
arbeiten und absolut ungeeignet sind.

Hat jemand das schon mal gemacht?
Gibt es beispiele die so arbeiten?

MFG, Peter

von Jim M. (turboj)


Lesenswert?

Peter schrieb:
> Jetzt wollte ich genau diese Interrupts auch beim STM einschalten.
> Aber nach den ersten INT ist der Tot und macht nichts mehr.

Wenn man die entsprechenden Flags nicht löscht, wird der Interrupt 
Handler endlos zyklisch aufgerufren. Anders als bei AVR findet dann auch 
keine Codeausführung in main() statt.

Übrigens sollte man sich einen eigenen Handler für Hardfault schreiben,
sonst sucht man u.U. endlos nach Fehlern. Die Cortex M0 sind z.B. 
empfindlich bei Alingment Problemen, die man auf 8-Bittern so gar nicht 
kennt.

Anders als AVR kann man Cortex M IMHO ziemlich gut debuggen...

von Peter (Gast)


Lesenswert?

Der Serial Int ist Tot nicht der Prozessor, Main läuft noch ohne 
Probleme.

Die Flags lösche ich, habe es auch schon mal ohne löschen probiert, 
gleiche Resultat.
In einem Anderen Projekt habe ich mit der SIO schon gearbeitet, aber da 
ohne die Fehlerbehandlung.

Ich packe nachher mal die paar Testzeilen hier rein, habe das Projekt 
gerade nicht dabei.

Den Umgang mit den ARM Prozessoren kenne ich inzwischen recht gut.
Aber das man den viel besser debuggen kann konnte ich bis jetzt nicht 
merken.
Weder ein M0, M4 noch ein M7 war da besonders besser als ein AVR.

MfG Peter

von Falk B. (falk)


Lesenswert?

@  Peter (Gast)

>Der Serial Int ist Tot nicht der Prozessor, Main läuft noch ohne
>Probleme.

Dann hast du einen Bug in deiner ISR-Behandlung. Wo auch immer.

>Den Umgang mit den ARM Prozessoren kenne ich inzwischen recht gut.

Aber kriegst nicht mal einen einfachen UART mit Interrupt zum laufen?
Noch einer, der glaubt zu wissen.

>Aber das man den viel besser debuggen kann konnte ich bis jetzt nicht
>merken.
>Weder ein M0, M4 noch ein M7 war da besonders besser als ein AVR.

Man muss schon die Methodik kennen und richtig anwenden. printf() ist es 
nicht.

von Peter (Gast)


Lesenswert?

Ich glaube Printf ist kein geeignetes Mittel um ein Programm zu 
debuggen, da ist ein ICE doch um klassen besser.
Besonders beim ARM werden einem die Dinger ja für wenig Geld nach 
geworfen.


Eine normale SIO bekomme ich hin, nur hier ist eine Eigenart der SIO bei 
den Fehler Quellen gefragt und da klappt halt was nicht.

von Falk B. (falk)


Lesenswert?

@ Peter (Gast)

>Ich glaube Printf ist kein geeignetes Mittel um ein Programm zu
>debuggen, da ist ein ICE doch um klassen besser.
>Besonders beim ARM werden einem die Dinger ja für wenig Geld nach
>geworfen.

Und wie kommst du dann zu der Aussage, dass ARM nicht besser zu debuggen 
ist als ein AVR?

von Peter (Gast)


Lesenswert?

Weil es für den AVR auch solche Tools gibt und die sind nicht besser 
oder schlechter.
Aber lass es einfach, ist nicht das Thema hier!

Wenn Du was über DMX mit dem STM32f072 sagen kannst dann bitte.

Peter

von Altes Lötzinn stinkt (Gast)


Lesenswert?

Hatte das gleiche Problem beim STM32F072
Ich vermute mal Du nutzt die HAL Lib?
Aber warten wir mal ab bis Du Deinen Code postest.

von Peter (Gast)


Lesenswert?

So ich habe gestern Abend noch etwas Probiert und jetzt geht es auf 
einmal.
Bin aber noch nicht so sicher ob das alles so richtig ist, ich meine den 
Empfang nicht was mit den Daten passiert.

Hier der Code (Auszug):
1
void USART1_IRQHandler(void)
2
{
3
   uint16_t rx;
4
5
   if (USART_GetITStatus(USART1, USART_IT_ORE) != RESET) // Data Overrun?
6
   {
7
      rx = USART_ReceiveData(USART1); // Lese das Zeichen
8
      USART_ClearITPendingBit(USART1,USART_IT_ORE);
9
      DmxInStatus = IN_BREAK; // Warte auf Reset (BREAK)
10
   }
11
   else
12
   {
13
      if (USART_GetITStatus(USART1, USART_IT_FE) != RESET) //BREAK or FramingError?
14
      {
15
         rx = USART_ReceiveData(USART1); // Lese das Zeichen
16
         USART_ClearITPendingBit(USART1,USART_IT_FE);
17
         if (rx == 0)
18
         {
19
            DmxInStatus = IN_STARTB; // FE WAS a BREAK -> Warte auf Start Byte!
20
         } else {
21
            DmxInStatus = IN_BREAK; // Warte einfach auf Reset (BREAK) 
22
         }
23
      }
24
      else
25
      {
26
         if (USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) // Empfangsinterrupt?
27
         {
28
            rx = USART_ReceiveData(USART1); // Lese das Zeichen
29
            switch (DmxInStatus)
30
            {
31
            case IN_STARTB:
32
               if (rx == 0)
33
               {
34
                  DmxInStatus = IN_DMX_DATA; // gehe in den Daten einlese Zustand
35
                  DmxInDataCounter = 0; // Reset vom Daten Counter
36
               } else {
37
                  DmxInStatus = IN_BREAK; // Warte einfach auf Reset                                    
38
               }
39
               break;
40
            case IN_DMX_DATA: // Daten ablegen
41
               DmxPc_In_DmxUniverse[DmxInDataCounter] = rx;
42
43
               DmxInDataCounter++; // Datum weiter zaehlen
44
               if (DmxInDataCounter >= sizeof (DmxPc_In_DmxUniverse))
45
               {
46
                  DmxInStatus = IN_BREAK; // ALL CHANNELS RECEIVED
47
               }
48
               break;
49
            default :
50
               break;
51
            }
52
         }
53
         else
54
         {
55
            USART_ClearITPendingBit(USART1,USART_IT_ERR);
56
            USART_ClearITPendingBit(USART1,USART_IT_FE);
57
            USART_ClearITPendingBit(USART1,USART_IT_IDLE);
58
            USART_ClearITPendingBit(USART1,USART_IT_ORE);
59
         }
60
      }
61
   }
62
}
63
64
65
//  DMX IN auf UART 1   Pin A9 & A10 (30&31)
66
void Uart1_Init(void)
67
{
68
   USART_InitTypeDef USART_InitStructure;
69
   GPIO_InitTypeDef GPIO_InitStructure;
70
   NVIC_InitTypeDef NVIC_InitStructure;
71
72
   RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);
73
   RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);
74
75
   GPIO_PinAFConfig(GPIOA, GPIO_PinSource9, GPIO_AF_1);
76
   GPIO_PinAFConfig(GPIOA, GPIO_PinSource10, GPIO_AF_1);
77
78
   /* Configure USART1 pins:  Rx and Tx ----------------------------*/
79
   GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_9 | GPIO_Pin_10;
80
   GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
81
   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
82
   GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
83
   GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
84
   GPIO_Init(GPIOA, &GPIO_InitStructure);
85
86
   /* Enable USART1 IRQ */
87
   NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
88
   NVIC_InitStructure.NVIC_IRQChannelPriority = 0;
89
   NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
90
   NVIC_Init(&NVIC_InitStructure);
91
92
   USART_InitStructure.USART_BaudRate = 250000;
93
   USART_InitStructure.USART_WordLength = USART_WordLength_8b;
94
   USART_InitStructure.USART_StopBits = USART_StopBits_2;
95
   USART_InitStructure.USART_Parity = USART_Parity_No;
96
   USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
97
   USART_InitStructure.USART_Mode = USART_Mode_Rx;
98
   USART_Init(USART1, &USART_InitStructure);
99
100
   USART_Cmd(USART1,ENABLE);
101
   USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); // Enable always
102
   USART_ITConfig(USART1, USART_IT_ERR, ENABLE); // Enable always
103
}


Wer sich damit auskennt könnte mir mal sagen was ich noch falsch mache,
oder was man besser anders machen sollte.

Peter

von Peter (Gast)


Lesenswert?

Schade das niemand was zum Code zu sagen hat.

Peter

von Marcus H. (Firma: www.harerod.de) (lungfish) Benutzerseite


Lesenswert?

Man fragt sich halt, was sich seit Deiner ersten Anfrage geändert hat. 
:)
Andere Optimierungsstufe? Welches EWU?

Bei ISR Funktionen schau ich mir gerne mal das Timing an (Latenzzeit, 
Verweildauer).
Falls Debug-Pins zur Verfügung stehen, mit dem Oszi, ansonsten mit den 
eingebauten Zählern in der MCU.


Die Interruptlatenzzeit ist bei Cortex Mx erstaunlich groß, dafür 
sichert Dir die Kiste aber schon den Kontext weg.
Auf F030 reden wir hier über mehr als 500ns, bevor Deine ISR losrennt.
Du hast maximal 44us (11/Baudrate) für Deine ISR. Sieht gut aus.

Zum Thema Effizienz:
- Standardbibliotheken (gut zum Einstieg, lahmes Speicherschwein)
- direkter Zugriff auf die Peripherieregister (da weiß man hat, schon 
recht kompakt)
- Assembler (da war es wieder, das böse Wort)


Konkrete Vorschläge:

- die 50MHz Portpins kannst Du auch noch runterbremsen

- das hier
            USART_ClearITPendingBit(USART1,USART_IT_ERR);
            USART_ClearITPendingBit(USART1,USART_IT_FE);
            USART_ClearITPendingBit(USART1,USART_IT_IDLE);
            USART_ClearITPendingBit(USART1,USART_IT_ORE);
   wird eine Zeile, einfach Bits verodern. Tipp öfter mal F3 auf den 
Funktionsnamen und Defines und schau Dir an, wie die Dinger beschrieben 
werden. Nebendran hast Du die RM0360 offen.

- vor dem Enablen von Interrupts, DMA-Requests etc. alle dazugehörigen 
Flags löschen. Der Mechanismus ist bei STM32 manchmal nicht sofort zu 
sehen, ggf. in den Foren suchen. Lösch mal einen pending 
Timer-DMA-Request. ;)

- Hardfault-Handler wurde schon erwähnt -> wenn Du da einen Breakpoint 
reinsetzt, siehst Du gleich, wenn und was schiefgelaufen ist. Komplett 
mit Call-History.

- wenn Dir noch was fischig vorkommt: Breakpoints setzen und die 
Peripherieregister gegen die RM0360 vergleichen, Bit für Bit. Wenn's mit 
den Standardbibliotheken nicht so wird, wie Du es haben willst, dann 
setz die Register von Hand.

von Peter (Gast)


Lesenswert?

Danke für Deine umfangreiche und zutreffende gute Antwort.
Leider geht es hier aber nicht um Timming, Debuggen oder wie arbeitet 
man.

Klar kann man später die CMSIS Sachen noch mal ersetzten, mache ich 
normalerweise wenn es läuft auch. Lasse dann als Kommentar die CMSIS 
Zeile immer drin.
Das macht immer Sinn wenn man mal den Prozessor wechselt, was mit Teilen 
meiner Software auch oft passiert.
Heute ist der Code in einem M0 und vielleicht in 8 Wochen in einem M4 
oder M7, wer kann das heute schon sagen.

Geändert haben sich nur 3 Sachen:
- Die Spannung ist nun im DMX Bereich sauberer (war 4,3V sollte 5,0V 
sein)
- Ich fische mit USART_ReceiveData(USART1) bei den Overrun die UART ab.
- Ich habe alles auf if .. else umgebaut und frage somit nicht mehr 
alles ab.

Also an den CMSIS Kram hat es nicht gelegen.
Aber ist das jetzt auch alles so richtig?
Was muss man technisch verbessern (ausser Timming)?

Peter

von Marcus H. (Firma: www.harerod.de) (lungfish) Benutzerseite


Lesenswert?

Peter schrieb:
> Danke für Deine umfangreiche und zutreffende gute Antwort.
Danke für die Blumen.

> Leider geht es hier aber nicht um Timming, Debuggen oder wie arbeitet
> man.
Ich dachte, dass es genau darum ging. Du bist mit dem Ergebnis 
unzufrieden und wolltest Kommentare zum Code. Solange niemand außer Dir 
hat die passende Hardware, Deinen gesamten Code und Zeit hat, bleibt Dir 
nur die RM0360.

von Peter (Gast)


Lesenswert?

In diesem Fall verteile ich gerne Blumen, weil es einfach gut ist, was 
Du geschrieben hast. Perfekt für einen Programmieranfänger.
Ich bin aber schon lange im Geschäft, nur die ganzen STM32 Prozessoren 
bringen mich regelmäßig zum verzweifeln. Entweder ich werde Alt oder STM 
sollte sich mal überlegen warum man regelmäßig total unlogische Abläufe 
einhalten muss und diese dann nicht mal sauber beschreibt.

Damit hast Du wiedermal recht, ich habe das gesamte Projekt und noch 
kein anderer. Wird kein Produkt was ich verkaufe! Das ist ein Projekt 
innerhalb eines Vereins und wird später auch nur Vereinsintern genutzt.

Es gibt doch einige die sich mit der SIO beim STM32F072 beschäftigt 
haben und wenn dann jemand hier drauf schaut, sollte derjenige schon gut 
sehen können ob das so richtig ist. Gut es geht jetzt, aber ist das nur 
Glück?
Zu mindestens ist das hier um einiges übersichtlicher und einfacher wie 
manch andere Anfragen hier im Forum (Wenn man sich damit auskennt).

VG, Peter

von Marcus H. (Firma: www.harerod.de) (lungfish) Benutzerseite


Lesenswert?

Wir werden alle nicht jünger.
Die STM32 sind halt eine andere Kampfklasse als AVR/PIC. Bis man die ca. 
4000 Seiten Doku, verteilt auf ca. 50 Dokumente, für den F0 durch hat, 
das dauert. Aber im Vergleich zum F4 ist das Teil echt übersichtlich.
Allerdings kann man anschließend in den MCUs Dinge abbilden, die vor ein 
paar Jahren nur mit FPGAs bzw. ASICs gingen. Meine Website ist voll mit 
Beispielen dafür.

Dabei ist der Cortex Mx eher der Knecht zum Datenverarbeiten. Das 
Datenschaufeln zwischen Peripherie und Speicher macht bevorzugt DMA.

Das nur als abschließende Idee, viel Erfolg mit dem Projekt.
Ich lese einfach noch ein wenig mit. :)

von Peter (Gast)


Lesenswert?

DMA würde ich gerne nehmen, ist hier aber nicht so einfach möglich.
Irgendwie muss ich halt auf die ganzen Errors reagieren, weil darüber 
der Start erkannt wird und die Anzahl der Daten die ankommen ist nicht 
sicher. DMX sagt zwar 512 Byte aber es gibt DMX Sender die nur 60Byte 
senden.
Das ganze lief vorher auf einem AVR und wenn der das packt dann sollte 
der STM darüber lachen können.

Die ARM Typen von NXP und Atmel haben mir nie soviel Ärger gemacht.
Aber bei den letzten Anwendungen die ich gemacht habe war von den Daten 
der STM Typen immer besser. Außerdem wenn sie laufen dann arbeitet auch 
alles perfekt.

Ich werde den Code so lassen, schau in mir aber noch mal im Debugger an.
Wenn ich Probleme bemerke dann werde ich mich wieder melden.

VG, Peter

von Falk B. (falk)


Lesenswert?

@Peter (Gast)

>DMA würde ich gerne nehmen, ist hier aber nicht so einfach möglich.
>Irgendwie muss ich halt auf die ganzen Errors reagieren, weil darüber
>der Start erkannt wird und die Anzahl der Daten die ankommen ist nicht
>sicher. DMX sagt zwar 512 Byte aber es gibt DMX Sender die nur 60Byte
>senden.
>Das ganze lief vorher auf einem AVR und wenn der das packt dann sollte
>der STM darüber lachen können.

Eben. DMA nützt nur was bei einem DMX-Sender.

von Peter (Gast)


Lesenswert?

Das auch nur wenn man kein interbyte Delay macht.
Also ein paar µs wartet zwischen den einzelnen Bytes.

Bitte nicht lachen, es gibt Geräte die schaffen sonst den Empfang nicht.

von Falk B. (falk)


Lesenswert?

@ Peter (Gast)

>Das auch nur wenn man kein interbyte Delay macht.
>Also ein paar µs wartet zwischen den einzelnen Bytes.

Dann geht es immer noch mit DMA, nur dass die dann halt per Timer und 
nicht per UART getriggert wird.

>Bitte nicht lachen, es gibt Geräte die schaffen sonst den Empfang nicht.

Jaja, schlechte Designs und Chinakram.

von Peter (Gast)


Lesenswert?

Stimmt diesen Trick gibt es ja.

Wenn ich mal einen Sender baue werde ich das dann auch so vorsehen, aber 
zur Zeit muss ich nur empfangen.

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.