Hallo allerseits, ich habe ein seltsames Problem mit einem STM32F407ZG (168MHz Takt, 8MHz Quarz) Ich bin seit einiger Zeit bei einem Gerät programmieren welches ständig um neue ICs etc erweitert wird. Mittlerweile habe ich folgende Peripherie im Einsatz: USART2, 115200 8N1, RXNE IRQ SPI1, Master 1,32MHz SPI3, Master 1,32MHz I2C1, I2C 400kHz TIM1, 100Hz PWM TIM9, 1ms IRQ TIM10, 0-2kHz PWM TIM11, 0-2kHz PWM Ich habe nur 2 IRQ in Verwendung, alles andere wird über Flags oder anders gelöst. 1. USART2 RXNE -> wann Daten vom PC ankommen (hat bereits die höchste Priorität) 2. TIM9 -> wird alle 1ms aufgerufen für Timing (hat eine niedrigere Priorität) Mit dem TIM9 wird quasi die Zeitbasis erstellt und bestimmt welcher IC (AD, DA etc) wann ausgelesen werden soll (SPI1, SPI3, I2C1) und gibt auch das Intervall für die Messwertausgabe über RS232 Tx (USART2) vor. Mein Problem ist nun, dass sich über die Zeit ein Fehler beim USART2 RXNE IRQ eingeschlichen hat. Ich bekommen nicht mehr alle Rx Daten im Buffer angezeigt, der Controller schluckt quasi ab und zu 1,2,3 Zeichen, meist am Schluss. Ich habe keine Ahnung wie so etwas bei einem IRQ überhaupt passieren kann?!?! Ich habe nun als Versuch alles außer USART2 und TIM9 vom Programm eliminiert und nun funktioniert wieder alles, keinen einzigen Fehler!!?? Kann es sein das der µC mit etwas zu "beschäftigt" ist? Kann ein IRQ eine Warteschleife (bis TXE Flag etc kommt bei SPI, I2C) nicht einfach unterbrechen?? Vielleicht hat noch jemand eine Antwort auf meine Fragen oder einen Tipp/Hinweis für mich was man kontrollieren oder ändern könnte?! Bin für jede Hilfe dankbar!! Vielen Dank im Voraus!
An welcher Stelle in der ISR setzt Du das RXNE Flag zurueck? Vor oder nach dem Auslesen des DatenRegisters?
Vor dem Auslesen, sofort nach dem Aufrufen. Könnte das das Problem sein?? Aber wieso funktioniert es dann ohne die restliche Peripherie dann ohne Probleme? Nachtrag: Habe es gerade mal vertauscht, aber die fehlenden Zeichen kommen immer noch vor.
Dann kommst Du wohl nicht drumherum Dir mal ins Eingemachte gucken zu
lassen.
>Kann es sein das der µC mit etwas zu "beschäftigt" ist?
glaube nicht das dein Programm einen 168MHz cm4 auslastet.
Wenn die Prozessorlast allerdings sehr hoch ist, ist es ratsam alle
Peripherie wo es geht ueber ISR's auszuwerten.
Evtl die UART und SPI Geschichte ueber DMA.
hast Du den RX Buffer und den Buffer-Index-Counter als volatile
declariert?
Ju
John W. schrieb: > [...] hat bereits die höchste > Priorität [...] Zeige bitte den Code. Dir ist bekannt, das bei Cortex M die höhere Zahl eine niedrigere Priorität hat?
Vielen Dank erstmal an alle für eure Hilfe. @ Juergen G Nein, ich hatte Buffer und Counter nicht mit volatile deklariert. Habe es aber gerade ausprobiert, am Anfang schien es als ob es besser wäre aber leider tritt der Fehler immer noch auf. Habe sie aber nun trotzdem mit volatile deklariert lassen. @ Jim Meba Ja das ist mir bekannt. Der USART2 RXNE hat Priority 0 und SubPriority 0, der TIM9 BRK hat Priority 1 und SubPriority 1. Hier der Code von TIM9 und USART2 Init sowie USART2 RXNE IRS:
1 | NVIC_InitTypeDef NVIC_InitStructure; |
2 | TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; |
3 | TIM_OCInitTypeDef TIM_OCInitStructure; |
4 | |
5 | /* TIM9 clock enable */
|
6 | RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM9, ENABLE); |
7 | |
8 | /* Enable the TIM9 global Interrupt */
|
9 | NVIC_InitStructure.NVIC_IRQChannel = TIM1_BRK_TIM9_IRQn; |
10 | NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; |
11 | NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; |
12 | NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; |
13 | NVIC_Init(&NVIC_InitStructure); |
14 | |
15 | /* Compute the prescaler value */
|
16 | TIM9_PrescalerValue = (uint16_t) (SystemCoreClock / 16000000) - 1; |
17 | |
18 | /* Time base configuration */
|
19 | TIM_TimeBaseStructure.TIM_Period = TIM9_ARR; |
20 | TIM_TimeBaseStructure.TIM_Prescaler = TIM9_PrescalerValue; |
21 | TIM_TimeBaseStructure.TIM_ClockDivision = 0; |
22 | TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; |
23 | TIM_TimeBaseInit(TIM9, &TIM_TimeBaseStructure); |
24 | |
25 | /* Output Compare Toggle Mode configuration: Channel1 */
|
26 | TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_Toggle; |
27 | TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; |
28 | TIM_OCInitStructure.TIM_Pulse = TIM9_CCR1; |
29 | TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low; |
30 | TIM_OC1Init(TIM9, &TIM_OCInitStructure); |
31 | |
32 | TIM_OC1PreloadConfig(TIM9, TIM_OCPreload_Disable); |
33 | |
34 | /* TIM enable counter */
|
35 | TIM_Cmd(TIM9, ENABLE); |
36 | |
37 | /* TIM IT enable */
|
38 | TIM_ITConfig(TIM9, TIM_IT_CC1, ENABLE); |
1 | GPIO_InitTypeDef GPIO_InitStructure; |
2 | USART_InitTypeDef USART_InitStructure; |
3 | NVIC_InitTypeDef NVIC_InitStructure; |
4 | |
5 | /* Enable USART2 Clock */
|
6 | RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE); |
7 | |
8 | /* Enable GPIO clock */
|
9 | RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE); |
10 | |
11 | |
12 | // Tx Pin
|
13 | GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2; |
14 | GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; |
15 | GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; |
16 | GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; |
17 | GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP ; |
18 | GPIO_Init(GPIOA, &GPIO_InitStructure); |
19 | |
20 | // Rx Pin
|
21 | GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3; |
22 | GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; |
23 | GPIO_Init(GPIOA, &GPIO_InitStructure); |
24 | |
25 | /* Connect USART2 pins to AF7 */
|
26 | GPIO_PinAFConfig(GPIOA, GPIO_PinSource2, GPIO_AF_USART2); |
27 | GPIO_PinAFConfig(GPIOA, GPIO_PinSource3, GPIO_AF_USART2); |
28 | |
29 | |
30 | USART_InitStructure.USART_BaudRate = 115200; |
31 | USART_InitStructure.USART_WordLength = USART_WordLength_8b; |
32 | USART_InitStructure.USART_StopBits = USART_StopBits_1; |
33 | USART_InitStructure.USART_Parity = USART_Parity_No; |
34 | USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; |
35 | USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; |
36 | USART_Init(USART2, &USART_InitStructure); |
37 | |
38 | /* Enable the USARTx Interrupt */
|
39 | NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn; |
40 | NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; |
41 | NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; |
42 | NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; |
43 | NVIC_Init(&NVIC_InitStructure); |
44 | |
45 | /* Enable USART */
|
46 | USART_Cmd(USART2, ENABLE); |
47 | |
48 | /* Enable Receive interrupt */
|
49 | USART_ITConfig(USART2, USART_IT_RXNE, ENABLE); |
1 | void USART2_IRQHandler( void ) |
2 | {
|
3 | // RXE Interrupt, wenn neues Zeichen empfangen wurde auf 1
|
4 | if(USART2->SR & USART_SR_RXNE) |
5 | {
|
6 | USART2->SR &= ~USART_SR_RXNE; // Receive IR-Flag zuruecksetzen |
7 | |
8 | // wenn der letzte Befehl verarbeitet wurde
|
9 | if (RS232_In == 0) |
10 | {
|
11 | |
12 | // Zeichen nur übernehmen wenn es ein zulässiges ASCII Zeichen ist (a-z, A-Z, 0-9, '/', ';', '<', '>', '=', ',' , CR, '.', '-')
|
13 | if( (RxCounter < RS232_RX_ZEICHEN_MAX) && ( ((USART2->DR >= 0x61) && (USART2->DR <= 0x7A)) || |
14 | ((USART2->DR >= 0x2F)&&(USART2->DR <= 0x39)) || ((USART2->DR >= 0x41)&&(USART2->DR <= 0x5A)) || |
15 | ((USART2->DR >= 0x3B)&&(USART2->DR <= 0x3E)) || (USART2->DR <= 0x2C) || (USART2->DR == 0x0D) || |
16 | (USART2->DR == 0x2E) || (USART2->DR == 0x2D)) ) |
17 | {
|
18 | RxBuffer[RxCounter] = USART2->DR ; // vom Eingangsbuffer ins RxBuffer kopieren |
19 | RxCounter++; // und Zähler erhöhen |
20 | |
21 | // beim Endzeichen '>' oder 'CR' wenn vollst Befehl übernehmen und ganz vorne anfangen
|
22 | if( (USART2->DR == 0x3E) || (USART2->DR == 0x0D) ) |
23 | {
|
24 | RS232_In = 1; |
25 | RxCounter = 0; |
26 | }
|
27 | // bei zuvielen Zeichen, Buffer voll, jedenfalls ungültig, daher verwerfen
|
28 | if( RxCounter >= RS232_RX_ZEICHEN_MAX ) |
29 | {
|
30 | RxCounter = 0; |
31 | }
|
32 | |
33 | }
|
34 | |
35 | }
|
36 | // -> Fehlersuche RS232
|
37 | // else
|
38 | // {
|
39 | // RxBuffer_Fail[RxCounter_Fail++] = USART2->DR;
|
40 | // }
|
41 | |
42 | |
43 | // -> Fehlersuche RS232
|
44 | // RxBuffer_Test[Rx_Cnt++] = USART2->DR;
|
45 | |
46 | |
47 | }
|
48 | }
|
Ich möchte nocheinmal betonen das der Code bzw die RS232 ohne sonstige SPI1/3 etc Vorgängen sich völlig normal verhält und KEIN Fehler auftritt!!! Was kann also die USART2 Hardware oder den USART2 IRS dazu veranlassen ab und zu nicht auszulösen?? Auffällig ist noch, dass meistens das 2.+ 3. Zeichen oder die letzen 2-3 Zeichen fehlen und somit auch das Schlusszeichen!
John W. schrieb: > if( (RxCounter < RS232_RX_ZEICHEN_MAX) && ( ((USART2->DR >= 0x61) > && (USART2->DR <= 0x7A)) || > ((USART2->DR >= 0x2F)&&(USART2->DR <= 0x39)) || ((USART2->DR >= > 0x41)&&(USART2->DR <= 0x5A)) || > ((USART2->DR >= 0x3B)&&(USART2->DR <= 0x3E)) || (USART2->DR <= > 0x2C) || (USART2->DR == 0x0D) || > (USART2->DR == 0x2E) || (USART2->DR == 0x2D)) ) > { Das wuerde ich nicht so machen. lies erst USART2->DR in eine Variable und mache die Auswertung an der Variablen. Ich bin mir nicht ganz sicher, aber nur mal so als Idee. Waerend Deiner Evaluation kann schon das naechste Byte gesendet worden sein. RXNE ist geloescht aber der UART wird das Byte nicht annehmen weil DR noch nicht gelesen wurde. Probiers einfach mal aus.
Bin nun ein gutes Stück vorangekommen. Ich habe nun die USART2 auf Hardware Flow Control umgestellt und direkt an die Serielle von meinem PC gehängt, dann war der Fehler weg (soweit ich das mit dem Terminalprogramm sagen kann)!! Leider funktioniert dies (noch) nicht mit meiner eigentlichen Gegenstelle dem USB HID IC CP2110. Mit der eigentlich PC Software wird nähmlich über USB HID kommuniziert. Ich habe jedenfalls dann mit dem Oszi auf die Leitung RTS vom Controller getriggert und festgestellt, das er ab und zu für 100 - 400µs auf high ist und somit beschäftigt ist! Da es nur die TIM9 IRS sein konnte welche den USART2 IRS abhalten konnte diesen auzuführen, habe ich einen Pin solange auf 1 geschalten, solange diese ausgeführt wird! Damit wurde meine Vermutung bestätigt, dass es wirklich die TIM9 IRS ist welche den Controller davon abhält die Daten auszuwerten (für max. 380µs (~3-4 ASCII Zeichen)!!) Zu den Bildern: Kanal A (rot) ist der RTS Pin vom STM, Kanal B (blau) ist die TIM9 IRS. Die TIM9 IRS wird alle 1ms aufgerufen für die Zeitbasis, alle 10ms werden aber alle IC ausgelesen (SPI1, I2C), dann braucht er natürlich etwas länger! Meine Fragen nun: - Warum kann USART2 IRS die TIM9 IRS nicht unterbrechen obwohl die Priorität richtig gesetzt ist?? - Muss man diese IRQ Funktion zum Unterbrechen vielleicht noch zusätzlich irgendwie aktivieren??? - Wenn zB. eine SPI Funktion zum Auslesen von einem IC innerhalb von der TIM9 IRS aufgerufen wird, zählt diese dann trotzdem zur TIM9 IRS oder könnte das Probleme verursachen? Vielleicht habe ich auch grundlegend etwas am NVIC/IRQ/IRS nicht verstanden, bitte daher um eure Hilfe!! Vielen Dank im Voraus!
@ Juergen G. Danke für diesen Hinweis und die gute Erklärung. Es wird an meinem aktuellen Problem sicher nichts ändern aber das werde ich demnächst zur Sicherheit auf deine Variante umstellen. Wie sollte man nun eine IRS ganz korrekt abarbeiten? Zuerst Daten kopieren, auswerten und dann erst das Flag löschen oder?
John W. schrieb: > Wie sollte man nun eine IRS ganz korrekt abarbeiten? Das solltest Du individual festlegen, es kommt auf den IRQ, Prioritaet, Haeufugkeit, Systemlast etc. an und es gibt da kein Standardvorgehen. zBsp. kann ein SPI, CAN oder Ethernet viel mehr Daten/s empfangen als ein UART. Wenn dann eine (nicht so aufwendige) Evaluation stattfinden soll die aus irgendwelchen Gruenden in die ISR muss, ist es ratsam die Daten zu lesen dann das Flag zuruecksetzen dann die Evaluation. Manchmal auch Evaluation und dann Flag zuruecksetzen. Wenn die Evaluation aufwendiger ist, dann in der ISR nur Daten lesen und Flag zuruecksetzen, Evaluation dann an anderer Stelle. Bei vielen uC's kann man auch auf Memory Value Change Triggern. Aber wie gesagt, es kommt auf den speziellen Fall an und sollte immer fuer genau diesen Fall entschieden werden.
Danke für die ausführliche Erklärung! Hast du oder sonst jemand zufällig eine Erklärung (oder Theorie) bezüglich meiner letzten Fragen von oben??
Daten Kopieren, Flag loeschen, Daten auswerten. Wenn das Flag geloescht ist, kann waerend Du Daten auswertest das naechste Byte schon reinkommen und wenn Du die ISR verlaesst springt der uC gleich wieder in die ISR wenn ein Byte da ist. Das ist aber beim UART, Deinem speziellen Fall und einem 168MHz uC ziehmlich unwarscheinlich. Da die Rechenzeit in der ISR viel kuerzer ist als der UART Daten empfangen kann. In Deinem Fall, Du schreibst dass die TIM9 ISR fuer Verzoegerung sorgt, wuerde ich diese ISR auf das Minimum and notwendiger Arbeit zusammenkuerzen. Wenn TIM9 sowieso nur eine Timebase ist um zBsp. den ADC um eine Konversion zu bitten oder die Daten am DA zu aendern, kannst Du das ueber Flags machen. Also eine globale (volatile) Variable als Flagregister nehmen und in der ISR nur die Flags setzten. In der Hauptschleife dann die Flags abfragen und die Arbeit machen lassen. Dann ist es auch recht unwarscheinlich das die TIM9 ISR Deinen UART stoert.
Kleine Ergaenzung noch, falls Du Dein Programm an den Beispielen von ST orientierst. Die Programmiertechnik der Chiphersteller ist nicht "Real Project" tauglich. Die vielen
1 | while(warte_auf_flag) |
2 | {}
|
koennen Dir ganz schoen viel Prozessorzeit kosten. Die Beispiele sind nur um zu zeigen das die Peripherie auch das macht was der Chiphersteller geplant hat. Der Beispiel code macht nichts anderes als das zu zeigen. Wenn Du viele dieser Codebeispiele zusammen in ein Programm packst, erlebst Du Dein Blaues Wunder und jeder Atmega ist schneller als Dein ARM. Die Programmlogik und das Timing ist das Hauptproblem der uC Programmierung. Du solltest ein Timing-Diagramm fuer Deine Programme erstellen. Dann kannst Du zBsp. sehen das Du in einer Timebase nur jeden dritten IRQ irgendetwas machen musst, aber jedes mal was anderes. So zBsp. 1. IRQ -> ADC anstossen 2. IRQ -> DAC updaten 3. IRQ -> Daten senden dann wieder von vorn. somit hat Deine ISR auch immer die selbe Verarbeitungszeit
Wenn da wirklich noch ein ADC läuft, empfiehlt es sich m.E. sowieso, für diesen die DMA zu nutzen, dann bleibt das Interruptsystem völlig frei. Das gleiche geht übrigens auch für UARTs...
@ Matthias Sch. Die ADC sind extern über SPI, nicht die internen. Aber du hast Recht, man sollte sicher auf DMA bei den Bussystemen umsteigen. @ Juergen G Danke vielmals für deine bisherige Hilfe. Ich muss leider zugeben das ich doch einige Beispiele der ST Lib so verwendet habe (while Abfrage). Mir ist das zwar von Anfang an etwas komisch vorgekommen aber als Anfänger habe ich da nicht mehr großartig darüber nachgedacht und war froh das überhaupt der SPI funktioniert hat. Falls ich nun doch sämtliche Busperipherie auf DMA und IRQ umstelle, würde das natürlich vieles erleichtern, aber auch viel arbeit bedeuten. Die Geschwindigkeitsprobleme sollten dann aber sicher der Vergangenheit angehören, auch wenn die 168MHz natürlich von Haus aus etwas oversized sind. Ich habe es aktuell so das TIM9 eben die Zeitbasis erstellt wird und alle 10ms die AD Wandler ICs ausgelesen werden. Diese müssen teilweise ein paar ms zuvor gestartet werden was ich ebenfalls in der IRS mache. Da die AD Wandler ICs aber quasi gleichzeitig ausgelesen werden müssen(!), damit der zeitlicher Bezug zwischen den Messkanälen stimmt, habe ich das Auslesen über eine Funktion auch in TIM9 IRS geschrieben und diese dann nacheinander ausführen lassen. Mit der Zeit hat sich das dann immer so um IC und IC erweitert und dann sind eben irgendwann die Zeichenfehler aufgetreten. Muss ich mir mal genau überlegen wie ich das verbessern bzw umstellen könnte!?!? Mich interessiert aber trotzdem noch immer warum die USART IRS die TIM9 IRS nicht einfach unterbrechen kann!!!???? Das ist doch auch einer der angepriesenen Vorteil beim STM NVIC oder?? (siehe Bild) Danke im Voraus.
John W. schrieb: > USART2->SR &= ~USART_SR_RXNE; // Receive IR-Flag zuruecksetzen Das ist zwar nicht die Ursache, aber trotzdem falsch, weil so in seltenen Fällen versehentlich auch andere IR Flags des Registers zurückgesetzt werden können. Besser ist USART2->SR = ~USART_SR_RXNE; Siehe Definition von rc_w0.
Noch ein Nebentipp: Ich würde empfehlen, für den NVIC nicht die veralteten Funktionen der ST-Lib zu verwenden, sondern die vom CMSIS.
Juergen G. schrieb: > Das wuerde ich nicht so machen. > > lies erst USART2->DR in eine Variable und mache die Auswertung an der > Variablen. Das ist nicht nur sinnvoll, sondern zwingend, da bei UARTs ein Lesevorgang auf DR üblicherweise zerstörend wirkt. Wenn mehr als ein Zeichen im Puffer liegt, dann geht mit jedem überschüssigen Zugriff auf DR ein Zeichen verloren.
A. K. schrieb: > USART2->SR = ~USART_SR_RXNE; > Siehe Definition von rc_w0. Korrektur: Für RXNE gilt: "It is cleared by a read to the USART_DR register." Also: DR in jedem Fall erst einmalig auslesen, dann weiterverarbeiten. RXNE in Ruhe lassen.
John W. schrieb: > - Warum kann USART2 IRS die TIM9 IRS nicht unterbrechen obwohl die > Priorität richtig gesetzt ist?? Wie sieht denn die TIM9 ISR aus? Damit sie unterbrechbar wird, muß gleich zu Beginn etwas wie __enable_interrupt(); stehen. Oder verwechsel ich da etwas?
M. N. schrieb: > Oder verwechsel ich da etwas? Ja. Die Cortex-Mx unterstützen ein verschachteltes Interrupt-System mit Prioritäten. In einer ISR sind automatisch nur Interrupts gleicher und niedrigerer Prio blockiert, nicht aber alle.
John W. schrieb: > - Warum kann USART2 IRS die TIM9 IRS nicht unterbrechen obwohl die > Priorität richtig gesetzt ist?? Das ist schon seltsam, aber nested IRQ's beim F4 habe ich schon gemacht und es funktioniert. Also ist der Wurm bestimmt im Programm. vielleicht benutzt Du mal NVIC_SetPriority(XXX_IRQn, y); NVIC_GetPriority(XXX_IRQn); NVIC_EncodePriority NVIC_DecodePriority um zu sehen wie die Prioritaten aussehen wenn alles initialisiert ist. Manche IRQs lassen sich nicht durch NVIC_Init() beindrucken, da muss man die Prioritaet nach dem activieren setzen. Das sind aber mE nur die core IRQ's und da gehoeren der Tim9 und der UART glaube ich nicht dazu. Aber probier mal was GetPriority sagt, nachdem alles initialisiert ist.
John W. schrieb: > sämtliche Busperipherie auf DMA und IRQ umstelle, > würde das natürlich vieles erleichtern, aber auch viel arbeit bedeuten. Naja, es muss ja nicht gleich sämtliche Peripherie sein, in deinem Fall reicht ja der USART. Ist auf jeden Fall mal lehrreich, sich mit der DMA zu beschäftigen, denn z.B. der interne ADC ist mit mehreren Kanälen ohne DMA nicht sinnvoll zu benutzen. Das die STM32 durch die etwas ungeschickte Doku kein Sonntagsspaziergang sind, ist dir ja bereits klar, hehehe. M.E. ist es sinnvoll, die Prioritäten der beiden IRQs auch mal auszutauschen, denn eine USART ist ein eher langsames Dings. So mach ich es z.B. in meinem BLDC Projekt auch, und da geht nichts verloren, trotz recht heftigen Timer- und Hallsensor IRQs.
A. K. schrieb: > M. N. schrieb: >> Oder verwechsel ich da etwas? > > Ja. Die Cortex-Mx unterstützen ein verschachteltes Interrupt-System mit > Prioritäten. In einer ISR sind automatisch nur Interrupts gleicher und > niedrigerer Prio blockiert, nicht aber alle. Das ist schon klar. Ich habe es mit den Renesas RX-ISRs verwechselt. Diese brauchen eine Spezialbehandlung, da mit jedem Interrupt das globale 'I'-Flag gelöscht wird, wodurch auch höher priorisierte ISRs gesperrt werden. Das ist zwar eigenartig, aber vielleicht braucht man so etwas ja irgendwo. Juergen G. schrieb: > vielleicht benutzt Du mal > > NVIC_SetPriority(XXX_IRQn, y); > NVIC_GetPriority(XXX_IRQn); > NVIC_EncodePriority > NVIC_DecodePriority > > um zu sehen wie die Prioritaten aussehen wenn alles initialisiert ist. Das würde ich auch sagen und kontrollieren, ob in TIM9 ISR nicht eine INT-Sperre eingebaut ist. Zudem sind 100-400µs ja fast eine Ewigkeit.
Wow, vielen Dank an alle für eure Hilfe und die ganzen Antworten!! @ A. K. Danke für den Hinweis mit dem Löschen der IRQ Flags usw. Habe nun die USART2 IRS auf die empfohlene Variante von dir und Juergen G. umgestellt. Was meinst du genau mit NVIC Funktionen von CMSIS verwenden? Meinst du die Funktionen aus der core_cm4.h oder gibt es da noch etwas?? Wenn es was anderes gibt wäre ein Link sehr hilfreich. @ Juergen G. Du hast wiedermal voll ins Schwarze getroffen. Nach dem bisherigen initaliseren waren beide IRQ auf Priority 0!! Ich habe dann mit NVIC_SetPriority() die Priority vom TIM9 auf 1 gestellt und dann hat es endlich so funktioniert wie ich das haben wollte!! (siehe Bild) Muss ich alle NVIC Funktionen die du aufgeschrieben hast auch ausführen? Verstehe noch nicht ganz wozu NVIC_EncodePriority() und NVIC_DecodePriority() genau dient!? Warum gibt es dort Priority, PriorityGroup, PreemptPriority und SubPriority? Ich kenne nur Priority und SubPriority vom NVIC der ST-Lib!?!? Wie M. N. schrieb (Zudem sind 100-400µs ja fast eine Ewigkeit.) sollte ich über das Handling/Timing der AD Wandler vermutlich noch mal nachdenken. Obwohl es nun mit der funktionierenden IRQ Priority keine Fehler mehr gibt, wäre eine Lösung über Flags vermutlich sinnvoller - oder wie würdet ihr das lösen?? Wenn die ST-Lib Funktionen mit den while Schleifen nicht gut sind, was kann man da dann genau umstellen bzw verbessern?? Alles auf IRQ oder DMA mit IRQ??? Mir hat es an und für sich schon gut gefallen das zB am Ende meiner SPI1 Sende/Empfangsfunktion die Auswertung gleich folgen konnte und ich genau wusste, welche Daten von welchem IC gerade im Buffer stehen, eben wie im C-Code nacheinander programmiert. Ich schätze das würde bei einer IRQ Lösung schon viel komplizierter werden... Schöne Grüße
John W. schrieb: > Meinst du die Funktionen aus der core_cm4.h Ja. Der NVIC-Support der ST-Lib ist dort nur noch drin, weil er aus der Zeit vor CMSIS geerbt wurde.
Wovon ist das abhängig ob ein Interrupt die Priority Einstellung über die NVIC_SetPriority() Funktion benötigt oder über das NVIC Init struct? In den Beispielen von ST wird ja eigentlich immer das Struct benutzt.
funky schrieb: > Wovon ist das abhängig ob ein Interrupt die Priority Einstellung über > die NVIC_SetPriority() Funktion benötigt oder über das NVIC Init struct? Es führen viele Wege nach Rom. Man kann auch direkt an die Hardware. Oder man verwendet http://www.libopencm3.org für Core- und Non-Core-Kram. Das erspart einem die umständlichen Structs. > In den Beispielen von ST wird ja eigentlich immer das Struct benutzt. Weil die Beispiel entsprechend alt sind. Anfangs gab es CMSIS nicht, also baute ST den NVIC-Support in die Lib. Später kam CMSIS. Rausgeworfen hat ST deren Kram natürlich nicht, aber meiner vagen Erinnerung nach haben es zwischenzeitlich deshalb in ein anderes Include-File verschoben.
John W. schrieb: > Muss ich alle NVIC Funktionen die du aufgeschrieben hast auch ausführen? Nein, das war nur ein Denkanstoss um herauszufinden wo der Hase im Pfeffer liegt. Wenn Get/SetPriority nicht zum Ziel fuehren, hat man mit den Encode/Decode Routinen ein Werkzeug um etwas tiefer ins Eingemachte zu gehen. John W. schrieb: > Verstehe noch nicht ganz wozu NVIC_EncodePriority() und > NVIC_DecodePriority() genau dient!? Um STM32 Einsteiger zu verwirren ;-) Du musst nicht alles auf einmal Lernen. Kleiner allgemeiner Hinweis. Wenn Dir irgendetwas Raetsel aufgibt, Du es im Moment aber nicht unbedingt brauchst, ist es besser, es erst mal zu ignorieren. Spaeter wenn Du dann mal ein Problem hast wo Du es unbedingt brauchst wirst Du es auch verstehen. Salopp gesagt sind NVIC_EncodePriority() und NVIC_DecodePriority() andere Funktionen um die Prioritaeten zu Gruppieren und innerhalb der Gruppen zu Ordnen. Bei Groesseren Projekten kann man schnell mal die Uebersicht verlieren, wenn man in jeder Classen Datei Prioritaeten vergibt ohne auf die anderen schon vergebenen zu achten.
Nochmal zu Deinen SPI ADC's. Du schreibst weiter oben, John W. schrieb: > und > alle 10ms die AD Wandler ICs ausgelesen werden. Diese müssen teilweise > ein paar ms zuvor gestartet werden was ich ebenfalls in der IRS mache. Wenn die Conversion vorher angestossen werden muss ist es egal wann Du sie in welcher Reihenfolge ausliest, nur angestossen werden muessen sie zur selben Zeit. also innerhalb der TIM9 ISR einen Counter der immer bei 10 zurueckgesetzt wird. Wenn zurueckgesetz, die ADC's anstossen und je nachdem wie lange sie fuer eine Conversion brauchen, dann in Counter = X das Flag setzen um den entsprechenden ADC in der Mainloop auzulesen. Wenn ale ausgelesen sind die Auswertung oder den Transfer machen. Das alles vom jetzigen Code auf ISR umzustellen ist kein Problem. Kopiere den Code den Du in der ISR zum Auslesen und Auswerten hast in eine Funktion. In der ISR setzt Du nur ein Flag und in der MainLoop rufst Du die Funktion auf.
Ok, dann habe ich soweit alles verstanden! Vielen Dank nochmal an alle und speziell an dich Juergen G., du hast mir wirklich sehr weitergeholfen in den letzten Tagen!! Vielleicht liest man sich mal wieder bei einem weiteren STM32 Problem... ;-)
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.