STM32 CAN Botschaft empfangen

Gast #6150395
Lesenswert?

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
Angehängte Dateien:
Gast #6150406
Lesenswert?

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?
Gast #6150419
Lesenswert?

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
Gast #6150424
Lesenswert?

>>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.
Gast #6150433
Lesenswert?

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
Gast #6150461
Lesenswert?

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.
Gast #6150647
Lesenswert?

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.
Gast #6150669
Lesenswert?

>>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.
Gast #6151374
Lesenswert?

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
Gast #6151478
Lesenswert?

>>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
Gast #6151495
Lesenswert?

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
Gast #6151659
Lesenswert?

>>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.
#6151662
Lesenswert?

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.
#6233007
Lesenswert?

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!
Angehängte Dateien:
#6233153
Lesenswert?

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!
#6233191
Lesenswert?

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"
#6233202
Lesenswert?

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.
#6233589
Lesenswert?

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.
#6233688
Lesenswert?

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.
#6233709
Lesenswert?

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.
Angehängte Dateien:
#6233744
Lesenswert?

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.
#6233972
Lesenswert?

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!
Angehängte Dateien:
#6234114
Lesenswert?

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!

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren