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
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...
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
@ 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.
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.
@ 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?
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
Hatte das gleiche Problem beim STM32F072 Ich vermute mal Du nutzt die HAL Lib? Aber warten wir mal ab bis Du Deinen Code postest.
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
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.
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
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.
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
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. :)
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
@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.
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.
@ 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.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.