Forum: Mikrocontroller und Digitale Elektronik STM32 CAN Botschaft empfangen


von Jens (Gast)


Angehängte Dateien:

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

von Stefan F. (Gast)


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?

von Jens (Gast)


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

von Pieter (Gast)


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.

von Stefan F. (Gast)


Lesenswert?

Jens schrieb:
> der Code hängt doch an im ersten Post?

Oha, ja jetzt sehe ich ihn auch. Komisch.

von Jens (Gast)


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

von Pieter (Gast)


Lesenswert?

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.

von Jens (Gast)


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.

von Stefan F. (Gast)


Lesenswert?

Jens schrieb:
> und dann?

Das weißt du, dass dieser Teil der Software funktioniert. Erst danach 
baut man die Verarbeitung der Daten oben drauf.

von Johannes S. (Gast)


Lesenswert?

Mit Mbed sieht das etwas einfacher aus:
https://os.mbed.com/docs/mbed-os/v5.15/apis/can.html

von CK (Gast)


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.

von Pieter (Gast)


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.

von CK (Gast)


Lesenswert?

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.

von Jens (Gast)


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

von Stefan F. (Gast)


Lesenswert?

Jens schrieb:
> Wie kann ich den Wert des Registers auslesen?

variable = registername;

uint32_t r=CAN->RF0R;

von Jens (Gast)


Lesenswert?

Stefan ⛄ F. schrieb:
> uint32_t r=CAN->RF0R;

Danke!

Da steht eine saubere 0 drin :(. Ausgelesen über den ST-LinkV2 im Debug 
Modus.

von Jens (Gast)


Angehängte Dateien:

Lesenswert?

Hier noch ein Bild vom Oszi, direkt gemessen am PIN A11.

Das passt aus meiner Sicht.

VG Jens

von Pieter (Gast)


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

von Jens (Gast)


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

von Pieter (Gast)


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.

von Rainer B. (katastrophenheinz)


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.

von Philipp V. (brain_pain)


Lesenswert?

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.

von Philipp V. (brain_pain)


Angehängte Dateien:

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!

von Dominic (Gast)


Lesenswert?

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.

von Dominic (Gast)


Lesenswert?

*Und nutze fürs Erste

von Stefan F. (Gast)


Lesenswert?

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.

von Philipp V. (brain_pain)


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!

von Rainer B. (katastrophenheinz)


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"

von Rainer B. (katastrophenheinz)


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.

von Domenik (dodome)


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.

von Rainer B. (katastrophenheinz)


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.

von Philipp V. (brain_pain)


Angehängte Dateien:

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.

von Rainer B. (katastrophenheinz)


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.

: Bearbeitet durch User
von Philipp V. (brain_pain)


Angehängte Dateien:

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!

von Philipp V. (brain_pain)


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!

: 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
Noch kein Account? Hier anmelden.