Hallo zusammen, ich habe hier einen STM32F103 auf dem BluePill Board. Daran hängt ein MCP2551 CAN Transciever. Damit versende ich erfolgreich CAN Botschaften. Jetzt möchte ich den umgedrehten Weg gehen und eine Botschaft empfangen. Allerdings scheitere ich daran. Ich nutze die HAL-Bibliotheken und habe mich an Beispiel aus dem STM PDF gehalten (Anhang). Wo liegt der Fehler? Ich habe das Gefühl das ich nicht in den Interrupt Handler springe und somit die Nachricht nicht richtig dekodieren kann. Wenn ich die Funktion "HAL_CAN_GetRxMessage" in der while schleife ausführe, dann passiert auch nichts. Irgendwie macht es für mich auch keinen Sinn, im Interrupt die Variable RxData zu befüllen. Normal müsste ich RxData ja ein Rückgabewert der Funktion sein, oder? Viele Grüße
Jens schrieb: > Ich nutze die HAL-Bibliotheken und habe mich an Beispiel aus dem STM PDF > gehalten (Anhang). Solche große Dokumente verlinkt man normalerweise anstatt sie anzuhängen. > Wo liegt der Fehler? Irgendwo in deinem Programm oder deiner Schaltung. Du hast vergessen, deinen Quelltext und den Schaltplan anzuhängen. Ein detailliertes Foto vom Aufbau wäre auch hilfreich. Bist du denn wenigstens sicher, dass es da CAN Botschaften zum Empfangen gibt? Hast du das mit einem Sniffer oder Logic Analyzer verifiziert?
Hallo Stefan, der Code hängt doch an im ersten Post? Ja, ich habe ein CAN Interface dran. Da sehe ich meine eigene Botschaft die ich vom STM aus schicke und ich sende vom Interface aus eine auf den Bus. Sollte passen. Aufbau ist relativ einfach. Steckbret, darauf die BluePill und der MCP2551 + 120 Ohm. Wie gesagt, die Hardware steht, da bin ich relativ sicher. Ich scheitere an der SW. VG
>>Damit versende ich erfolgreich CAN Botschaften. Wer hat da was empfangen? >>Ich habe das Gefühl das ich nicht in den Interrupt Handler springe Du(!) kannst da nicht reinspringen... >>und somit die Nachricht nicht richtig dekodieren kann die CAN-Hardware dekodiert das schon... Deine main_mc ist für die Fragestellung unbrauchbar, da ist zuviel "Müll" drin. Reduziere Dein Prog auf reinen CAN-Betrieb.
Pieter schrieb: > Wer hat da was empfangen? Das CAN Interface. Auf 500kbit/s --> senden funktioniert, HW steht. Pieter schrieb: > Du(!) kannst da nicht reinspringen... Gut das du mir das nochmal deutlich gemacht hast, dass war das Problem. Pieter schrieb: > die CAN-Hardware dekodiert das schon... Gut zu wissen, warum dann alle SW schreiben wenn die Hardware doch alles schon erledigt... Pieter schrieb: > Reduziere Dein Prog auf reinen CAN-Betrieb. Dann kommt in 5 min jemand und fragt nach dem vollen Code, zwecks fehlern in der Config, dem Takt etc. Deswegen habe ich alles angehangen. VG
ok., Du hast eine CAN-Gegenstelle, dann schreibe ein Prog welches CAN empfängt und zurücksendet. Zurück sollte ja gehen. und dann sehen wir weiter.
Meinst du jetzt ein Prog für das CAN Interface? Das habe ich schon, aber was soll mir das bringen? Dann sehe ich in der SW vom CAN Interface als RX die ID321 die vom STM gesendet wird und schicke sie wieder auf den CAN...und dann? Der MCP2551 quittiert die Korrektheit der Botschaft mit einem ACK und das wars dann. Genau da beginnt ja mein Problem, ich kriege die Daten nicht in den STM.
Jens schrieb: > und dann? Das weißt du, dass dieser Teil der Software funktioniert. Erst danach baut man die Verarbeitung der Daten oben drauf.
Der bxCAN-Controller im STM32 hat zwei Empfangspuffer mit je 3 Slots. Damit die befüllt werden, muss du Filterregeln definieren. Anhand der Filterregeln weiß der Controller welche Nachricht in welchen Puffer kommt. Alle andren Nachrichten werden ignoriert. Ob in den Puffern was drin ist, kannst du über Register-Flags abfragen. Die Filterregeln können unterschiedlich aufgebaut sein. (Es gibt 4 Arten) Std-ID oder Ext-ID ID-List oder ID-Mask Am besten du fängst einfach an, und schreibst eine Std-ID-List Regel. Da kannst du dann bis zu 4 IDs ein schreiben, die z.B. alle in den ersten Puffer einsortiert werden. Dann kannst du diesen Puffer abfragen.
>>bis zu 4 IDs ein schreiben
wieso nur 4?
F0R1 = ( Maske << 21 ) || (Adresse << 5)
wenn die Maske auf 0 gesetzt wird, wird jede Adresse gültig.
wenn die Maske auf 0x7FF gesetzt wird, ist nur eine Adresse gültig.
Pieter schrieb: > wenn die Maske auf 0 gesetzt wird, wird jede Adresse gültig. > wenn die Maske auf 0x7FF gesetzt wird, ist nur eine Adresse gültig. Ja, das wäre dann eine Std-ID-Mask Regel Da kann man zwei ID+Mask Kombinationen wählen.
CK schrieb: > Ob in den Puffern was drin ist, kannst du über Register-Flags abfragen. OK, danke für den Hinweis! Das müsste ja dann das Register "CAN_RF0R" sein? Wenn da das Bit0 auf 1 steht, dann müsste doch eine Nachricht in der Mailbox liegen, oder? Wie kann ich den Wert des Registers auslesen? CK schrieb: > Da kannst du dann bis zu 4 IDs ein schreiben, die z.B. alle in den > ersten Puffer einsortiert werden. Muss man den Puffer zwangsläufig zuweisen oder wird immer in den "CAN_RX_FIFO0" geschrieben, sofern nicht anders konfiguriert? VG Jens
Jens schrieb: > Wie kann ich den Wert des Registers auslesen? variable = registername; uint32_t r=CAN->RF0R;
Stefan ⛄ F. schrieb: > uint32_t r=CAN->RF0R; Danke! Da steht eine saubere 0 drin :(. Ausgelesen über den ST-LinkV2 im Debug Modus.
Hier noch ein Bild vom Oszi, direkt gemessen am PIN A11. Das passt aus meiner Sicht. VG Jens
>>Wie kann ich den Wert des Registers auslesen?
bo,eh, was soll die Frage bedeuten?
Ist die 0x88 auch als Adresse/Maske zugewiesen?
Ist ein Filter zugewiesen?
Wird der IRQHandler angesprungen?
Daher meine Bitte das Prog auf rein CAN zu reduzieren
Pieter schrieb: > bo,eh, was soll die Frage bedeuten? Meiner Meinung nach lässt die Frage wenig Interpretationsspielraum. Stefan hat die Frage verstanden und beantwortet. Pieter schrieb: > Ist die 0x88 auch als Adresse/Maske zugewiesen? > Ist ein Filter zugewiesen? Mein Filer steht nun auf "Disable", ist dann so eine Zuweisung nötig? Das Filtern würde ich gern auf später verschieben, sobald der Empfang der Nachricht funktioniert. Pieter schrieb: > Daher meine Bitte das Prog auf rein CAN zu reduzieren OK, mache ich. VG Jens
>>Das Filtern würde ich gern auf später verschieben, >>sobald der Empfang der Nachricht funktioniert. Henne-Ei-Problem. Mindestens das 1. Filter muß aktiviert sein. Die Adresse wäre sonst 0, ob das geht habe ich noch nicht getestet.
Du musst mindestens einen filter definieren und aktivieren, damit was in der empfangsfifo ankommt. Also z.b. um jeden datenframe zu empfangen, Filter auf RTR=0 und Mask mit RTR=1. Das Ganze ist in diesen 16bit variablen der HAL-Filter struct ganz merkwürdig codiert, wenn du das über die HAL machst, musst du im refman gucken, an welcher stelle im filterwort das RTR bit steht, ich glaube, Bit 1 oder 2.
Hat der TO das Problem beheben können? Stehe nämlich vor exakt dem selben Problem. Ich werde jetzt versuchen eure Lösungsvorschläge anzuwenden und euch dann von meinem hoffentlich positiven Ergebnis berichten.
Leider war ich bis jetzt wenig erfolgreich. Ich weiß nicht, ob der TO eben falls dieses Problem hatte, aber mir scheint es, als würde der Programmdurchlauf nicht bis zur Main Methode kommen. Denn egal was ich in die Main schreibe, sie wird nicht ausgeführt. Wenn auch hier zu viel sonstiger Code ist dann kann ich das natürlich noch reduzieren. Bin für jeden schlauen Rat offen!
Startest du irgendwo den CAN Interrupt? Und fürs Erste die Loopbackfunktion. Was kann Bluepill? Ist da ein Debugger drauf? Ansonsten nutze eine LED fürs Debugging. Und lass mal das xprintf Zeug weg.
Dominic schrieb: > Was kann Bluepill? Ist da ein Debugger drauf? Da ist ein ARM Cortex M3 drauf, also ja. Mit Debugger-Interface. Dazu braucht man dann noch einen ST-Link Adapter zum PC hin. Hat er bestimmt schon.
Also die Loopback funktion habe ich schon genutzt und auch das debuggen mittels LED. Wenn der Interrupt in der Main noch aufgerufen werden muss, dann werde ich das noch einpflegen. Ich versuche das ganze übrigens mit zwei STM32f103RB Nucleo Boards zu realisieren. Ich debugge im Augenblick einfach über den USB Port. Etwas merkwürdig ist auch, dass wenn ich die Jumperkabel vom Empfängerboard an Tx und Rx Port entferne und das Board resette wird die Main ganz normal ausgeführt. Danke schonmal im Voraus!
1 | RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE; |
2 | RCC_OscInitStruct.HSEState = RCC_HSE_ON; |
3 | RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1; |
4 | RCC_OscInitStruct.HSIState = RCC_HSI_ON; |
5 | RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; |
6 | RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE; |
7 | RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9; |
8 | if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) |
9 | {
|
10 | _Error_Handler(__FILE__, __LINE__); |
11 | }
|
Die Nucleo64-Boards (zumindest beim STM32L4) haben keinen HSE-Quarz bestückt, sondern bekommen ihren HSE-Takt vom ST-Link Controller. Ich vermute, du musst dann HSEState auf RCC_HSE_BYPASS setzen, ansonsten hängt der Controller in "SystemClock_Config"
1 | /*##-2- Configure the CAN Filter ###########################################*/
|
2 | sFilterConfig.FilterNumber = 0; |
3 | sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK; |
4 | sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT; |
5 | sFilterConfig.FilterIdHigh = 0x0000; |
6 | sFilterConfig.FilterIdLow = 0x0000; |
7 | sFilterConfig.FilterMaskIdHigh = 0x0000; |
8 | sFilterConfig.FilterMaskIdLow = 0x0000; |
9 | sFilterConfig.FilterFIFOAssignment = CAN_FILTER_FIFO0; |
10 | sFilterConfig.FilterActivation = ENABLE; |
11 | sFilterConfig.BankNumber = 0; |
12 | HAL_CAN_ConfigFilter(&hcan, &sFilterConfig); |
13 | |
14 | if (HAL_CAN_ConfigFilter(&hcan, &sFilterConfig) != HAL_OK) |
15 | {
|
16 | /* Filter configuration Error */
|
17 | Error_Handler(); |
18 | }
|
Du hast kein einziges Maskenbit gesetzt. Mit diesem Filter fliegt alles raus. Du solltest mindestens das Maskenbit, das das RTR-Bit auswählt, auf 1 setzen. An welcher Stelle dieses Bit steht, verrät ein Blick ins RefMan.
Rainer B. schrieb: > Du hast kein einziges Maskenbit gesetzt. Mit diesem Filter fliegt alles > raus. Du solltest mindestens das Maskenbit, das das RTR-Bit auswählt, > auf 1 setzen. An welcher Stelle dieses Bit steht, verrät ein Blick ins > RefMan. Eig genau anders rum, so werden alle IDs akzeptiert, ist also zum Testen so schon mal okay. Zum Takt kann ich so nichts sagen, da ich das Board nicht kenne. Die HAL_Libs unterscheiden sich teilweise. Für mich fehlt dort ein HAL_CAN_Start. Zudem kenne ich statt BankNumber = 0 eher SlaveStartFilterBank = 14. Und was sagt dein Debugging? Hast du ein Oszilloskop? Dann lass dir doch mal den Takt ausgeben und schaue.
Dominic F. schrieb: > Eig genau anders rum, so werden alle IDs akzeptiert, ist also zum Testen > so schon mal okay. Ja, du hast recht, Asche auf mein Haupt. Wichtig ist nur, dass überhaupt mindestens ein Filter definiert ist. > Zudem kenne ich statt BankNumber = 0 eher SlaveStartFilterBank = 14. Das ist schon ok. Der TO benutzt den Slave-CAN ja nicht. Und SlaveStartFilterBank = 14 ist eh default after reset. @TO: Wie oben schon vorgeschlagen, teste erst einmal im Loopback-Modus, bevor du mit zwei Boards probierst. Dafür fehlt dann in deinem Code das HAL_CAN_Transmit.
Dominic F. schrieb: > Und was sagt dein Debugging? Hast du ein Oszilloskop? Dann lass dir doch > mal den Takt ausgeben und schaue. Den Takt habe ich über CubeMX eingestellt und Habe die 36MHz für den Bus auf 250KBit/s runtergeteilt. Das Oszilloskop sagt mir eigentlich dass das Signal korrekt ankommt. Beim debuggen kann ich nur ein Warning über eine ungenutzte Funktion feststellen. Rainer B. schrieb: > @TO: Wie oben schon vorgeschlagen, teste erst einmal im Loopback-Modus, > bevor du mit zwei Boards probierst. Dafür fehlt dann in deinem Code das > HAL_CAN_Transmit. Also eigentlich habe ich das auch genau so gemacht. Erst im Loopback Modus probiert und dann das ganze aufgeteilt auf zwei Boards. Ich werde das ganze jetzt nochmal im Loopback Modus testen.
Philipp V. schrieb: >Beim debuggen kann ich nur ein Warning über eine ungenutzte Funktion feststellen. Wie sagt dir das der Debugger? Und welche ist das? > Erst im Loopback Modus probiert und dann das ganze aufgeteilt auf zwei Boards. Was zeigt das Oszi denn da? Das Tx-Signal vom Sender-Board oder das RX-Signal vom Empfänger-Board? Hast du die Abstürze des Empfänger-Boards in den Griff bekommen? Hast du die HSE-Config umgestellt auf bypass? Hast du zwischen den CAN-Leitungen Abschluss-Widerstände eingebaut? Wird auf dem Receiver-Board der CAN1_RX0_IRQHandler überhaupt mal aufgerufen? Nutzt du jetzt einen Debugger oder nicht? Falls ja, dann setze mal Breakpoints auf alle Can-Interrupts auf dem Receiver-Board um zu gucken, ob überhaupt was passiert. Falls kein Debugger, lass von allen CAN-Interrupt-Service-Routinen mal testweise je ein unterschiedliches Zeichen mit deiner "uart_putc" ausgeben, um zu gucken, ob da überhaupt irgendwas aktiviert wird. Vllt landet ja alles im Fehler-Interrupt. Danach das "uart_putc" wieder rausnehmen.
:
Bearbeitet durch User
Rainer B. schrieb: > Was zeigt das Oszi denn da? Das Tx-Signal vom Sender-Board oder das > RX-Signal vom Empfänger-Board? Das Siganl zeigt das CAN Low Signal. Im jetzigen Anhang zeigt das lilane signal weiter das CAN Low Signal und das gelbe Signal das Rx Signal nach einem Spannungsteilerverhältnis von 1:1 Die Widerstände habe ich auch drin an jedem Ende. Die Clock Konfiguration habe ich über CubeMX eingestellt und sie seit meinen Versuchen im Loopback Modus nicht mehr geändert. Dabei hat es keinerlei Störungen gegeben, weshalb ich auch annehme, dass die Konfiguration so funktioniert. Kann natürlich auch sein, dass ich unrecht habe. Einen Debugger habe ich noch nicht. Mit deiner vorgeschlagenen Methode bin ich leider auch nicht weiter gekommen. Rainer B. schrieb: > Wird auf dem Receiver-Board der CAN1_RX0_IRQHandler überhaupt mal > aufgerufen? Soweit ich weiß wird dieser Handler nicht aufgerufen. Auf die Gefahr hin, dass es eine dumme frage ist, frage ich trotzdem mal. Wie genau, bzw. warum soll ich denn den CAN1_RX0_IRQHandler aufrufen?
1 | void RxIntEnable(CAN_HandleTypeDef *CanHandle) { |
2 | if(CanHandle->State == HAL_CAN_STATE_BUSY_TX){ |
3 | CanHandle->State = HAL_CAN_STATE_BUSY_TX_RX1; |
4 | |
5 | }else { |
6 | CanHandle->State = HAL_CAN_STATE_BUSY_RX1; |
7 | |
8 | /* Set CAN error code to none */
|
9 | CanHandle->ErrorCode = HAL_CAN_ERROR_NONE; |
10 | |
11 | /* Enable Error warning Interrupt */
|
12 | __HAL_CAN_ENABLE_IT(CanHandle, CAN_IT_EWG); |
13 | |
14 | /* Enable Error passive Interrupt */
|
15 | __HAL_CAN_ENABLE_IT(CanHandle, CAN_IT_EPV); |
16 | |
17 | /* Enable Bus-off Interrupt */
|
18 | __HAL_CAN_ENABLE_IT(CanHandle, CAN_IT_BOF); |
19 | |
20 | /* Enable Last error code Interrupt */
|
21 | __HAL_CAN_ENABLE_IT(CanHandle, CAN_IT_LEC); |
22 | |
23 | /* Enable Error Interrupt */
|
24 | __HAL_CAN_ENABLE_IT(CanHandle, CAN_IT_ERR); |
25 | }
|
26 | |
27 | // Enable FIFO 0 message pending Interrupt
|
28 | __HAL_CAN_ENABLE_IT(CanHandle, CAN_IT_FMP0); |
29 | }
|
Diese Routine habe ich mehr oder weniger blind übernommen aus eine YouTube Video. Dort sollen "manuell" die Interrupt Flags gesetzt werden, weil es ansonsten scheinbar Problenme mit der Cube Libary gibt. Vielleicht liegt dort auch der Fehler. in der _hal_can.h sind die HAL_CAN_STATE's "definiert". Danke für eure Zeit!
Okay kleine Edit, ich bin davon ausgegangen, dass ich die Rx Spannung über den Spannungsteiler halbieren muss. Jetzt ist mir aufgefallen, dass der Transceiver eine andere Spannung ausgibt, als die von der ich ausgegangen bin. Long Story short, ich habe mir den Spannungsteiler gespart und es findet eine Übertragung statt. Zwar ist diese noch irgendwo fehlerhaft aber das ist hoffentlich ein lösbares Problem. Ich bedanke mich für eure Ratschläge!
:
Bearbeitet durch User
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.