Forum: Mikrocontroller und Digitale Elektronik Arduino Blue Pill & CAN mit SN65HVD230


von Kay L. (kgbrus)


Lesenswert?

Hallo und guten Tag zusammen,

ich hoffe Ihr könnt mir helfen, nachdem das in diversen Arduino Foren 
nicht wirklich funktioniert hat.
Ich bin auf der Suche nach entweder jemandem, der ein Arduino Blue Pill 
(STM32F103) und SN65HVD230 für CAN Bus mittels in der Arduino IDE 
programmiert hat, oder ein (wenn möglich deutschsprachiges) Tutorial 
dazu. Gefunden dazu hab ich ein Video eines nuschelnden Spaniers der 
versucht englisch zu sprechen.. ;-)

ich bin auf der Suche nach Hilfe zur Selbsthilfe es soll mir keiner 
einen Sketch schreiben. Wenn jemand etwas fertiges lauffähiges zu dem 
Thema hat, was vernünftig kommentiert ist, würde mir das als Grundlage 
auf der ich aufbauen kann weiterhelfen.

Mein Projekt ist die Steuerung einer analogen Modelleisenbahn. Teile der 
Steuerung (wie zB die Steuerung des Schattenbahnhofes) habe ich fertig. 
Ich möchte nur den Zustand von ein paar Variablen via CAN von einem 
Arduino zum anderen schicken. ZB (Lichtschranke 1 = High)

Gruß

Kay

: Verschoben durch Moderator
von Sebastian (Gast)


Lesenswert?

Bluepill leider nein. Bei AVR und Teensy 3/4 habe ich gute Erfahrungen 
mit den ACAN-Bibliotheken von Pierre Molinaro gemacht. Wo hakt es denn?

LG, Sebastian

von Kay L. (kgbrus)


Lesenswert?

Es hakt überall :-)

Das ist ja das Problem. Die absoluten Basics des CAN sind mir so 
halbwegs klar, aber in dem beispielsketch den ich bei Github gefunden 
habe:
https://github.com/nopnop2002/Arduino-STM32-CAN/blob/master/stm32f103/stm32f103.ino

Komme ich keinen schritt weiter, da steige ich nicht durch.  Das mag 
auch am Englisch oder der für einen Laien nicht ausreichenden 
kommentierung liegen.

Zu meinem Hintergrund ich programiere erst seit 2 Jahren, komme aber aus 
der Elektronic... Wohl noch analog :-)

Zu meinen Programierkenntnissen:
Umgesetzt habe ich bis dato:
1. Steuerung des Schattenbahnhofes mit 5 Gleisen (Suche freies Gleis, 
fahren des Zuges bis zum Haltepunkt, schalten der Weichen usw.
2. Geschwindigkeits mess und Regelung (mit LCD)
3. Totman box, die Verhindert das die Bahn tagelang im Keller unter 
strom steht (mit LCD)
4. Schweisslicht
5. Gleisstatusanzeige mit LCD
und ein paar andere Kleinigkeiten
Alles als State Maschine mit Übergang also mit aktualState und 
nextState.

Habe mir das alles selber bei gebracht, aber für den CAN Bus fehlen mir 
wohl noch jede Menge Basics. Deshalb wäre ein Tutorial wie dieses: 
https://www.fh-bielefeld.de/medienportal/video/13B1-Aufzugtuer-als-endlicher-Automat-in-C/36538450aeaa04af71bc17b2ae9617d0 
(damit hab ich die State Maschine verstanden) nur halt für CAN äusserst 
hilfreich. Alternativ würde auch ein sehr gut kommentierter Code reichen 
der eine Variable übergibt. Denn könnte ich mir dann mittels try and 
error erklären. Dafür ist  der Code von Github aber zu komplex

Gruß

Kay

von Pieter (Gast)


Lesenswert?

moin,

in Zusammenfassung: CAN ist einfacher als I2C!
Was verwirrend ist, sind die Filter und Masken. Meist braucht man die 
aber gar nicht.
Was ist an dem code unklar?
>>https://github.com/nopnop2002/Arduino-STM32-CAN/blob/master/stm32f103/stm32f103.ino

VG
Pieter

von H. (Gast)


Lesenswert?

Kay L. schrieb:
> Komme ich keinen schritt weiter, da steige ich nicht durch.  Das mag
> auch am Englisch oder der für einen Laien nicht ausreichenden
> kommentierung liegen.

In dem Github-Code ist Treiber und Beispiel alles in einem Sourcefile 
verwurstet. Das ist für das erste Verständnis auch maximal ungünstig. 
Besser wäre eine abgekapselte Lib, die einfach nur den can_write, 
can_read und die grundlegende CAN-Struktur mit Id, Len und Data[8] zur 
Verfügung stellt.

Wichtig ist auch, dass man nicht unbedingt nur seine beiden 
CAN-Teilnehmer vor sich liegen hat, dessen Code man selber erstellt hat. 
Besser man hat ein CAN-Analyzer mit angeschlossen, dem man vertraut und 
einem anzeigt, was gerade auf dem Bus vor sich geht.
So ein CAN-Analyzer kann etwas von Peak sein (evtl. etwas teuer für 
Hobby), etwas von fischl.de oder auch einfach nur ein Logik-Analyzer von 
Amazon für <10€. Der LA hat den Nachteil, dass er keine Live-View 
bietet. Gibt auch noch weitere CAN-Werkzeuge für kleines Geld, einfach 
mal stöbern.

Bleibe dran, es lohnt sich! CAN ist zwar schon uralt, aber eine schöne 
Methode, damit sich verschiedene Teilnehmer Botschaften zuschieben 
können, ohne an Bustimings gebunden zu sein.

von Frank K. (fchk)


Lesenswert?

Kay L. schrieb:
> ich hoffe Ihr könnt mir helfen, nachdem das in diversen Arduino Foren
> nicht wirklich funktioniert hat.
> Ich bin auf der Suche nach entweder jemandem, der ein Arduino Blue Pill
> (STM32F103) und SN65HVD230 für CAN Bus mittels in der Arduino IDE
> programmiert hat, oder ein (wenn möglich deutschsprachiges) Tutorial
> dazu.

Bei Deinem STM32F103 kannst Du entweder USB oder CAN verwendet, nicht 
beides zusammen. Erstens liegen die Signale auf den gleichen Pins, und 
zweitens verwenden beide Peripherieeinheiten das gleiche Dual-Port-RAM.

Erste Empfehlung: keinen F103 nehmen, sondern einen F302 oder F303. Die 
haben das Problem nicht.
Zweite Empfehlung, wenn das Kind schon ganz tief im Brunnen steckt: 
Schauen, ob Du für Dein konkretes Board einen Schaltplan bekommst. Wenn 
da USB drauf ist, dann alles, was damit zu tut hat, runternehmen. 
Überprüfen, ob PA11/PA12 tatsächlich mit der Stiftleiste verbunden sind. 
In der Software alles, was mit USB zu tun hat, rauswerfen.

Dann könnte es gehen.

Es ist halt blöd, dass noch so altes Zeugs verkauft und verwendet wird. 
Blöde Anfängerfalle.

fchk

: Bearbeitet durch User
von Kay L. (kgbrus)


Lesenswert?

Frank K. schrieb:
> Kay L. schrieb:
>> ich hoffe Ihr könnt mir helfen, nachdem das in diversen Arduino Foren
>> nicht wirklich funktioniert hat.
>> Ich bin auf der Suche nach entweder jemandem, der ein Arduino Blue Pill
>> (STM32F103) und SN65HVD230 für CAN Bus mittels in der Arduino IDE
>> programmiert hat, oder ein (wenn möglich deutschsprachiges) Tutorial
>> dazu.
>
> Bei Deinem STM32F103 kannst Du entweder USB oder CAN verwendet, nicht
> beides zusammen. Erstens liegen die Signale auf den gleichen Pins, und
> zweitens verwenden beide Peripherieeinheiten das gleiche Dual-Port-RAM.
>
> Erste Empfehlung: keinen F103 nehmen, sondern einen F302 oder F303. Die
> haben das Problem nicht.
> Zweite Empfehlung, wenn das Kind schon ganz tief im Brunnen steckt:
> Schauen, ob Du für Dein konkretes Board einen Schaltplan bekommst. Wenn
> da USB drauf ist, dann alles, was damit zu tut hat, runternehmen.
> Überprüfen, ob PA11/PA12 tatsächlich mit der Stiftleiste verbunden sind.
> In der Software alles, was mit USB zu tun hat, rauswerfen.
>
> Dann könnte es gehen.
>
> Es ist halt blöd, dass noch so altes Zeugs verkauft und verwendet wird.
> Blöde Anfängerfalle.
>
> fchk

Hallo Frank,

ich verstehe gerade deinen Post nicht, ich möchte USB gar nicht nutzen. 
Selbst das programieren des Arduinos mache ich direkt, also über STLink 
utility.


Gruß

Kay

von Frank K. (fchk)


Lesenswert?

Kay L. schrieb:

> ich verstehe gerade deinen Post nicht, ich möchte USB gar nicht nutzen.

Ist auf Deinem Bluepill Board denn ein USB-Anschluss drauf? Auch wenn 
der nicht benutzt wird. Wenn ja, dann wird der die gleichen Pins 
(PA11/PA12) benutzen, die der CAN verwendet. Genau diese 
Doppelbeschaltung kann zu Problemen führen.

Was mir noch einfallt: Ist das denn wirklich ein originaler Chip von ST? 
Die STM32F103 sind mit die am häufigsten gecloneten Chips überhaupt - da 
gibt es wesentlich mehr Kopien als Originale. Auch der Aufdruck ist of 
gefälscht.

Die STM32F30x sind von der Clonerei noch nicht so betroffen, obwohl es 
auch da Nachbauten gibt. Und die Nachbauten sind nicht immer überall 1:1 
kompatibel.

fchk

von Kay L. (kgbrus)


Lesenswert?

Pieter schrieb:
> moin,
>
> in Zusammenfassung: CAN ist einfacher als I2C!
> Was verwirrend ist, sind die Filter und Masken. Meist braucht man die
> aber gar nicht.
> Was ist an dem code unklar?
>>>https://github.com/nopnop2002/Arduino-STM32-CAN/blob/master/stm32f103/stm32f103.ino
>
> VG
> Pieter

So ziemlich alles ;-) vor allem der ist ziemlich lang. Wir ist auch 
nicht klar warum der verschiedene Bitraten zulässt, fehlermeldung für 
eine falsche Bitrate auswirft usw.
Das dies für die saubere Programierung und den sauberen stabilen Betrieb 
notwendig ist, ist mir natürlich klar, für den Einstieg aber nur maximal 
verwirrend

Eine Sketch zB der Via CAN einfach nur den Zustand einer Variable mit 
festgelegter Bitrate an einen anderen übermittelt, ohne hätte, sollte, 
könnte, vielleicht wäre für mich der ideale Einstieg.
Da könnte ich dann sehen, ah es läuft, dann ändere ich den Zustand der 
Variable die ich sende und sehe "ach da und in der Form wird der Zustand 
übertragen" dann "ach da wird der Name in der Form der variablen 
übertragen" ach da syncronisiere ich die Bitrate" usw usw.
Oder halt ein Video die CAN für Dummies erklärt ;-)

Ich muß auch nicht so tief gehen wenn es eine einfache Libery wie zB für 
die Character LCD´s gibt wäre mir das noch lieber.
ich mache ja keine Raketentechnik nur eine Modelleisenbahn, da ist es 
nicht schlimm wenn mal was schief läuft.


Gruß

Kay

von Thomas F. (igel)


Lesenswert?

Kay L. schrieb:
> Eine Sketch zB der Via CAN einfach nur den Zustand einer Variable mit
> festgelegter Bitrate an einen anderen übermittelt

Du musst ja auch nicht den kompletten Code verstehen. Wenn er 
funktioniert - ich habe es nicht getestet - reicht der Teil ab Zeile 
522.
Als erstes muss man natürlich den CAN mal einschalten:
1
void setup() {
2
  Serial.begin(115200);
3
  bool ret = CANInit(CAN_500KBPS, 2);  // CAN_RX to PB8, CAN_TX to PB9
4
  if (!ret) while(true);
5
}

Und dann ein einfaches Senden:
1
void loop() {
2
  CAN_msg_t CAN_TX_msg;
3
4
  CAN_TX_msg.data[0] = 0x00;
5
  CAN_TX_msg.data[1] = 0x01;
6
  CAN_TX_msg.data[2] = 0x02;
7
  CAN_TX_msg.len = 3;  // Länge der Botschaft: 3 Bytes
8
9
  CAN_TX_msg.type = DATA_FRAME;
10
  CAN_TX_msg.id = 0x123;
11
12
  CANSend(&CAN_TX_msg);
13
14
  Delay(1000);
15
  }
Wie gesagt: ungetestet, aber in etwa so läufts.

von Kay L. (kgbrus)


Lesenswert?

Thomas F. schrieb:
> Kay L. schrieb:
>> Eine Sketch zB der Via CAN einfach nur den Zustand einer Variable mit
>> festgelegter Bitrate an einen anderen übermittelt
>
> Du musst ja auch nicht den kompletten Code verstehen. Wenn er
> funktioniert - ich habe es nicht getestet - reicht der Teil ab Zeile
> 522.
> Als erstes muss man natürlich den CAN mal einschalten:
>
>
1
> void setup() {
2
>   Serial.begin(115200);
3
>   bool ret = CANInit(CAN_500KBPS, 2);  // CAN_RX to PB8, CAN_TX to PB9
4
>   if (!ret) while(true);
5
> }
6
>
>
> Und dann ein einfaches Senden:
>
>
1
> void loop() {
2
>   CAN_msg_t CAN_TX_msg;
3
> 
4
>   CAN_TX_msg.data[0] = 0x00;
5
>   CAN_TX_msg.data[1] = 0x01;
6
>   CAN_TX_msg.data[2] = 0x02;
7
>   CAN_TX_msg.len = 3;  // Länge der Botschaft: 3 Bytes
8
> 
9
>   CAN_TX_msg.type = DATA_FRAME;
10
>   CAN_TX_msg.id = 0x123;
11
> 
12
>   CANSend(&CAN_TX_msg);
13
> 
14
>   Delay(1000);
15
>   }
16
>
> Wie gesagt: ungetestet, aber in etwa so läufts.
Erstmal vielen lieben Dank!! ich suche schon seit Monaten in den Arduino 
Foren....

Mal sehen ob ich das bis dato gelesene auch richtig Verstanden habe.

Auf der Empängerseite mus ich das auch so einfügen nur anstelle von TX 
(Transiver) RX (Receiver) einsetzten?

Zum Sketch
1
CAN_msg_t CAN_TX_msg;  
2
// Beutet für den STM ab hier startet eine CAN Message als Sender
3
4
CAN_TX_msg.data[0] = 0x00;
5
// Bedeutet Datenbits 1 -3  aber was bedeutet "0x00"? 
6
 CAN_TX_msg.len = 3;  
7
// Länge der Botschaft: 3 Bytes (selbsterklärend)
8
 CAN_TX_msg.type = DATA_FRAME;  
9
// Hier weis ich nicht so genau was das ist?
10
CAN_TX_msg.id = 0x123; 
11
// Der "Name" der Botschaft, damit der Empfänger die für Ihn bestimme Botschaft auch findet. aber was ist 0x123 (sind die 0x123 usw ev nur Platzhalter?
12
CANSend(&CAN_TX_msg); 
13
// "Sendebefehl das die Mitteilung jetzt gesendet wird
Ich hoffe das stimmt so halbwegs? und meine Fragen sind nicht komplett 
doof

Gruß

Kay

von Thomas F. (igel)


Lesenswert?

Kay L. schrieb:
1
CAN_TX_msg.data[0] = 0x00;
2
// Bedeutet Datenbits 1 -3  aber was bedeutet "0x00"?

Dir ist der Ausdruck "0x00" unbekannt? Das sind jetzt aber absolute 
Anfänger-Grundlagen: 0x steht für die Hex-Schreibweise einer Zahl. 0x00 
ist einfach 0. 0x0A ist 10.
1
CAN_TX_msg.id = 0x123; 
2
// Der "Name" der Botschaft, damit der Empfänger die für Ihn bestimme Botschaft auch findet. aber was ist 0x123 (sind die 0x123 usw ev nur Platzhalter?

Siehe oben: Hexadezimale Schreibweise.
Ich fürchte du solltest dich erst noch mal mit den Grundlagen befassen.

von Kay L. (kgbrus)


Lesenswert?

Sorry da stand ich auf dem Schlauch.. Ich war schon bei Hexadezimal, nur 
hatte ich die zweistellig vor Augen... Das 0x vorne als Bescheibung für 
die Hexadezimalzahl hatte ich nicht mehr auf dem Schirm...

von erklehr behr (Gast)


Lesenswert?

Frank K. schrieb:
> Wenn ja, dann wird der die gleichen Pins
> (PA11/PA12) benutzen, die der CAN verwendet. Genau diese
> Doppelbeschaltung kann zu Problemen führen.

Was wird denn hier wieder für Käse-Information verbreitet?

Ein F103 kann das CAN Interface entweder auf PA11/PA12 oder
auf PB8/PB9 konfiguriert haben.

Einfach mal ins Datenblatt schauen oder CubeMX über sich
ergehen lassen .....

von Kay L. (kgbrus)



Lesenswert?

Frank K. schrieb:
> Kay L. schrieb:
>
>> ich verstehe gerade deinen Post nicht, ich möchte USB gar nicht nutzen.
>
> Ist auf Deinem Bluepill Board denn ein USB-Anschluss drauf? Auch wenn
> der nicht benutzt wird. Wenn ja, dann wird der die gleichen Pins
> (PA11/PA12) benutzen, die der CAN verwendet. Genau diese
> Doppelbeschaltung kann zu Problemen führen.
>
> Was mir noch einfallt: Ist das denn wirklich ein originaler Chip von ST?
> Die STM32F103 sind mit die am häufigsten gecloneten Chips überhaupt - da
> gibt es wesentlich mehr Kopien als Originale. Auch der Aufdruck ist of
> gefälscht.
>
> Die STM32F30x sind von der Clonerei noch nicht so betroffen, obwohl es
> auch da Nachbauten gibt. Und die Nachbauten sind nicht immer überall 1:1
> kompatibel.
>
> fchk

Sorry hatte deine Post übersehen. Ja USB ist drauf, um den USB zur 
Programierung zu nutzen muss man vorher mittels eines FTDI Adapters 
einen Bootloader aufspielen. Da ich ja über STLink Programiere, spiele 
ich keinen Bootloader auf und in der Arduino IDE nutze ich auch kein 
USB. Eine doppelnutzung kann also nicht vorkommen.
Mir ist auch bewusst das die 103er oft gefaked werden. Ich hatte sogar 
schon mal welche, da hab ich mich tot gesucht, warum die sich nicht 
programieren lassen. Irgendwann bin ich dann mal darauf gekommen mir die 
Chips genauer anzusehen und siehe da, kein ST Logo drauf.

Das ist der Arduino Blue Pill:
https://www.az-delivery.de/products/stm32f103c8t6

ich weiß jetzt auch nicht ob es einen anderen ST32 als "Arduino" gibt.

Ich hab mal die Scematics von dem teil angehangen. Ich hoffe, das ist 
OK?

von erklehr behr (Gast)


Lesenswert?

Kay L. schrieb:
> Sorry hatte deine Post übersehen.

Meinen Beitrag hast du auch wohl auch übersehen.

Kay L. schrieb:
> Ich hab mal die Scematics von dem teil angehangen.

Nein, du hast ihn angehängt. Oder sagst du auch du hast etwas
eingekaufen, du hast etwas aufgemalen, du hast etwas eingelöten?

von Kay L. (kgbrus)


Lesenswert?

erklehr behr schrieb:
> Kay L. schrieb:
>> Sorry hatte deine Post übersehen.
>
> Meinen Beitrag hast du auch wohl auch übersehen.
>
> Kay L. schrieb:
>> Ich hab mal die Scematics von dem teil angehangen.
>
> Nein, du hast ihn angehängt. Oder sagst du auch du hast etwas
> eingekaufen, du hast etwas aufgemalen, du hast etwas eingelöten?

Trägt dieser Post etwas zur Lösung meiner Fragestellung bei?

von C.K. (Gast)


Lesenswert?

Kay L. schrieb:
> Das ist der Arduino Blue Pill:
> https://www.az-delivery.de/products/stm32f103c8t6

AZ-Delivery verkauft schon lange keine BluePills mehr mit einem 
Originalen STM32. Sind immer nur mehr oder weniger kompatible 
Nachbauten. Meist von CKS oder GD



Schau doch mal genau, was für eine Bezeichnung auf dem Chip steht.

Schau dir mal die Referenz Bilder an.

Die Klone fangen vorne nicht mit

"STM" https://www.richis-lab.de/STM32_02.htm

sondern z.B. mit

"CKS" https://www.richis-lab.de/STM32_03.htm

"APM" https://www.richis-lab.de/STM32_05.htm

"GD" https://www.richis-lab.de/STM32_06.htm / 
https://www.richis-lab.de/STM32_10.htm

"MM" https://www.richis-lab.de/STM32_07.htm

"BLM" https://www.richis-lab.de/STM32_08.htm

"HK" https://www.richis-lab.de/STM32_09.htm

an.

Oder es können Fakes sein, wo zwar STM drauf steht, aber kein STM drin 
ist
https://www.richis-lab.de/STM32_01.htm / 
https://www.richis-lab.de/STM32_04.htm

von Stefan F. (Gast)


Lesenswert?

Kay L. schrieb:
> Das ist der Arduino Blue Pill...
> ich weiß jetzt auch nicht ob es einen anderen ST32 als "Arduino" gibt.

Es hat noch nie ein echtes "Arduino Blue Pill" Board gegeben. Das 
LeafLabs Maple Mini Board kommt dem noch am nächsten, aber auch das war 
nie ein originales Arduino Board. Beide Boards wurden nicht von Arduino 
designt und die zugehörige Software kommt auch nicht von Arduino.

Wenn du etwas besseres mit ähnlichem Format haben willst, dann nimm ein 
Nucleo32 Board von ST. Das kannst du auch mit der Arduino IDE 
programmieren und die entsprechende Software 
(https://github.com/stm32duino/Arduino_Core_STM32) kommt direkt vom 
Chiphersteller ST.

von Sebastian W. (wangnick)


Lesenswert?

Thomas F. schrieb:
1
CAN_TX_msg.type = DATA_FRAME;
2
CAN_TX_msg.id = 0x123;
3
CANSend(&CAN_TX_msg);

Ich glaube, da sollte besser noch ein
1
CAN_TX_msg.format = STANDARD_FORMAT;
vor das CANSend().

Kay L. schrieb:
> Auf der Empängerseite mus ich das auch so einfügen nur anstelle von TX
> (Transiver) RX (Receiver) einsetzten?

TX steht für Transmitter. Und nein, du solltest vor dem Aufruf von 
CANReceive(&CAN_RX_msg) mit CANMsgAvail() prüfen, ob überhaupt eine 
CAN-Nachricht empfangen wurde.

In der loop()-Routine des stm32f103.ino werden regelmäßig zwei 
verschiedene CAN-Nachrichten gesendet, und dann werden auch alle 
CAN-Nachrichten empfangen und ausgegeben. Nimm das doch als ersten 
Versuch.

LG, Sebastian

von Kay L. (kgbrus)


Lesenswert?

Sebastian W. schrieb:
> Thomas F. schrieb:
>
1
> CAN_TX_msg.type = DATA_FRAME;
2
> CAN_TX_msg.id = 0x123;
3
> CANSend(&CAN_TX_msg);
4
>
>
> Ich glaube, da sollte besser noch ein
>
1
> CAN_TX_msg.format = STANDARD_FORMAT;
2
>
> vor das CANSend().
>
> Kay L. schrieb:
>> Auf der Empängerseite mus ich das auch so einfügen nur anstelle von TX
>> (Transiver) RX (Receiver) einsetzten?
>
> TX steht für Transmitter. Und nein, du solltest vor dem Aufruf von
> CANReceive(&CAN_RX_msg) mit CANMsgAvail() prüfen, ob überhaupt eine
> CAN-Nachricht empfangen wurde.
>
> In der loop()-Routine des stm32f103.ino werden regelmäßig zwei
> verschiedene CAN-Nachrichten gesendet, und dann werden auch alle
> CAN-Nachrichten empfangen und ausgegeben. Nimm das doch als ersten
> Versuch.
>
> LG, Sebastian


Vielen lieben Dank dafür, damit kann ich etwas anfangen.
Verstehe ich das richtig, das ich die info die ich übertragen will (zB 
StatusLS1 = true)

in die canTX.msg umwandeln muß?
1
 void loop() {
2
>   CAN_msg_t CAN_TX_msg;
3
>  if (StatusLS1 = true)
4
{
5
>   CAN_TX_msg.data[0] = 0x00; // Status LS1 = true
6
>   CAN_TX_msg.data[1] = 0x01;
7
>   CAN_TX_msg.data[2] = 0x02;
8
>   CAN_TX_msg.len = 3;  // Länge der Botschaft: 3 Bytes
9
> }
10
> else 
11
{
12
>  CAN_TX_msg.data[0] = 0x01; // Status LS1 = false
13
>   CAN_TX_msg.data[1] = 0x01;
14
>   CAN_TX_msg.data[2] = 0x02;
15
>   CAN_TX_msg.len = 3;  // Länge der Botschaft: 3 Bytes
16
}
17
>
18
>   CAN_TX_msg.type = DATA_FRAME;
19
>   CAN_TX_msg.id = 0x123;
20
> 
21
>   CANSend(&CAN_TX_msg);
22
> 
23
>   Delay(1000);
24
>   }

: Bearbeitet durch User
von Peter* (Gast)


Lesenswert?

Hallo,

vielleicht habe den Sinn nicht verstanden, aber warum nimmst Du nicht 
einfach eine fertige Can-Bus Platine mit Controller 2515?

Oder soll es eine persönliche Herausforderung sein, nicht den normalen 
Weg über gute Programme wie schon erwähnt ACAN2515, MCP_Can usw.... zu 
gehen?

von Sebastian (Gast)


Lesenswert?

Kay L. schrieb:
> das ich die info die ich übertragen will (zB StatusLS1 = true)
> in die canTX.msg umwandeln muß

Ja. Vielleicht besser nicht so umständlich, aber ja.

LG, Sebastian

von Kay L. (kgbrus)


Lesenswert?

Peter* schrieb:
> Hallo,
>
> vielleicht habe den Sinn nicht verstanden, aber warum nimmst Du nicht
> einfach eine fertige Can-Bus Platine mit Controller 2515?
>
> Oder soll es eine persönliche Herausforderung sein, nicht den normalen
> Weg über gute Programme wie schon erwähnt ACAN2515, MCP_Can usw.... zu
> gehen?

Hallo Peter,
Der STM32F1 stellt ja den CAN BUS zur verfügung, also warum den Umweg 
über Umwandeln gehen? Der 2525 Wandelt ja das CAN in ein SPI Signal um.

Nun ja der "normale Weg" ist wohl eher das vorhandene CAN ohne Umwandler 
zu nutzen. Nur weil es viele anders machen muß es ja nicht der normale 
sein :-)

Die Herausforderung dabei ist meine Konstellation:
1. ich bin blutiger Anfänger
2. Den Blue Pill mit STM32F1 nutzen nicht viele (wie man auch hier im 
Fred ja schon sieht ist der eher verpöhnt)
3. Den CAN Bus darauf noch entsprechend weniger.

Auch habe ich meine Baseboards für die Nutzung von CAN vorgesehen.

Zu guter letzt, ja mittlerweile ist es etwas persönliches zwischen mir 
und dem CAN Bus :-)


Gruß

Kay

von Kay L. (kgbrus)


Lesenswert?

Sebastian schrieb:
> Kay L. schrieb:
>> das ich die info die ich übertragen will (zB StatusLS1 = true)
>> in die canTX.msg umwandeln muß
>
> Ja. Vielleicht besser nicht so umständlich, aber ja.
>
> LG, Sebastian

Hallo Sebastian,

vielen lieben Dank! Jetzt weiß ich wo ich ansetzten muß!

Auch an alle anderen die etwas zur Lösung und damit das ich einen Ansatz 
habe beigetragen haben

Gruß


Kay

von Sebastian (Gast)


Lesenswert?

Kay L. schrieb:
> Auch an alle anderen die etwas zur Lösung und damit das ich einen Ansatz
> habe beigetragen haben

Ein Oszilloskop und ein Logikanalysator könnten im weiteren Verlauf 
hilfreich sein. Tip: Schließe einen SN65HVD230 am CAN-Bus an, versorge 
ihn, und häng den Logikanalysator an seinen RX-Pin. So kannst du passiv 
den Bus beobachten

LG, Sebastian

von Kay L. (kgbrus)


Lesenswert?

Sebastian schrieb:
> Kay L. schrieb:
>> Auch an alle anderen die etwas zur Lösung und damit das ich einen Ansatz
>> habe beigetragen haben
>
> Ein Oszilloskop und ein Logikanalysator könnten im weiteren Verlauf
> hilfreich sein. Tip: Schließe einen SN65HVD230 am CAN-Bus an, versorge
> ihn, und häng den Logikanalysator an seinen RX-Pin. So kannst du passiv
> den Bus beobachten
>
> LG, Sebastian

Ja mache ich Dankeschön.

von Steve van de Grens (roehrmond)


Lesenswert?

Kay L. schrieb:
> Den Blue Pill mit STM32F1 nutzen nicht viele

Nicht mehr. Vor 2000 war das ein sehr beliebtes Board, deswegen haben 
viele Bastler damit Erfahrung.

von Thomas F. (igel)


Lesenswert?

Kay L. schrieb:
> Vielen lieben Dank dafür, damit kann ich etwas anfangen.
> Verstehe ich das richtig, das ich die info die ich übertragen will (zB
> StatusLS1 = true)
>
> in die canTX.msg umwandeln muß?

canTX_msg ist ein struct.
Das struct beinhaltet unter anderem die Datenbytes der zu sendenden 
Botschaft.
Eine CAN-Botschaft kann zwischen 0 und 8 Datenbytes enthalten.
Willst du lediglich ein Statusbit übertragen dann musst du min. 1 
Datenbyte senden:
1
  CAN_TX_msg.data[0] = StatusLS1;
2
  CAN_TX_msg.len = 1;  // Länge der Botschaft: 1 Bytes
3
  CAN_TX_msg.id = 0x123; // Identifier der Botschaft
4
5
  // und nun ab damit...
6
  CANSend(&CAN_TX_msg);

von Peter* (Gast)


Lesenswert?

Hallo,

Kay L. schrieb:
> Nun ja der "normale Weg" ist wohl eher das vorhandene CAN ohne Umwandler
> zu nutzen. Nur weil es viele anders machen muß es ja nicht der normale
> sein :-)

Über "normal" kann man sich streiten, aber es hängt doch meistens vom 
dem Faktor der Anzahl ab, die es so nutzen!!

Der Can_Controller MCp2515 ist kein Umwandler er nutz SPI und übernimmt 
die ganze Abwicklung des CanBus's und befreit den Prozessor von dieser 
Aufgabe, der sonst gebunden ist!! und evtl. so zusätzlich Speicherplatz 
belegt.

> 3. Den CAN Bus darauf noch entsprechend weniger.... dein handeln ist wohl so 
unlogisch oder :-)

Habe noch vor wenigen Jahren im Automotiv_bereich den CAN_Restbus (500k) 
mit dem BlusPill mit MCP2515 simuliert, selbst ein Arduino UNO reicht so 
aus.

verpönt ist dumm, aber ist inzwischen zu teuer geworden 2Euro hat er 
gekostet.

PI Pico W (6,99) mit ACAN

von Sebastian (Gast)


Lesenswert?

Peter* schrieb:
> PI Pico W (6,99) mit ACAN

Kann der RP2040 CAN?

LG, Sebastian

von Peter* (Gast)


Lesenswert?

Hallo,

ACAN steht für ACAN2515 oder auch ACAN2517/18 (Can 2.0B und FD)

NiRen, CANdiy-Shield V2

Pico ist momentan der Günstigste (Reichelt) und auch unter Arduino 
programmierbar.

von Tilo R. (joey5337) Benutzerseite


Lesenswert?

Sebastian schrieb:
> Peter* schrieb:
>> PI Pico W (6,99) mit ACAN
>
> Kann der RP2040 CAN?
>
> LG, Sebastian

Von Natur aus nicht, aber jemand hat es hinbekommen, mit dem PIO CAN-Bus 
zu emulieren:
https://github.com/KevinOConnor/can2040
´
Das habe ich allerdings bisher nicht selbst ausprobiert.

von Kay L. (kgbrus)


Lesenswert?

Hallo Zusammen,

ich habe nun den Code in einen Sketch geschrieben.  Für den CAN also nur 
das einschalten mappen des CANBusses
1
// --------------------------------------  Umbenenen der STM Pins
2
// Library
3
4
5
// Eingänge
6
7
// Taster
8
9
const int Taster = PB9;
10
int TasterState = 0;
11
12
13
// Ausgänge
14
15
const int LED = PA0;
16
void setup()
17
{
18
  pinMode(LED_BUILTIN, OUTPUT);  //LED auf Arduino auf HIGH
19
  // --------------------------------------  pinMode
20
  pinMode(Taster, INPUT);
21
  pinMode(LED, OUTPUT);
22
23
  // CAN aktivieren
24
25
  { 
26
Serial.begin(115200);
27
    bool ret = CANInit(CAN_500KBPS, 2);  // CAN_RX to PB8, CAN_TX to PB9
28
    if (!ret) while (true);
29
  }
30
}
31
void loop()
32
{
33
  TasterState = digitalRead(Taster);    // Taster abfragen
34
35
  if (TasterState == LOW)
36
  {
37
    digitalWrite(LED, HIGH);
38
  }
39
  else
40
  {
41
    digitalWrite(LED, LOW);
42
  }
43
44
}
Leider bekomme ich folgende Fehlermeldung:
C:\Users\Büro\privat\Eisenbahn\MCU_Program\Sketches\Testprogramme\CAN\CA 
N1_0\CAN1_0.ino:  In function 'void setup()':
CAN1_0:52:24: error: 'CAN_500KBPS' was not declared in this scope
CAN1_0:52:38: error: 'CANInit' was not declared in this scope
exit status 1
'CAN_500KBPS' was not declared in this scope

Er sieht CANinit usw anscheinend als undefinierte Variable....

Was hab ich vergessen?

Gruß

Kay

: Bearbeitet durch User
von mitlesa (Gast)


Lesenswert?

Kay L. schrieb:
> Was hab ich vergessen?

Ich tippe mal auf
1
#include <xxxxxx.h>

xxxxxx.h steht für den Namen deiner Header-Datei der Arduino
Lib die du verwendest bzw. verwenden willst.

Kay L. schrieb:
> Er sieht CANinit usw anscheinend als undefinierte Variable....

Nein, er sieht CANinit als ihm unbekannte Funktion.

von Sebastian W. (wangnick)


Lesenswert?

Kay L. schrieb:
> Was hab ich vergessen?

Du hast den ganzen Kram aus 
https://github.com/nopnop2002/Arduino-STM32-CAN/blob/master/stm32f103/stm32f103.ino 
vergessen.

Du musst diese stm32f103.ino in eine stm32f103.h und eine stm32f103.cpp 
zerlegen, in dein Sketch-Verzeichnis kopieren, und in deinem Sketch
1
#include "stm32f103.h"
dazufügen.

Die Datei stm32f103.h sollte so aussehen:
1
typedef enum {CAN_50KBPS, CAN_100KBPS, CAN_125KBPS, CAN_125KBPS32MHZ, CAN_125P1KBPS31P9MHZ,CAN_250KBPS, CAN_500KBPS, CAN_1000KBPS} BITRATE;
2
typedef enum {STANDARD_FORMAT = 0, EXTENDED_FORMAT} CAN_FORMAT;
3
typedef enum {DATA_FRAME = 0, REMOTE_FRAME}         CAN_FRAME;
4
5
typedef struct
6
{
7
  uint32_t id;        /* 29 bit identifier                               */
8
  uint8_t  data[8];   /* Data field                                      */
9
  uint8_t  len;       /* Length of data field in bytes                   */
10
  uint8_t  ch;        /* Object channel(Not use)                         */
11
  uint8_t  format;    /* 0 - STANDARD, 1- EXTENDED IDENTIFIER            */
12
  uint8_t  type;      /* 0 - DATA FRAME, 1 - REMOTE FRAME                */
13
} CAN_msg_t;
14
15
bool CANInit(BITRATE bitrate, int remap);
16
void CANReceive(CAN_msg_t* CAN_rx_msg);
17
void CANSend(CAN_msg_t* CAN_tx_msg);
18
uint8_t CANMsgAvail(void);

Die Datei stm32f103.cpp solle alles aus stm32f103.ino bis 
einschliesslich Zeile 502 enthalten. Allerdings solle der Anfang danach 
noch leicht abgeändert werden:
[code]
#include <Arduino.h>
#include "stm32f103.h"
[code]

Außerdem solltest du die Typdefinitionen, die schon in stm32f103.h sind, 
in stm32f103.cpp am Anfang noch löschen (also die enums BITRATE, 
CAN_FORMAT, CAN_FRAME und die struct CAN_msg_t).

Dann sollte dein Sketch übersetzen.

LG, Sebastian

: Bearbeitet durch User
von Kay L. (kgbrus)


Lesenswert?

Hallo Sebastian,

ok, dann hatte ich Frank s Post (09.02.2023 14:30) komplett falsch 
verstanden. Ich dachte ich bräuchte nur den kleinen Teil...
Auf ein neues.

Vielen Dank für eure Mühe

Gruß

Kay

von Sebastian W. (wangnick)


Angehängte Dateien:

Lesenswert?

Kay L. schrieb:
> ok, dann hatte ich Frank s Post (09.02.2023 14:30) komplett falsch
> verstanden. Ich dachte ich bräuchte nur den kleinen Teil...

Meinst du den Beitrag von Thomas? Thomas F. schrieb:
> Du musst ja auch nicht den kompletten Code verstehen. Wenn er
> funktioniert - ich habe es nicht getestet - reicht der Teil ab Zeile
> 522.

Er meinte wohl dass du den Code ausserhalb von loop() nicht verstehen 
musst, und dass es reicht den loop()-Teil für deine Zwecke anzupassen. 
Er meinte damit aber nicht dass du den Code vor setup () und loop() gar 
nicht brauchst.

Zumindest meine ich dass er das meinte.

Kay L. schrieb:
> Auf ein neues.

Ich habe mir, angeregt durch deine Experimente, kurzfristig ein 
Nucleo-F303K8-Board zugelegt. Alles was ich heute mittag geschrieben 
habe hatte ich vorher mit 
https://github.com/nopnop2002/Arduino-STM32-CAN/tree/master/stm32f303 
nachvollzogen. Bei mir läuft der CAN-Empfang auf dem STM32F303K8T6. Ich 
benutze allerdings einen TJA1050-Transceiver an PA11 und PA12 (die 
beiden Pins sind hoffentlich 5V-tolerant):
1
Standard ID: 0x206      DLC: 8 Data: 0x14 0x18 0x15 0x0 0xA 0x0 0x0 0x0
2
Standard ID: 0x249      DLC: 8 Data: 0x7B 0x22 0x74 0x6F 0x70 0x69 0x63 0x22
3
Standard ID: 0x249      DLC: 8 Data: 0x3A 0x22 0x77 0x61 0x74 0x74 0x22 0x2C
4
Standard ID: 0x249      DLC: 8 Data: 0x22 0x69 0x64 0x22 0x3A 0x31 0x32 0x38
5
Standard ID: 0x249      DLC: 8 Data: 0x30 0x39 0x2C 0x22 0x6E 0x6F 0x22 0x3A
6
Standard ID: 0x249      DLC: 7 Data: 0x9 0x0 0x25 0x41 0x46 0x0 0x1

Insofern: Nur Mut!

LG, Sebastian

von Thomas F. (igel)


Lesenswert?

Sebastian W. schrieb:
> Meinst du den Beitrag von Thomas? Thomas F. schrieb:
>> Du musst ja auch nicht den kompletten Code verstehen. Wenn er
>> funktioniert - ich habe es nicht getestet - reicht der Teil ab Zeile
>> 522.
>
> Er meinte wohl dass du den Code ausserhalb von loop() nicht verstehen
> musst, und dass es reicht den loop()-Teil für deine Zwecke anzupassen.
> Er meinte damit aber nicht dass du den Code vor setup () und loop() gar
> nicht brauchst.
>
> Zumindest meine ich dass er das meinte.

Genau das habe ich gemeint. :-)

Natürlich muss man die benötigten Code-Teile vor Zeile 522 auch mit in 
das Projekt übernehmen. Wie das geht hat ja Sebastian dankenswerter 
Weise beschrieben.

Ab Zeile 522 kannst du dann mit deinen eigenen Code herumwerkeln.

von Kay L. (kgbrus)


Lesenswert?

Hallo zusammen,

im sketch wir eine assert.h eingebunden.

ich bin aber zu blöd die zu finden.

Wo bekomme ich die her?

von Thomas F. (igel)


Lesenswert?

Kay L. schrieb:
> im sketch wir eine assert.h eingebunden.
>
> ich bin aber zu blöd die zu finden.

Kommentiere einfach mal die paar Zeilen welche "assert" enthalten aus.
Sollte problemlos auch ohne gehen.

von Kay L. (kgbrus)


Lesenswert?

Hab ich auskommentiert,

ich bekomme weiterhin die Fehlermeldung beim Kompelieren:
 'CAN1' was not declared in this scope
1
//------------------------------------------------------------------------------------------------------------Testweise auskommentiert    #include <assert.h>
2
#include <Arduino.h>
3
#include "stm32f103.h"
4
5
#define DEBUG 0
6
7
8
9
10
11
12
typedef struct
13
{
14
    uint16_t baud_rate_prescaler;                /// [1 to 1024]
15
    uint8_t time_segment_1;                      /// [1 to 16]
16
    uint8_t time_segment_2;                      /// [1 to 8]
17
    uint8_t resynchronization_jump_width;        /// [1 to 4] (recommended value is 1)
18
} CAN_bit_timing_config_t;
19
20
#define CAN_STM32_ERROR_UNSUPPORTED_BIT_RATE     1000
21
#define CAN_STM32_ERROR_MSR_INAK_NOT_SET         1001
22
#define CAN_STM32_ERROR_MSR_INAK_NOT_CLEARED     1002
23
#define CAN_STM32_ERROR_UNSUPPORTED_FRAME_FORMAT 1003
24
25
/*
26
 * Calculation of bit timing dependent on peripheral clock rate
27
 */
28
int16_t ComputeCANTimings(const uint32_t peripheral_clock_rate,
29
                          const uint32_t target_bitrate,
30
                          CAN_bit_timing_config_t* const out_timings)
31
{
32
    if (target_bitrate < 1000)
33
    {
34
        return -CAN_STM32_ERROR_UNSUPPORTED_BIT_RATE;
35
    }
36
37
    //------------------------------------------------------------------------------------------------------------Testweise auskommentiert    assert(out_timings != NULL);  // NOLINT
38
    memset(out_timings, 0, sizeof(*out_timings));
39
40
    /*
41
     * Hardware configuration
42
     */
43
    static const uint8_t MaxBS1 = 16;
44
    static const uint8_t MaxBS2 = 8;
45
46
    /*
47
     * Ref. "Automatic Baudrate Detection in CANopen Networks", U. Koppe, MicroControl GmbH & Co. KG
48
     *      CAN in Automation, 2003
49
     *
50
     * According to the source, optimal quanta per bit are:
51
     *   Bitrate        Optimal Maximum
52
     *   1000 kbps      8       10
53
     *   500  kbps      16      17
54
     *   250  kbps      16      17
55
     *   125  kbps      16      17
56
     */
57
    const uint8_t max_quanta_per_bit = (uint8_t)((target_bitrate >= 1000000) ? 10 : 17);    // NOLINT
58
    //------------------------------------------------------------------------------------------------------------Testweise auskommentiert     assert(max_quanta_per_bit <= (MaxBS1 + MaxBS2));
59
60
    static const uint16_t MaxSamplePointLocationPermill = 900;
61
62
    /*
63
     * Computing (prescaler * BS):
64
     *   BITRATE = 1 / (PRESCALER * (1 / PCLK) * (1 + BS1 + BS2))       -- See the Reference Manual
65
     *   BITRATE = PCLK / (PRESCALER * (1 + BS1 + BS2))                 -- Simplified
66
     * let:
67
     *   BS = 1 + BS1 + BS2                                             -- Number of time quanta per bit
68
     *   PRESCALER_BS = PRESCALER * BS
69
     * ==>
70
     *   PRESCALER_BS = PCLK / BITRATE
71
     */
72
    const uint32_t prescaler_bs = peripheral_clock_rate / target_bitrate;
73
74
    /*
75
     * Searching for such prescaler value so that the number of quanta per bit is highest.
76
     */
77
    uint8_t bs1_bs2_sum = (uint8_t)(max_quanta_per_bit - 1);    // NOLINT
78
79
    while ((prescaler_bs % (1U + bs1_bs2_sum)) != 0)
80
    {
81
        if (bs1_bs2_sum <= 2)
82
        {
83
            return -CAN_STM32_ERROR_UNSUPPORTED_BIT_RATE;          // No solution
84
        }
85
        bs1_bs2_sum--;
86
    }
87
88
    const uint32_t prescaler = prescaler_bs / (1U + bs1_bs2_sum);
89
    if ((prescaler < 1U) || (prescaler > 1024U))
90
    {
91
        return -CAN_STM32_ERROR_UNSUPPORTED_BIT_RATE;              // No solution
92
    }
93
94
    /*
95
     * Now we have a constraint: (BS1 + BS2) == bs1_bs2_sum.
96
     * We need to find such values so that the sample point is as close as possible to the optimal value,
97
     * which is 87.5%, which is 7/8.
98
     *
99
     *   Solve[(1 + bs1)/(1 + bs1 + bs2) == 7/8, bs2]  (* Where 7/8 is 0.875, the recommended sample point location *)
100
     *   {{bs2 -> (1 + bs1)/7}}
101
     *
102
     * Hence:
103
     *   bs2 = (1 + bs1) / 7
104
     *   bs1 = (7 * bs1_bs2_sum - 1) / 8
105
     *
106
     * Sample point location can be computed as follows:
107
     *   Sample point location = (1 + bs1) / (1 + bs1 + bs2)
108
     *
109
     * Since the optimal solution is so close to the maximum, we prepare two solutions, and then pick the best one:
110
     *   - With rounding to nearest
111
     *   - With rounding to zero
112
     */
113
    uint8_t bs1 = (uint8_t)(((7 * bs1_bs2_sum - 1) + 4) / 8);       // Trying rounding to nearest first  // NOLINT
114
    uint8_t bs2 = (uint8_t)(bs1_bs2_sum - bs1);  // NOLINT
115
   //------------------------------------------------------------------------------------------------------------Testweise auskommentiert     assert(bs1_bs2_sum > bs1);
116
117
    {
118
        const uint16_t sample_point_permill = (uint16_t)(1000U * (1U + bs1) / (1U + bs1 + bs2));  // NOLINT
119
120
        if (sample_point_permill > MaxSamplePointLocationPermill)   // Strictly more!
121
        {
122
            bs1 = (uint8_t)((7 * bs1_bs2_sum - 1) / 8);             // Nope, too far; now rounding to zero
123
            bs2 = (uint8_t)(bs1_bs2_sum - bs1);
124
        }
125
    }
126
127
    const bool valid = (bs1 >= 1) && (bs1 <= MaxBS1) && (bs2 >= 1) && (bs2 <= MaxBS2);
128
129
    /*
130
     * Final validation
131
     * Helpful Python:
132
     * def sample_point_from_btr(x):
133
     *     assert 0b0011110010000000111111000000000 & x == 0
134
     *     ts2,ts1,brp = (x>>20)&7, (x>>16)&15, x&511
135
     *     return (1+ts1+1)/(1+ts1+1+ts2+1)
136
     */
137
    if ((target_bitrate != (peripheral_clock_rate / (prescaler * (1U + bs1 + bs2)))) ||
138
        !valid)
139
    {
140
        // This actually means that the algorithm has a logic error, hence assert(0).
141
      //------------------------------------------------------------------------------------------------------------Testweise auskommentiert      assert(0);  // NOLINT
142
        return -CAN_STM32_ERROR_UNSUPPORTED_BIT_RATE;
143
    }
144
145
    out_timings->baud_rate_prescaler = (uint16_t) prescaler;
146
    out_timings->resynchronization_jump_width = 1;      // One is recommended by UAVCAN, CANOpen, and DeviceNet
147
    out_timings->time_segment_1 = bs1;
148
    out_timings->time_segment_2 = bs2;
149
150
    if (DEBUG) {
151
      Serial.print("target_bitrate=");
152
      Serial.println(target_bitrate);
153
      Serial.print("peripheral_clock_rate=");
154
      Serial.println(peripheral_clock_rate);
155
  
156
      Serial.print("timings.baud_rate_prescaler=");
157
      Serial.println(out_timings->baud_rate_prescaler);
158
      Serial.print("timings.time_segment_1=");
159
      Serial.println(out_timings->time_segment_1);
160
      Serial.print("timings.time_segment_2=");
161
      Serial.println(out_timings->time_segment_2);
162
      Serial.print("timings.resynchronization_jump_width=");
163
      Serial.println(out_timings->resynchronization_jump_width);
164
    }
165
    return 0;
166
}
167
 
168
/**
169
 * Print registers.
170
*/ 
171
void printRegister(const char * buf, uint32_t reg) {
172
  if (DEBUG == 0) return;
173
  Serial.print(buf);
174
  Serial.print(reg, HEX);
175
  Serial.println();
176
}
177
178
/**
179
 * Initializes the CAN filter registers.
180
 *
181
 * @preconditions   - This register can be written only when the filter initialization mode is set (FINIT=1) in the CAN_FMR register.
182
 * @params: index   - Specified filter index. index 27:14 are available in connectivity line devices only.
183
 * @params: scale   - Select filter scale.
184
 *                    0: Dual 16-bit scale configuration
185
 *                    1: Single 32-bit scale configuration
186
 * @params: mode    - Select filter mode.
187
 *                    0: Two 32-bit registers of filter bank x are in Identifier Mask mode
188
 *                    1: Two 32-bit registers of filter bank x are in Identifier List mode
189
 * @params: fifo    - Select filter assigned.
190
 *                    0: Filter assigned to FIFO 0
191
 *                    1: Filter assigned to FIFO 1
192
 * @params: bank1   - Filter bank register 1
193
 * @params: bank2   - Filter bank register 2
194
 *
195
 */
196
void CANSetFilter(uint8_t index, uint8_t scale, uint8_t mode, uint8_t fifo, uint32_t bank1, uint32_t bank2) {
197
  if (index > 27) return;
198
199
  CAN1->FA1R &= ~(0x1UL<<index);               // Deactivate filter
200
201
  if (scale == 0) {
202
    CAN1->FS1R &= ~(0x1UL<<index);             // Set filter to Dual 16-bit scale configuration
203
  } else {
204
    CAN1->FS1R |= (0x1UL<<index);              // Set filter to single 32 bit configuration
205
  }
206
    if (mode == 0) {
207
    CAN1->FM1R &= ~(0x1UL<<index);             // Set filter to Mask mode
208
  } else {
209
    CAN1->FM1R |= (0x1UL<<index);              // Set filter to List mode
210
  }
211
212
  if (fifo == 0) {
213
    CAN1->FFA1R &= ~(0x1UL<<index);            // Set filter assigned to FIFO 0
214
  } else {
215
    CAN1->FFA1R |= (0x1UL<<index);             // Set filter assigned to FIFO 1
216
  }
217
218
  CAN1->sFilterRegister[index].FR1 = bank1;    // Set filter bank registers1
219
  CAN1->sFilterRegister[index].FR2 = bank2;    // Set filter bank registers2
220
221
  CAN1->FA1R |= (0x1UL<<index);                // Activate filter
222
223
}
224
225
/**
226
 * Initializes the CAN controller with specified bit rate.
227
 *
228
 * @params: bitrate - Specified bitrate. If this value is not one of the defined constants, bit rate will be defaulted to 125KBS
229
 * @params: remap   - Select CAN port. 
230
 *                    =0:CAN_RX mapped to PA11, CAN_TX mapped to PA12
231
 *                    =1:Not used
232
 *                    =2:CAN_RX mapped to PB8, CAN_TX mapped to PB9 (not available on 36-pin package)
233
 *                    =3:CAN_RX mapped to PD0, CAN_TX mapped to PD1 (available on 100-pin and 144-pin package)
234
 *
235
 */
236
bool CANInit(BITRATE bitrate, int remap)
237
{
238
  // Reference manual
239
  // https://www.st.com/content/ccc/resource/technical/document/reference_manual/59/b9/ba/7f/11/af/43/d5/CD00171190.pdf/files/CD00171190.pdf/jcr:content/translations/en.CD00171190.pdf
240
241
  RCC->APB1ENR |= 0x2000000UL;       // Enable CAN clock 
242
  RCC->APB2ENR |= 0x1UL;             // Enable AFIO clock
243
  AFIO->MAPR   &= 0xFFFF9FFF;        // reset CAN remap
244
                                     // CAN_RX mapped to PA11, CAN_TX mapped to PA12
245
246
  if (remap == 0) {
247
    RCC->APB2ENR |= 0x4UL;           // Enable GPIOA clock
248
    GPIOA->CRH   &= ~(0xFF000UL);    // Configure PA12(0b0000) and PA11(0b0000)
249
                                     // 0b0000
250
                                     //   MODE=00(Input mode)
251
                                     //   CNF=00(Analog mode)
252
253
    GPIOA->CRH   |= 0xB8FFFUL;       // Configure PA12(0b1011) and PA11(0b1000)
254
                                     // 0b1011
255
                                     //   MODE=11(Output mode, max speed 50 MHz) 
256
                                     //   CNF=10(Alternate function output Push-pull
257
                                     // 0b1000
258
                                     //   MODE=00(Input mode)
259
                                     //   CNF=10(Input with pull-up / pull-down)
260
                                     
261
    GPIOA->ODR |= 0x1UL << 12;       // PA12 Upll-up
262
    
263
  }
264
                                
265
  if (remap == 2) {
266
    AFIO->MAPR   |= 0x00004000;      // set CAN remap
267
                                     // CAN_RX mapped to PB8, CAN_TX mapped to PB9 (not available on 36-pin package)
268
269
    RCC->APB2ENR |= 0x8UL;           // Enable GPIOB clock
270
    GPIOB->CRH   &= ~(0xFFUL);       // Configure PB9(0b0000) and PB8(0b0000)
271
                                     // 0b0000
272
                                     //   MODE=00(Input mode)
273
                                     //   CNF=00(Analog mode)
274
275
    GPIOB->CRH   |= 0xB8UL;          // Configure PB9(0b1011) and PB8(0b1000)
276
                                     // 0b1011
277
                                     //   MODE=11(Output mode, max speed 50 MHz) 
278
                                     //   CNF=10(Alternate function output Push-pull
279
                                     // 0b1000
280
                                     //   MODE=00(Input mode)
281
                                     //   CNF=10(Input with pull-up / pull-down)
282
                                     
283
    GPIOB->ODR |= 0x1UL << 8;        // PB8 Upll-up
284
  }
285
  
286
  if (remap == 3) {
287
    AFIO->MAPR   |= 0x00005000;      // set CAN remap
288
                                     // CAN_RX mapped to PD0, CAN_TX mapped to PD1 (available on 100-pin and 144-pin package)
289
290
    RCC->APB2ENR |= 0x20UL;          // Enable GPIOD clock
291
    GPIOD->CRL   &= ~(0xFFUL);       // Configure PD1(0b0000) and PD0(0b0000)
292
                                     // 0b0000
293
                                     //   MODE=00(Input mode)
294
                                     //   CNF=00(Analog mode)
295
296
    GPIOD->CRH   |= 0xB8UL;          // Configure PD1(0b1011) and PD0(0b1000)
297
                                     // 0b1000
298
                                     //   MODE=00(Input mode)
299
                                     //   CNF=10(Input with pull-up / pull-down)
300
                                     // 0b1011
301
                                     //   MODE=11(Output mode, max speed 50 MHz) 
302
                                     //   CNF=10(Alternate function output Push-pull
303
                                     
304
    GPIOD->ODR |= 0x1UL << 0;        // PD0 Upll-up
305
  }
306
307
  CAN1->MCR |= 0x1UL;                   // Require CAN1 to Initialization mode 
308
  while (!(CAN1->MSR & 0x1UL));         // Wait for Initialization mode
309
310
  //CAN1->MCR = 0x51UL;                 // Hardware initialization(No automatic retransmission)
311
  CAN1->MCR = 0x41UL;                   // Hardware initialization(With automatic retransmission)
312
   
313
  // Set bit timing register 
314
  CAN_bit_timing_config_t timings;
315
  Serial.print("bitrate=");
316
  Serial.println(bitrate);
317
  uint32_t target_bitrate = SPEED[bitrate];
318
  Serial.print("target_bitrate=");
319
  Serial.println(target_bitrate);
320
  int result = ComputeCANTimings(HAL_RCC_GetPCLK1Freq(), target_bitrate, &timings);
321
  Serial.print("ComputeCANTimings result=");
322
  Serial.println(result);
323
  if (result) while(true);  
324
  CAN1->BTR = (((timings.resynchronization_jump_width - 1U) &    3U) << 24U) |
325
              (((timings.time_segment_1 - 1U)               &   15U) << 16U) |
326
              (((timings.time_segment_2 - 1U)               &    7U) << 20U) |
327
              ((timings.baud_rate_prescaler - 1U)           & 1023U);
328
329
  // Configure Filters to default values
330
  CAN1->FMR  |=   0x1UL;                // Set to filter initialization mode
331
  CAN1->FMR  &= 0xFFFFC0FF;             // Clear CAN2 start bank
332
333
  // bxCAN has 28 filters.
334
  // These filters are shared by both CAN1 and CAN2.
335
  // STM32F103 has only CAN1, so all 28 are used for CAN1
336
  CAN1->FMR  |= 0x1C << 8;              // Assign all filters to CAN1
337
338
  // Set fileter 0
339
  // Single 32-bit scale configuration 
340
  // Two 32-bit registers of filter bank x are in Identifier Mask mode
341
  // Filter assigned to FIFO 0 
342
  // Filter bank register to all 0
343
  CANSetFilter(0, 1, 0, 0, 0x0UL, 0x0UL); 
344
  
345
  CAN1->FMR   &= ~(0x1UL);              // Deactivate initialization mode
346
347
  uint16_t TimeoutMilliseconds = 1000;
348
  bool can1 = false;
349
  CAN1->MCR   &= ~(0x1UL);              // Require CAN1 to normal mode 
350
351
  // Wait for normal mode
352
  // If the connection is not correct, it will not return to normal mode.
353
  for (uint16_t wait_ack = 0; wait_ack < TimeoutMilliseconds; wait_ack++) {
354
    if ((CAN1->MSR & 0x1UL) == 0) {
355
      can1 = true;
356
      break;
357
    }
358
    delayMicroseconds(1000);
359
  }
360
  //Serial.print("can1=");
361
  //Serial.println(can1);
362
  if (can1) {
363
    Serial.println("CAN1 initialize ok");
364
  } else {
365
    Serial.println("CAN1 initialize fail!!");
366
    return false;
367
  }
368
  return true; 
369
}
370
371
372
#define STM32_CAN_TIR_TXRQ              (1U << 0U)  // Bit 0: Transmit Mailbox Request
373
#define STM32_CAN_RIR_RTR               (1U << 1U)  // Bit 1: Remote Transmission Request
374
#define STM32_CAN_RIR_IDE               (1U << 2U)  // Bit 2: Identifier Extension
375
#define STM32_CAN_TIR_RTR               (1U << 1U)  // Bit 1: Remote Transmission Request
376
#define STM32_CAN_TIR_IDE               (1U << 2U)  // Bit 2: Identifier Extension
377
378
#define CAN_EXT_ID_MASK                 0x1FFFFFFFU
379
#define CAN_STD_ID_MASK                 0x000007FFU
380
 
381
/**
382
 * Decodes CAN messages from the data registers and populates a 
383
 * CAN message struct with the data fields.
384
 * 
385
 * @preconditions A valid CAN message is received
386
 * @params CAN_rx_msg - CAN message structure for reception
387
 * 
388
 */
389
void CANReceive(CAN_msg_t* CAN_rx_msg)
390
{
391
  uint32_t id = CAN1->sFIFOMailBox[0].RIR;
392
  if ((id & STM32_CAN_RIR_IDE) == 0) { // Standard frame format
393
      CAN_rx_msg->format = STANDARD_FORMAT;;
394
      CAN_rx_msg->id = (CAN_STD_ID_MASK & (id >> 21U));
395
  } 
396
  else {                               // Extended frame format
397
      CAN_rx_msg->format = EXTENDED_FORMAT;;
398
      CAN_rx_msg->id = (CAN_EXT_ID_MASK & (id >> 3U));
399
  }
400
401
  if ((id & STM32_CAN_RIR_RTR) == 0) { // Data frame
402
      CAN_rx_msg->type = DATA_FRAME;
403
  }
404
  else {                               // Remote frame
405
      CAN_rx_msg->type = REMOTE_FRAME;
406
  }
407
408
  
409
  CAN_rx_msg->len = (CAN1->sFIFOMailBox[0].RDTR) & 0xFUL;
410
  
411
  CAN_rx_msg->data[0] = 0xFFUL &  CAN1->sFIFOMailBox[0].RDLR;
412
  CAN_rx_msg->data[1] = 0xFFUL & (CAN1->sFIFOMailBox[0].RDLR >> 8);
413
  CAN_rx_msg->data[2] = 0xFFUL & (CAN1->sFIFOMailBox[0].RDLR >> 16);
414
  CAN_rx_msg->data[3] = 0xFFUL & (CAN1->sFIFOMailBox[0].RDLR >> 24);
415
  CAN_rx_msg->data[4] = 0xFFUL &  CAN1->sFIFOMailBox[0].RDHR;
416
  CAN_rx_msg->data[5] = 0xFFUL & (CAN1->sFIFOMailBox[0].RDHR >> 8);
417
  CAN_rx_msg->data[6] = 0xFFUL & (CAN1->sFIFOMailBox[0].RDHR >> 16);
418
  CAN_rx_msg->data[7] = 0xFFUL & (CAN1->sFIFOMailBox[0].RDHR >> 24);
419
420
  // Release FIFO 0 output mailbox.
421
  // Make the next incoming message available.
422
  CAN1->RF0R |= 0x20UL;
423
}
424
 
425
/**
426
 * Encodes CAN messages using the CAN message struct and populates the 
427
 * data registers with the sent.
428
 * 
429
 * @params CAN_tx_msg - CAN message structure for transmission
430
 * 
431
 */
432
void CANSend(CAN_msg_t* CAN_tx_msg)
433
{
434
  volatile int count = 0;
435
436
  uint32_t out = 0;
437
  if (CAN_tx_msg->format == EXTENDED_FORMAT) { // Extended frame format
438
      out = ((CAN_tx_msg->id & CAN_EXT_ID_MASK) << 3U) | STM32_CAN_TIR_IDE;
439
  }
440
  else {                                       // Standard frame format
441
      out = ((CAN_tx_msg->id & CAN_STD_ID_MASK) << 21U);
442
  }
443
444
  // Remote frame
445
  if (CAN_tx_msg->type == REMOTE_FRAME) {
446
      out |= STM32_CAN_TIR_RTR;
447
  }
448
449
  CAN1->sTxMailBox[0].TDTR &= ~(0xF);
450
  CAN1->sTxMailBox[0].TDTR |= CAN_tx_msg->len & 0xFUL;
451
  
452
  CAN1->sTxMailBox[0].TDLR  = (((uint32_t) CAN_tx_msg->data[3] << 24) |
453
                               ((uint32_t) CAN_tx_msg->data[2] << 16) |
454
                               ((uint32_t) CAN_tx_msg->data[1] <<  8) |
455
                               ((uint32_t) CAN_tx_msg->data[0]      ));
456
  CAN1->sTxMailBox[0].TDHR  = (((uint32_t) CAN_tx_msg->data[7] << 24) |
457
                               ((uint32_t) CAN_tx_msg->data[6] << 16) |
458
                               ((uint32_t) CAN_tx_msg->data[5] <<  8) |
459
                               ((uint32_t) CAN_tx_msg->data[4]      ));
460
461
  // Send Go
462
  CAN1->sTxMailBox[0].TIR = out | STM32_CAN_TIR_TXRQ;
463
464
  // Wait until the mailbox is empty
465
  while(CAN1->sTxMailBox[0].TIR & 0x1UL && count++ < 1000000);
466
467
  // The mailbox don't becomes empty while loop
468
  if (CAN1->sTxMailBox[0].TIR & 0x1UL) {
469
    Serial.println("Send Fail");
470
    Serial.println(CAN1->ESR);
471
    Serial.println(CAN1->MSR);
472
    Serial.println(CAN1->TSR);
473
  }
474
}
475
476
 /**
477
 * Returns whether there are CAN messages available.
478
 *
479
 * @returns If pending CAN messages are in the CAN controller
480
 *
481
 */
482
uint8_t CANMsgAvail(void)
483
{
484
  // Check for pending FIFO 0 messages
485
  return CAN1->RF0R & 0x3UL;
486
}

von fuck (Gast)


Angehängte Dateien:

Lesenswert?

Fuck!

Lese den Anhang, verstehe ihn, verinnerliche ihn und handle
danach. Kann man so blöd sein nicht zu verstehen wie dein
Posting die anderen sehen?

"Längerer Sourcecode" ist es wenn man dauernd scrollen muss um
alles zu sehen. Dein Sourcecode ist länger!

von Kay L. (kgbrus)


Lesenswert?

fuck schrieb:
> Fuck!
>
> Lese den Anhang, verstehe ihn, verinnerliche ihn und handle
> danach. Kann man so blöd sein nicht zu verstehen wie dein
> Posting die anderen sehen?
>
> "Längerer Sourcecode" ist es wenn man dauernd scrollen muss um
> alles zu sehen. Dein Sourcecode ist länger!

Hallo Fuck,

das ist eine Definitionsfrage ;-)

Danke für den Hinweis, werde mich in Zukunft daran halten. Wenn ich 
nicht zu blöd bin....

von Sebastian W. (wangnick)


Lesenswert?

Kay L. schrieb:
> ich bekomme weiterhin die Fehlermeldung beim Kompelieren:
>  'CAN1' was not declared in this scope

Für welches Board übersetzt du denn? Also was ist unter "Werkzeuge" als 
"Board" und als "Board part number" eingestellt?

LG, Sebastian

von Kay L. (kgbrus)


Lesenswert?

Hallo Sebastian,
STM32F1 Boards (Arduino STM32)
 generic STM32F103C und STM32F103C6

Die ich immer benutze.


Gruß

Kay

von Sebastian (Gast)


Lesenswert?

Kay L. schrieb:
> STM32F1 Boards (Arduino STM32)
> generic STM32F103C und STM32F103C6
> Die ich immer benutze.

Bei mir gibt es keine Übersetzungsfehler. Häng den aktuellen Stand der 
Dateien mal an, dann kann ich schauen wo der Unterschied liegt.

LG, Sebastian

von Stefan F. (Gast)


Lesenswert?

Kay L. schrieb:
>> Dein Sourcecode ist länger!
> das ist eine Definitionsfrage

Nein, der ist sogar sehr viel länger. Punkt.

von Kay L. (kgbrus)


Angehängte Dateien:

Lesenswert?

Hallo Sebastian,

sorry das ich dich hab warten lassen.

Anbei die h, die ccp und die ino Datei.
Die komplette Fehlermeldung hab ich in die Datei "fehler" kopiert

Gruß und Danke
Kay

von Jens R. (tmaniac)


Lesenswert?

Hast du dir mal den aller ersten Fehler durch gelesen und auch 
verstanden
> stm32f103.cpp:15:3: error: conflicting declaration 'typedef struct CAN_msg_t 
CAN_msg_t'

Es wird dir in der darauf folgenden Zeile verraten wo das typedef noch 
deklariert wird. 🤷‍♂️

von Kay L. (kgbrus)


Lesenswert?

Hallo Jens,

ja hatte ich gesehen. Das ist selbstverständlich weg wenn ich das erste 
typedef struct aus der Datei lösche.  Die frage die ich mir stelle ist: 
muss das struct in der .h oder der . ccp Datei sein?
Egal in welcher Datei ich das auskommentiere der "conflicting 
declaration" Fehler ist  weg, was aber bleibt ist der Hauptfehler "CAN1 
was not declared in this scope"

Gruß

Kay

von Sebastian W. (wangnick)


Lesenswert?

Kay L. schrieb:
> muss das struct in der .h oder der . ccp Datei sein?

Du willst diesen Typ auch im Hauptprogramm zur Verfügung haben, damit du 
CAN-Nachrichten überhaupt senden und empfangen kannst. Also in die 
.h-Datei.

Kay L. schrieb:
> was aber bleibt ist der Hauptfehler "CAN1
> was not declared in this scope"

Das passiert auf meinem Rechner nicht, wenn ich für BluePill F103C6 
(32K) oder Generic F103C6Tx übersetze. Welche Version der Arduino-IDE 
und des STM32-Support für die Arduino-IDE hast du installiert? Bei mir 
sind es Arduino 1.8.19 und darin STM32 2.4.0 ...

LG, Sebastian

von Jens R. (tmaniac)


Lesenswert?

Ok.
Der Fehler wird in der ersten Zeile erzeugt, welche irgend etwas CAN 
spezifisches beinhaltet. Es hat also nichts explizit mit dem "CAN1" zu 
tun sondern vermutlich mit grundsätzlichen.

Arbeitest du in der Arduino Umgebung oder nutzt du einen anderen Editor?

Weil es jetzt Sinn machen würde sich durch die "Arduino.h" zu hangeln 
und zu schauen welchen Controller und damit welche Definitionen dazu 
wirklich verlinkt werden.
Die ganzen CAN Registernamen welche in deinem Code auftauchen sind 
jedenfalls nicht jene, wie sie in der STM HAL genutzt werden. Wobei der 
Arduino STM32 Core eigentlich die HAL nutzt.

Hast du als "Controller" auch einen ausgewählt der CAN hat?

Sorry, wenn es da tiefer in den Arduino-Core bin ich wieder raus. Dein 
Beispiel von weiter oben müsste ich mir mal anschauen, wo der die CAN 
Definitionen her holt.

Beitrag #7357116 wurde vom Autor gelöscht.
von Kay L. (kgbrus)


Angehängte Dateien:

Lesenswert?

Sebastian W. schrieb:
> Das passiert auf meinem Rechner nicht, wenn ich für BluePill F103C6
> (32K) oder Generic F103C6Tx übersetze. Welche Version der Arduino-IDE
> und des STM32-Support für die Arduino-IDE hast du installiert? Bei mir
> sind es Arduino 1.8.19 und darin STM32 2.4.0 ...

meine IDE ist auch  1.8.19. Meinst Du mit STM32 2.4.0 den
Boardverwalter? Da hab ich den STM32F1xx/GD32F1xx boards Version
2021.5.31

Jens R. schrieb:
> Arbeitest du in der Arduino Umgebung oder nutzt du einen anderen Editor?

ich arbeite in der Arduino IDE


Zusatz von meiner Seite, ich vermute fast ich hab irgend etwas nicht
installiert. ich habe die original Arduino-STM32-CAN in eine IDE auf
einem anderen Rechner kopiert. Exakt die selbe Fehlermeldung. Dort ist
wohl eine neuere IDE installiert 2.0.0

von Sebastian W. (wangnick)


Lesenswert?

Kay L. schrieb:
> Meinst Du mit STM32 2.4.0 den
> Boardverwalter? Da hab ich den STM32F1xx/GD32F1xx boards Version
> 2021.5.31

Ok, ich glaube ich verstehe jetzt warum bei dir die Übersetzung 
fehlschlägt.

Ich muss allerdings vorausschicken, dass ich erst vor zwei Wochen 
angefangen habe mich mit den STM32-Prozessoren und deren Programmierung 
zu beschäftigen.

Es scheint so, dass es zwei Arduino-IDE-Erweiterungen für die 
Programmierung der STM32-Prozessoren gibt.

Zum einen ist da (A) 
https://github.com/rogerclarkmelbourne/Arduino_STM32. Diese Umgebung 
kann über die Boardverwalter-URL 
http://dan.drown.org/stm32duino/package_STM32duino_index.json der 
Arduino-IDE hinzugefügt werden, und ergänzt den Boardverwalter dann um 
"STM32F1xx/GD32F1xx boards by stm32duino" und um "STM32F4xx boards by 
stm32duino".

Zum anderen gibt es (B) 
https://github.com/stm32duino/Arduino_Core_STM32. Diese Umgebung kann 
über die Boardverwalter-URL 
https://github.com/stm32duino/BoardManagerFiles/raw/main/package_stmicroelectronics_index.json 
der Arduino-IDE hinzugefügt werden, und ergänzt den Boardverwalter dann 
um "STM32 MCU based boards by STMicroelectronics".

Stefan hat die Geschichte dahinter unter 
http://stefanfrings.de/stm32/stm32f1.html ein wenig erläutert.

Du hast (A) installiert. (A) unterstützt aber allem Anschein nach nicht 
die Programmierung des CAN-Busses, und ist auch generell die ältere und 
inzwischen weniger gepflegte Version. Ich habe (B) installiert. (B) wird 
von ST Microelectronics selbst gepflegt, scheint umfassender und 
aktueller zu sein, und enthält die für dein Projekt nötige Unterstützung 
von CAN1.

Wie gesagt, ich bin diesbezüglich nicht der Experte, aber aus meiner 
Perspektive solltest du überlegen, grundsätzlich auf (B) umzusteigen. 
Dabei könnte es eventuell natürlich nötig werden, einige deiner älteren 
Projekte entsprechend anzupassen. Vielleicht benutzt du auch in diesen 
anderen Projekten aber auch Zusatzbibliotheken die (A) voraussetzen? Das 
ist von hier aus schwierig zu beurteilen.

LG, Sebastian

: Bearbeitet durch User
von Kay L. (kgbrus)


Lesenswert?

Hallo Sebastian,


Top klasse! Wo kann ich "gefällt mir" drücken ;-)

Es funktioniert!!!!  Da wäre ich nie drauf gekommen.

Jetzt kompeliert er alles einwandfrei. Da kann ich endlich versuchen ne 
LED auf dem zweiten Board VIA CAN zum Leuchten zu bringen!

Vielen lieben Dank an dich und alle anderen die mir geholfen haben!


Das ich dann ggf alle Projekte anpassen ist ist nicht das Problem. Da 
hätte ich sowieso früher oder später nochmal ran gemusst, da ich heute 
vieles anders lösen würde als noch vor 2 Jahren!
LG

Kay

von Sebastian W. (wangnick)


Lesenswert?

Kay L. schrieb:
> Da kann ich endlich versuchen ne
> LED auf dem zweiten Board VIA CAN zum Leuchten zu bringen!

Keep us posted!

LG, Sebastian

von Kay L. (kgbrus)


Lesenswert?

Ja gerne....

aber leider schlechte Nachrichten....

ein kleiner sketch:
1
#include "stm32f103.h"  // 
2
const int Taster = PB6;
3
int TasterState = 0;
4
5
const int LED = PA0;
6
const int LED2 = PA3;
7
void setup()
8
{
9
  pinMode(LED_BUILTIN, OUTPUT);  //LED auf Arduino auf HIGH
10
  // --------------------------------------  pinMode
11
  pinMode(Taster, INPUT);
12
  pinMode(LED, OUTPUT);
13
  pinMode(LED2, OUTPUT);
14
  // CAN aktivieren
15
 {
16
 Serial.begin(115200);
17
  bool ret = CANInit(CAN_500KBPS, 2);  // CAN_RX to PB8, CAN_TX to PB9
18
  if (!ret) while (true);
19
 }
20
}
21
void loop()
22
{
23
  digitalWrite(LED2, HIGH);
24
  TasterState = digitalRead(Taster);    // Taster abfragen
25
  if (TasterState == LOW)
26
  {
27
    digitalWrite(LED, LOW);
28
  }
29
  else
30
  {
31
    digitalWrite(LED, HIGH);
32
  }
33
}

der nur funktionier, wenn ich von "Seriel.begin" bis "while (true);" 
auskommentiere.
Dann Leuchtet LED 2 und LED1 lässt sich über den schalter ein und 
ausmachen. Auch LED_BUILDIN leuchtet so wie es sein soll

Bleiben die Zeilen aktiv, leuchtet nur die  LED_Buildin, die im void 
setup angeschaltet wird, die anderen beiden nicht. alles was im Sketch 
nach Seriel.begin kommt wird ignoriert

von Sebastian W. (wangnick)


Lesenswert?

Kay L. schrieb:
> aber leider schlechte Nachrichten....

Hast du denn den Tranceiver schon angeschlossen? Ansonsten kann es gut 
sein, dass CANInit fehlschlägt, und dann führst du ja eine 
Endlosschleife in setup() aus und loop() wird überhaupt nicht betreten. 
Setze in stm32f103.cpp mal DEBUG auf 1, dann sollte während CANInit auf 
Serial einiges an Informationen erscheinen.

Mir kommen auch die Bezeichner PB6, PA0, PA3 im Zusammenhang mit 
pinMode, digitalWrite und digitalRead sehr komisch vor. An der Stelle 
sollten eigentlich Bezeichner der Art D5 verwendet werden. Wie sieht 
dein Aufbau genau aus? Wie sind die digitalen Ein- und Ausgänge 
bezeichnet?

LG, Sebastian

von Sebastian W. (wangnick)


Lesenswert?

Sebastian W. schrieb:
> Hast du denn den Tranceiver schon angeschlossen? Ansonsten kann es gut
> sein, dass CANInit fehlschlägt, und dann führst du ja eine
> Endlosschleife in setup() aus und loop() wird überhaupt nicht betreten.

Ich hab das hier mal mit meinem STM32F303 nachvollzogen. CANInit() 
funktioniert auch ohne angeschlossenen Transceiver. Da ist bei dir doch 
irgendwo ziemlich grundsätzlich noch der Wurm drin.

LG, Sebastian

von Kay L. (kgbrus)


Lesenswert?

Sebastian W. schrieb:
> Mir kommen auch die Bezeichner PB6, PA0, PA3 im Zusammenhang mit
> pinMode, digitalWrite und digitalRead sehr komisch vor. An der Stelle
> sollten eigentlich Bezeichner der Art D5 verwendet werden. Wie sieht
> dein Aufbau genau aus? Wie sind die digitalen Ein- und Ausgänge
> bezeichnet?

PB6, PA8, PA3 kommen aus dem STM Datenblatt:
https://www.alldatasheet.com/datasheet-pdf/pdf/201596/STMICROELECTRONICS/STM32F103C8T6.html

Ab Seite 18 in der Tabelle.
Ich hab ja auch schon mehrere Programme exakt so geschrieben nur beim 
CAN hab ich diese Probleme.

ich habs mit und ohne Transiver versucht, ebenso mit einem anderen 
Bluepill Board. Mit einem Logiganalyser habe ich RX dauerhaft High und 
TX dauerhaft 0. (gemessen direkt am Arduino vor dem Transiver.

Das "Problem" hab ich auch mal unserem Entwicklungsleiter geschrieben 
(er hat mich auf STM und CAN gebracht) vielleicht hat er eine Idee.

Dir trotzdem vielen Dank für die Mühe. Sobald sich irgendwas ergibt 
melde ich mich

Gruß

Kay

von Sebastian W. (wangnick)


Lesenswert?

Sebastian W. schrieb:
> Sebastian W. schrieb:
>> Hast du denn den Tranceiver schon angeschlossen? Ansonsten kann es gut
>> sein, dass CANInit fehlschlägt, und dann führst du ja eine
>> Endlosschleife in setup() aus und loop() wird überhaupt nicht betreten.
>
> Ich hab das hier mal mit meinem STM32F303 nachvollzogen. CANInit()
> funktioniert auch ohne angeschlossenen Transceiver. Da ist bei dir doch
> irgendwo ziemlich grundsätzlich noch der Wurm drin.

Mmh. Ohne Transceiver liefert bei meinem STM32F303 mit angeschlossenem 
Logikanalysator an PA11 und PA12 CANInit() plötzlich "CAN1 initialize 
fail!!" und false zurück. Ziehe ich den Logikanalysator ab erhalte ich 
"CAN1 initialize ok" und true.

Eine der zwei möglichen Meldungen solltest du aber in jedem Fall 
erhalten. Lösch auch mal die Zeile "if (!ret) while (true);". Dann 
sollte nach der Medung "CAN1 initialize fail!!" zumindest trotzdem deine 
loop()-Funktion mit Taster und LED betreten werden.

Kay L. schrieb:
> ich habs mit und ohne Transiver versucht, ebenso mit einem anderen
> Bluepill Board. Mit einem Logiganalyser habe ich RX dauerhaft High und
> TX dauerhaft 0. (gemessen direkt am Arduino vor dem Transiver.

Mmh. CAN_RX ist ja ein Eingang und also ohne angeschlossenen Transceiver 
undefiniert. Aber bei geht ohne angeschlossenen Transceiver CAN_TX nach 
der Initialisierung auf dauerhaft High. CAN_TX ist bei dir PB9, und dort 
ist der D-Pin des SN65HVD230 angeschlossen?

Es besteht ja auch immer noch  die Möglichkeit, dass dein F103 kein 
original STM32 ist. Bei den Nachbauten scheint ja oft gerade die 
CAN-Unterstützung zu fehlen oder fehlerhaft zu sein ...

LG, Sebastian

: Bearbeitet durch User
von Kay L. (kgbrus)


Lesenswert?

Hallo Sebastian,

das es sich ggf  nicht um STM32 original handelt hatte ich auch schon in 
Betracht gezogen und hab mir die am Samstag abend genauer angesehen, das 
ST Micro Logo ist drauf also kein Nachbau sondern, wenn,  dann eine 
Fälschung. Mir ist dabei aber eine andere Abweichung aufgefallen. Drauf 
sein sollte der STM32F103C8xx verbaut ist aber STM32F103C6xx ob das der 
Grund sein kann kann ich so erstmal nicht sagen, ich habe mir aber 
zumindest bei AZ Delivery einen neuen Blue Pill mit C8 bestellt. Mal 
sehen ob es damit funktioniert


Danke und Gruß

Kay

: Bearbeitet durch User
von Sebastian W. (wangnick)


Lesenswert?

Kay L. schrieb:
> Drauf sein sollte der STM32F103C8xx verbaut ist aber STM32F103C6xx

Dann würde ich versuchen den Sketch noch einmal zu übersetzen und 
hochzuladen, und dabei vorher im Menü "Werkzeuge" unter "Board" "Generic 
STM32F1 series" als "Board part number" anstatt "BluePill F103C8" besser 
"BluePill F103C6 (32K)" auszuwählen.

LG, Sebastian

von Kay L. (kgbrus)


Lesenswert?

Hallo Sebastian,

hatte ich schon versucht....


Gruß


Kay

von Kay L. (kgbrus)


Lesenswert?

Soderle,

der C8 ist angekommen und getestet, selbes Ergebnis. Es liegt also nicht 
an der Chip version.

lösche ich "if (!ret) while (true);" bleibt der Code ebenfalls stehen,
lösche ich " bool ret = CANInit(CAN_500KBPS, 0); " dabei ist egal ob 
",0" oder ",2" läuft der Code weiter und die LED´s gehen wie gewünscht 
an.

Ein anderer Gedanke kam mir, ich programmiere mit den ST LinkV2 und 
nicht über die Arduino IDE, könnte das damit zusammen hängen?


Gruß

Kay

von Thomas F. (igel)


Lesenswert?

Kay L. schrieb:
> lösche ich " bool ret = CANInit(CAN_500KBPS, 0); " dabei ist egal ob
> ",0" oder ",2" läuft der Code weiter und die LED´s gehen wie gewünscht
> an.

Dann schlägt die CANInit fehl. Höchstwahrscheinlich hier:
1
  bool can1 = false;
2
  CAN1->MCR   &= ~(0x1UL);        // Require CAN1 to normal mode 
3
  // Wait for normal mode
4
  // If the connection is not correct, it will not return to normal mode.
5
  for (uint16_t wait_ack = 0; wait_ack < TimeoutMilliseconds; wait_ack++) {
6
    if ((CAN1->MSR & 0x1UL) == 0) {
7
      can1 = true;
8
      break;
9
    }

Das Datenblatt sagt dazu:

The request to enter Normal mode is issued by clearing the INRQ bit in 
the CAN_MCR register (-> Zeile 2). The bxCAN enters Normal mode and is 
ready to take part in bus activities when it has synchronized with the 
data transfer on the CAN bus. This is done by waiting for the occurrence 
of a sequence of 11 consecutive recessive bits (Bus Idle state). The 
switch to Normal mode is confirmed by the hardware by clearing the INAK 
bit in the CAN_MSR register.

Evtl. ist dein Bus nicht im Idle-State und der CAN-Controller verweigert 
deshalb den Normal Mode? Hast du einen zweiten Teilnehmer am Bus der 
auch funktioniert?

von Sebastian W. (wangnick)


Lesenswert?

Hallo Kay,

ich empfehle die systematisch vorzugehen:

1. Setze in stm32f103.cpp mal DEBUG auf 1, dann sollte während CANInit 
auf
Serial einiges an Informationen erscheinen.

2. Zeig mal ein Foto von deinem Testaufbau mit Anschluß des 
Transceivers.

3. Mach auch noch ein Foto der STM32, möglichst mit Licht von der Seite 
so dass man den Aufdruck gut erkennen kann.

Ich meine in der stm32f103.cpp auch noch einen Fehler entdeckt zu haben. 
In
1
bool CANInit(BITRATE bitrate, int remap)
 wird für
1
remap==0
 folgende Zeile ausgeführt:
1
    GPIOA->ODR |= 0x1UL << 12;       // PA12 Upll-up
PA12 ist aber der CAN_TX Ausgang, da macht ein Pull-up gar keinen Sinn. 
Ich meine daher, dort müsste stattdessen folgendes hin:
1
    GPIOA->ODR |= 0x1UL << 11;       // PA11 Pull-up
Dieses kleine Problem gilt nur für PA11, nicht für PB8, dort ist der 
Code korrekt. Das Problem spielt auch gar keine Rolle mehr sobald ein 
Transceiver angeschlossen ist, weil der seinen "R"-Ausgang treibt und 
damit den Pegel an PA11 definiert.

LG, Sebastian

von Kay L. (kgbrus)


Angehängte Dateien:

Lesenswert?

Soderle, ich glaube ich komme dem Übeltäter immer näher.

ich habe die Datei von Github komplett in meinen Sketch integriert, also 
nicht als geteilete .h. und .cpp Datei.

Dabei bleibt der Code nicht stehen. Die LED´s mach was sie sollen.
Also muß ich beim "zerteilen" einen Bock eingebaut haben. Ich hab das 
jetzt zig mal kontrolliert finde aber keinen.
Kann mal jemand schauen?

STM32_ino.txt ist die original Datei von Github. Die hab ich dann 
zerlegt und wie oben beschrieben geändert:
stm32f103.cpp
und
stm32f103.h

Meine .ino Date:
CAN2_1.txt

Ich hab die Ino dateien nur als txt hier hochgeladen, damit die jeder 
einsehen kann

LG Kay

von Kay L. (kgbrus)


Angehängte Dateien:

Lesenswert?

Hallo Zusammen,

vielleicht kann jemand mir die Zeilen in der VOID_loop_CAN.txt 
kommentieren,

damit ich verstehe, was in den einzelnen Zeilen geschieht


Dankeschön

Kay

von Peter D. (peda)


Lesenswert?

Kay L. schrieb:
> VOID_loop_CAN.txt

Also mein Compiler versteht kein *.txt.

von Kay L. (kgbrus)


Angehängte Dateien:

Lesenswert?

Hallo Peter,

nun als ino Datei

Gruß

Kay

von Sebastian W. (wangnick)


Angehängte Dateien:

Lesenswert?

Kay L. schrieb:
> Also muß ich beim "zerteilen" einen Bock eingebaut haben. Ich hab das
> jetzt zig mal kontrolliert finde aber keinen.
> Kann mal jemand schauen?

In stm32f103.h ist ein Fehler. Die Deklaration von BITRATE muss so 
lauten:
1
typedef enum {CAN_50KBPS, CAN_100KBPS, CAN_125KBPS, CAN_250KBPS, CAN_500KBPS, CAN_1000KBPS} BITRATE;

In dem Vorschlag von mir oben waren noch zusätzliche Bitraten enthalten, 
sorry.

Ich habe auch noch eine erste Zeile #pragma once dazugefügt.

LG, Sebastian

von Kay L. (kgbrus)


Lesenswert?

Hallo Sebastian,

nun blockiert der Code nicht mehr. Top Danke. Und Du brauchst dich nicht 
entschuldigen. Du hilfst mir sehr weiter. Fehlersuche bildet :-) Hab ich 
wieder was gelernt.

Jetzt brauch ich nur noch kommentierungen was in welcher Zeile der VOID 
LOOP passiert dann sollte ich der Sache langsam aber stetig auf den 
Grund kommen.

Nochmals vielen leiben Dank!

LG

kay

von Sebastian W. (wangnick)


Lesenswert?

Kay L. schrieb:
> vielleicht kann jemand mir die Zeilen in der VOID_loop_CAN.txt
> kommentieren, damit ich verstehe, was in den einzelnen Zeilen geschieht

Ich mach das mal mit CAN2_1.txt, weil VOID_loop_CAN.txt nicht 
vollständig ist.

Zeile 13: counter zählt bei jedem Versand einer Nachricht hoch.

Zeile 14: Es werden später CAN-Nachrichten verschiedener Länge versandt. 
In frameLength steht wie lang die nächste Nachricht sein soll.

Zeilen 41-52: CAN_TX_msg wird initial partiell befüllt.

Zeilen 54-56: Es wird alle interval Millisekunden etwas getan.

Zeilen 57-67: Der Rest der CAN_TX_msg wird befüllt. Wenn counter eine 
gerade Zahl ist, wird das EXTENDED_FORMAT und die ID 0x32F103 gewählt, 
sonst das STANDARD_FORMAT in die ID 0x103. Ausserdem wird bei 
CAN_TX_msg.len 0 ein REMOTE_FRAME gesendet, ansonsten ein DATA_FRAME. Es 
sollen hier halt einfach nur verschiedene Arten von CAN-Nachrichten mal 
testweise erzeugt werden. Für die Details kuck bei 
https://de.wikipedia.org/wiki/Controller_Area_Network.

Zeile 68: Die vorbereitete Nachricht wird an die Sende-Hardware zum 
Senden übergeben.

Zeilen 69-71: Die Zähler werden erhöht.

Zeile 74: Es wird geprüft ob eine empfangene Nachricht bereitliegt.

Zeile 75: Die Nachricht wird aus Empfangshardware abgeholt.

Zeilen 77-108: Die empfangene Nachricht wird auf Serial ausgegeben.

HTH.

LG, Sebastian

von Sebastian W. (wangnick)


Lesenswert?

Kay L. schrieb:
> Fehlersuche bildet :-) Hab ich
> wieder was gelernt.

Durch die zusätzlichen Einträge ist dein gewählter CAN_500KBPS Wert nach 
hinten verschoben worden und hat den Wert 6 bekommen. CANInit holt sich 
die target_bitrate unter diesem index aus dem SPEED-Array, und der hat 
nur 6 Einträge. SPEED[6] liegt also hinter dem Array, und der Wert dort 
im Speicher ist irgend etwas. ComputeCANTimings schlägt dann 
wahrscheinlich fehl, gibt eine Fehlermeldung aus, und läuft in diese "if 
(result) while(true)" Endlosschleife in stm32f103.cpp Zeile 340.

LG, Sebastian

von Kay L. (kgbrus)


Lesenswert?

Hallo Sebastian,

erstmal sorry das ich mich nicht gemeldet habe, aber ich musste mir 
einen neuen Rechner zulegen und es war nicht ganz so einfach alles 
wieder neu aufzusetzen.

ich habe noch ein paar Fragen:

Ich möchte zunächst nur den Zustand einer Variable übertragen.
Kann ich das so senden:
1
CAN_msg_t CAN_TX_msg;                 //  CAN_TX_msg wird initial partiell befüllt. Daten die versendet werden sollen Begin Nachricht
2
    CAN_msg_t CAN_RX_msg;
3
    if (LEDAN == false)CAN_TX_msg.data[0] = 0x00;
4
    if (LEDAN == true) CAN_TX_msg.data[0] = 0x01;
5
    CAN_TX_msg.len = frameLength;         // Daten die versendet werden sollen ende / Ende Nachricht

Mir ist die Empfangsseite nicht ganz klar da im Beispiel die Nachricht 
mit der ID "0x32F103" versehen wird muss am Empfänger ja nach eben 
dieser gefragt (bzw verglichen werden)
reicht eventuell:
1
if   (CAN_RX_msg.id == 0x32F103)
könnte ich da die Daten wieder in die Variable zurückwandeln?
zB
1
if (CAN_RX_msg.type == DATA_FRAME)
2
{
3
if (CAN_TX_msg.data[0] == 0x00) LEDAN = false;
4
if (CAN_TX_msg.data[0] == 0x01) LEDAN = true;
5
}

LG

Kay

von Thomas F. (igel)


Lesenswert?

Kay L. schrieb:
> Kann ich das so senden:
1
     CAN_msg_t CAN_TX_msg; 
2
     CAN_msg_t CAN_RX_msg;
3
4
     if (LEDAN == false)CAN_TX_msg.data[0] = 0x00;
5
     if (LEDAN == true) CAN_TX_msg.data[0] = 0x01;
6
     CAN_TX_msg.len = frameLength;  // wird das auch befüllt?
7
8
// Da fehlt noch mindestens:
9
10
     CAN_TX_msg.id = 0x[irgendwas];
11
     CANSend(&CAN_TX_msg);

1
 if (CAN_RX_msg.type == DATA_FRAME)
2
3
 if (CAN_TX_msg.data[0] == 0x00) LEDAN = false;
4
        ^^^ Da sollte schon auch RX stehen...

von Sebastian W. (wangnick)


Lesenswert?

Kay L. schrieb:
> Kann ich das so senden:

Im Prinzip ja. CAN_TX_msg.len, also die Länge des Datenbereichs der 
CAN-Nachricht, ist bei dir immer genau 1 und sollte also auch mit 1 
intialisiert werden. CAN_TX_msg.id, CAN_TX_msg.type und 
CAN_TX_msg.format sollten auch noch gesetzt werden. Und 
CAN_TX_msg.data[0] kann man auch weniger umständlich füllen :)

Kay L. schrieb:
> könnte ich da die Daten wieder in die Variable zurückwandeln?

Im Prinzip ja. Auch das Auslesen von CAN_RX_msg.data[0] geht etwas 
weniger umständlich. Ich würde auch wenigstens noch prüfen dass 
CAN_RX_msg.len zumindest >=1 ist, aber dass sind eher schon Details 
deines zu erstellenden Detailkonzepts von CAN-Nachrichten.

LG, Sebastian

von Kay L. (kgbrus)


Lesenswert?

Hallo zusammen,

vielen Dank an alle die mir bis hierhin geholfen haben.

ich habe es geschafft der Zustand der ersten Variablen zu übertragen. 
Ich fühle mich wie Marconi :-)

Jetzt kann ich Schritt für Schritt weitermachen und verstehen, was 
passiert, wenn man dies ändert.

Ich halte euch auf dem laufenden bzw komme bei Fragen nochmal auf euch 
zu.

GLG

Kay

von Kay L. (kgbrus)


Lesenswert?

Hallo zusammen,
Soderle da ist doch noch eine allgemeine Frage zu CAN aufgetaucht.

Da nicht ständig gesendet werden muß (und auch soll) sondern nur wenn 
eine Änderung des Zustandes eingetreten ist, reicht es wenn ich im 
Sketch einmal sende?
z.B.:
1
 if (next_state_Lichtschranke1 != akt_state_Lichtschranke1)  // ---------------vergleich ob sich der Status der Lichtschranke1 geändert hat
2
{
3
// Hier dann senden der CAN nachricht
4
}

Sprich wird die Rückmeldung, ob die Nachricht angekommen ist über die 
Hardware (Transiver) geregelt?

Gruß

Kay

von Thomas F. (igel)


Lesenswert?

Kay L. schrieb:
> Da nicht ständig gesendet werden muß (und auch soll) sondern nur wenn
> eine Änderung des Zustandes eingetreten ist

Bei CAN macht man es üblicherweise genau anders: Der Sender sendet 
zyklisch, z.B alle 100ms, immer wieder seine aktuellen Daten.
Der oder die Empfänger lesen die Daten, entscheiden ob sich für sie 
etwas geändert hat und ob deshalb etwas zu tun ist. Das hat den Vorteil 
dass Empfänger die mal eine Nachricht verpasst haben dann beim nächsten 
Sendezyklus die aktuellen Daten auch noch bekommen.


> Sprich wird die Rückmeldung, ob die Nachricht angekommen ist über die
> Hardware (Transiver) geregelt?

Ein CAN-Empfänger sendet am Ende der gerade empfangenen Botschaft das 
ACK-Bit an den Empfänger zurück. Der Empfänger weiß somit dass 
mindestens ein Empfänger seine Botschaft "quittiert" hat.
Der Transceiver hat damit wenig zu tun, der leitet ja nur die Bits 
weiter.

von Kay L. (kgbrus)


Lesenswert?

Thomas F. schrieb:
> Kay L. schrieb:
>> Da nicht ständig gesendet werden muß (und auch soll) sondern nur wenn
>> eine Änderung des Zustandes eingetreten ist
>
> Bei CAN macht man es üblicherweise genau anders: Der Sender sendet
> zyklisch, z.B alle 100ms, immer wieder seine aktuellen Daten.
> Der oder die Empfänger lesen die Daten, entscheiden ob sich für sie
> etwas geändert hat und ob deshalb etwas zu tun ist. Das hat den Vorteil
> dass Empfänger die mal eine Nachricht verpasst haben dann beim nächsten
> Sendezyklus die aktuellen Daten auch noch bekommen.
>
>



Erstmal danke, aber dann kann es doch passieren, das der Bus permanent 
belegt ist, wenn ich zB 100 Nachrichten mit oberster Priorität alle 
100ms sende. Oder nicht?

: Bearbeitet durch User
von Thomas F. (igel)


Lesenswert?

Kay L. schrieb:
> Erstmal danke, aber dann kann es doch passieren, das der Bus permanent
> belegt ist, wenn ich zB 100 Nachrichten mit oberster Priorität alle
> 100ms sende. Oder nicht?

kann passieren, kommt natürlich auf die Bus-Geschwindigkeit an.
Der "Architekt" des Busses überlegt sich das im Vorfeld und prüft ob die 
gewählte Baudrate das auch hergibt. Bei CAN heißt das dann "Bus-Last" 
und winrd in Prozent-Auslastung angegeben.

Ein 500kBit Bus langweilt sich mit 100 Botschaften im 0,1s Zyklus zu 
Tode.

von Kay L. (kgbrus)


Lesenswert?

Thomas F. schrieb:
> Kay L. schrieb:
>> Erstmal danke, aber dann kann es doch passieren, das der Bus permanent
>> belegt ist, wenn ich zB 100 Nachrichten mit oberster Priorität alle
>> 100ms sende. Oder nicht?
>
> kann passieren, kommt natürlich auf die Bus-Geschwindigkeit an.
> Der "Architekt" des Busses überlegt sich das im Vorfeld und prüft ob die
> gewählte Baudrate das auch hergibt. Bei CAN heißt das dann "Bus-Last"
> und winrd in Prozent-Auslastung angegeben.
>
> Ein 500kBit Bus langweilt sich mit 100 Botschaften im 0,1s Zyklus zu
> Tode.

OK Danke für den "Kernsatz" am Schluß ;-)

von Sebastian W. (wangnick)


Lesenswert?

Beim CAN-Bus kann man ziemlich sicher sein dass eine Nachricht entweder 
zugestellt wird oder sie nicht zustellbar ist. Der Fall "nicht 
zustellbar" lässt sich evtl. auf Senderseite durch das Auslesen von 
speziellen Registern erkennen.

Aber "ziemlich sicher" ist nicht "ganz sicher". Wenn du ganz sicher sein 
möchtest, dann könnte z.B. der Empfänger nach Erhalt einer Nachricht 
eine Quittung an den Sender zurücksenden.

Ich mach es bei meinem Haus- und Gartenbus so, dass ich jede 
Statusänderung sofort melde, und dann noch jede Minute den vollen Status 
versende. Ausnahme ist das Aufspielen neuer Software über den CAN-Bus, 
dabei quittiere ich dem Sender jede einzelne Nachricht. Auch damit der 
Sender nicht zu schnell wird, denn das Beschreiben des Flash dauert ein 
wenig.

LG, Sebastian

von Kay L. (kgbrus)


Lesenswert?

hallo Zusammen,

ich steuere damit meine Modellbahnalage. Zur Zeit gehe ich von 4 Prios 
aus:

1. Sensoren die belegte oder Einfahrt eines Zuges melden (um Kollisionen 
zu vermeiden) also Fahrstreckenüberwachung
2. Manuelle steuerung der Fahrstrecken (Geschwindigkeitsregelung oder 
Weichenschaltung sowie Daten für die Anzeigemodule
3. Sensoren in der Landschaft , Häuserbeleuchtung knopfdruckaktionen 
usw.

Ich befürchte das bei ständigem senden von Prio 1 und Prio 2 Nachrichten 
kein "Platz" mehr für Prio drei ist.

von Sebastian W. (wangnick)


Lesenswert?

Kay L. schrieb:
> Ich befürchte das bei ständigem senden von Prio 1 und Prio 2 Nachrichten
> kein "Platz" mehr für Prio drei ist.

Nicht fürchten, ausrechnen. Wenn du den CAN-Bus mit 500kHz fährst, 
passen pro Sekunde theoretisch 5000 Nachrichten a 100 Bit drauf. Die 
Nachrichten mit numerisch kleineren Ids bekommen auf dem Bus Priorität 
vor Nachrichten mit höheren Ids.

LG, Sebastian

von Kay L. (kgbrus)


Lesenswert?

Hallo Sebastian,

dann passt das wenn ich "nur" alle 500mS sende. Es ist nicht schlimm 
wenn eine info um die Zeit verzögert ankommt.

Noch etwas, ich habe zwei Dinge gelesen:

1. In den Datenbits werden nur 8 Zustande (0-7) akzeptiert? also 8-F 
wird ignoriert?

2. mit dem 11 Bit Identifier sind nur 2048 Nachrichten eindeutig zu 
identifizieren? Müssten das nicht viel mehr sein?


Gruß


Kay

: Bearbeitet durch User
von Thomas F. (igel)


Lesenswert?

Kay L. schrieb:
> 1. In den Datenbits werden nur 8 Zustande (0-7) akzeptiert? also 8-F
> wird ignoriert?

Wo hast du denn das gelesen?
Ein Datenbit kennt nur 2 Zustände, 0 und 1.
Das Data-Segment einer CAN-Botschaft kann maximal 8 Daten-Bytes 
innerhalb einer CAN-Botschaft transportieren. Ausnahme:CAN-FD, aber 
lassen wir das vorerst.


> 2. mit dem 11 Bit Identifier sind nur 2048 Nachrichten eindeutig zu
> identifizieren? Müssten das nicht viel mehr sein?

Warum, reicht doch? Die Kommunikation in modernen Autos kommt mit 11-Bit 
Identifiern aus.

: Bearbeitet durch User
von Sebastian W. (wangnick)


Lesenswert?

Kay L. schrieb:
> In den Datenbits werden nur 8 Zustande (0-7) akzeptiert? also 8-F wird
> ignoriert?

Nein, das stimmt nicht. Höchstwahrscheinlich hast du da etwas 
missverstanden. Das Datenfeld besteht aus 0 bis 8 Bytes aus 8 Bits. 
Jedes Datenbyte kann jeden Wert zwischen 0 und 255 annehmen. Das 
Datenlängenfeld bestimmt die Anzahl der Datenbytes. Es ist zwar 4 Bit 
lang, darf aber nur Werte zwischen 0 und 8 annehmen, 9-15 sind nicht 
erlaubt.

Kay L. schrieb:
> mit dem 11 Bit Identifier sind nur 2048 Nachrichten eindeutig zu
> identifizieren? Müssten das nicht viel mehr sein?

Wenn man Nachrichten numerieren möchte, dann sollte so eine Nummer wohl 
besser Teil der Datenbytes sein. Die Id wird meist für den Typ der Daten 
verwendet, auch weil man per Hardware auf Ids filtern kann. Aber wenn du 
lustig bist kannst du auch einen Teil der Id-Bits für Daten verwenden, 
die CAN-Bus-Spezifikation selbst hindert dich nicht daran ...

LG, Sebastian

: Bearbeitet durch User
von Kay L. (kgbrus)


Lesenswert?

Hallo Zusammen,

ich habe nun ein wenig rumexperimentiert und steige so halbwegs durch.

bis jetzt übertrage ich nur zwei Zustände pro Datenbyte in etwa so:

Variable A = false dann CAN_TX_msg.data[0] = 0x00

Variable A = true dann CAN_TX_msg.data[0] =  0x01

Das klappt einwandfrei

Das bedeutet aber wiederum das ich nur 2 Variablen in data[0]übertragen 
kann.

Wenn ich das richtig versteh können aber die eigentlich daten digits 
(also die letzten beiden) 0 bis F annehmen (0x00 bis 0xFF) dann könnte 
ich den Zustand (0 oder 1) von 4 verschiedenen Lichtschranken pro Ziffer 
übertragen.
für die letzte Ziffer in etwa so:

LS1 - LS2 - LS3 - LS4
 0  -  0  -  0  -   1

würde 1 als letzte Ziffer ergeben

LS1 - LS2 - LS3 - LS4
 1  -  1  -  1  -  1
würde F als letzte Ziffer ergeben.

Ich bekomme nur gerade nicht wirklich hin die 4 Zustände in eine Hex 
umzuwandeln, die ich übertragen kann.


Gruß

Kay

von Sebastian W. (wangnick)


Lesenswert?

Kay L. schrieb:
> Ich bekomme nur gerade nicht wirklich hin die 4 Zustände in eine Hex
> umzuwandeln, die ich übertragen kann.

Du musst die vier Zustände in eine Zahl umwandeln. Hexadezimal oder 
Dezimal sind nur Darstellungsformen von Zahlen, die aber mit der 
Übertragung nichts zu tun haben.

Dazu muss man ein wenig Binärarithmetik veranstalten.

Also z.B zum Senden:
1
bool ls1 = true;
2
bool ls2 = false;
3
bool ls3 = false;
4
bool ls4 = true;
5
bool ls5 = false;
6
7
uint8_t val = (ls1<<0)|(ls2<<1)|(ls3<<2)|(ls4<<3)|(ls5<<4);
8
9
msg.data[0] = val;
10
CANSend ...

Und beim Empfang wieder auseinandergedröselt:
1
CANReceive ... msg
2
uint8_t val = msg.data[0];
3
4
bool ls1 = val&1;
5
bool ls2 = val&2;
6
bool ls3 = val&4;
7
bool ls4 = val&8;
8
bool ls5 = val&16;

LG, Sebastian

von Kay L. (kgbrus)


Lesenswert?

Hallo Sebastian,

ich hab deinen Vorschlag auf meine Gegebenheiten abgeändert und dabei 
zunächst nur einen Wert in die val geschrieben.

Sender:
1
    CAN_msg_t CAN_TX_msg;                 //  CAN_TX_msg wird initialisiert
2
    CAN_msg_t CAN_RX_msg;                 //  CAN_RX_msg wird initialisiert
3
    LEDAN = true;
4
    uint8_t val =(LEDAN<<0);
5
    CAN_TX_msg.data[0] = val;
6
    CAN_TX_msg.len = frameLength;         // Daten die versendet werden sollen ende / Ende Nachricht
7
    unsigned long currentMillis = millis();    // alle intervall Millisekunden senden
8
    if (currentMillis - previousMillis >= interval)
9
    {
10
      previousMillis = currentMillis;
11
      if ( ( counter % 2) == 0)
12
      { // Der Rest der CAN_TX_msg wird befüllt
13
        CAN_TX_msg.type = DATA_FRAME;
14
        if (CAN_TX_msg.len == 0) CAN_TX_msg.type = REMOTE_FRAME;
15
        CAN_TX_msg.format = EXTENDED_FORMAT;
16
        CAN_TX_msg.id = 0x32F103;
17
      }
18
    
19
      CANSend(&CAN_TX_msg);           // Die vorbereitete Nachricht wird an die Sende-Hardware zum Senden übergeben.
20
      frameLength++;                  // Die Zähler werden erhöht.
21
      if (frameLength == 9) frameLength = 0;
22
      counter++;
23
    }

Empfänger:
1
    CAN_msg_t CAN_TX_msg;                //  CAN_TX_msg wird initialisiert
2
    CAN_msg_t CAN_RX_msg;               //  CAN_RX_msg wird initialisiert
3
    if (CANMsgAvail())
4
    { 
5
// Es wird geprüft ob eine empfangene Nachricht bereitliegt.
6
      CANReceive(&CAN_RX_msg);        // Die Nachricht wird aus Empfangshardware abgeholt.
7
8
      if (CAN_RX_msg.format == EXTENDED_FORMAT)
9
      {
10
        if (CAN_RX_msg.id == 0x32F103)
11
        {
12
          uint8_t val = CAN_RX_msg.data[0];
13
          bool LEDAN = val & 1;
14
        }
15
16
      }
17
    }

Es wird aber nichts übertragen..

von Sebastian W. (wangnick)


Lesenswert?

Du verwendest immer noch frameLength als Länge der gesendeten Daten? Und 
der Code bastelt auch immer noch mit REMOTE_FRAME rum? Und warum 
EXTENDED_FRAME und so hohe Id (0x32F103)? Da würde ich erst einmal alle 
Überbleibsel der Testanwendung rausräumen die du (noch) nicht brauchst.

LG, Sebastian

: Bearbeitet durch User
von Kay L. (kgbrus)


Lesenswert?

Da ich mir nicht sicher war was ich davon ggf noch brauche hab ich es 
noch nicht rausgeworfen. Das wollte ich machen nachdem die Übertragung 
in Hex auch funktioniert.
EXTENDED_FRAME bedeutet doch nur das ich eine höhere ID Zahl habe. Ich 
ändere das aber heute Abend ab. Auch die ID setze ich dann auf den 
kleinsten Wert zum Test.
Ich melde mich dann wieder

Gruß

Kay

von Kay L. (kgbrus)


Lesenswert?

Soderle, ich hab mal etwas zusammengestrichen und nur das nötigste drin 
gelassen (hoffe ich)Senderseite:
1
    CAN_msg_t CAN_TX_msg;                 //  CAN_TX_msg wird initial partiell befüllt. Daten die versendet werden sollen Begin Nachricht
2
    CAN_msg_t CAN_RX_msg;
3
    if (LEDAN == false)CAN_TX_msg.data[0] = 0x00;
4
    if (LEDAN == true) CAN_TX_msg.data[0] = 0x01;
5
    CAN_TX_msg.len = 1;         // Daten die versendet werden sollen ende / Ende Nachricht
6
7
    unsigned long currentMillis = millis();    // alle intervall Millisekunden senden
8
    if (currentMillis - previousMillis >= interval)
9
    {
10
      previousMillis = currentMillis;
11
      // Der Rest der CAN_TX_msg wird befüllt
12
      CAN_TX_msg.type = DATA_FRAME;
13
      CAN_TX_msg.format = STANDARD_FORMAT;
14
      CAN_TX_msg.id = 0x000001;
15
      CANSend(&CAN_TX_msg);           // Die vorbereitete Nachricht wird an die Sende-Hardware zum Senden übergeben.
16
     }
Empfängerseite:
1
    CAN_msg_t CAN_TX_msg;                 //  CAN_TX_msg wird initial partiell befüllt. Daten die versendet werden sollen Begin Nachricht
2
    CAN_msg_t CAN_RX_msg;
3
    if (CANMsgAvail())
4
    { // Es wird geprüft ob eine empfangene Nachricht bereitliegt.
5
      CANReceive(&CAN_RX_msg);        // Die Nachricht wird aus Empfangshardware abgeholt.
6
      if (CAN_RX_msg.id == 0x000001)
7
      {
8
        if (CAN_RX_msg.data[0] == 0x00) LEDAN = false;
9
        if (CAN_RX_msg.data[0] == 0x01) LEDAN = true;
10
      }
11
    }

leider funktioniert das nicht, die ID wird nicht erkannt. Erst wenn ich:
1
      else
2
      {
3
        if (CAN_RX_msg.data[0] == 0x00) LEDAN = false;
4
        if (CAN_RX_msg.data[0] == 0x01) LEDAN = true;
5
      }
im Empfänger zur if Abfrage einfüge wird die Info übertragen. Er erkennt 
also die ID 0x000001 nicht. Ich sehe aber gerade nicht, warum...

Gruß


Kay

von Sebastian W. (wangnick)


Lesenswert?

Kay L. schrieb:
> Er erkennt also die ID 0x000001 nicht. Ich sehe aber gerade nicht, warum...

Ich auch nicht. Welche Id WIRD denn empfangen?

LG, Sebastian

von Kay L. (kgbrus)


Angehängte Dateien:

Lesenswert?

Hallo Sebastian,

wie meinst du das ? Es gibt nur eine Nachricht und die hat die ID 
0x000001 . Es sind auch nur die zwei Telnehmer am Bus. Ich kann auch 
eine andere ID nehmen. Die Übertragung funktioniert immer nur wenn im 
Empfänger die else Schleife drin ist.

Oder meinst Du wie die Daten vom Logiganalyser aussehen?

einen Screenshot findets Du im Anhang

Gruß

Kay

von Sebastian W. (wangnick)


Lesenswert?

Kay L. schrieb:
> Die Übertragung funktioniert immer nur wenn im Empfänger die else
> Schleife drin ist.

Ich meine: Warum wird der else-Zweig betreten? Doch anscheinend weil im 
Empfänger die Id nicht 0x000001 ist. Was ist sie denn? Gib die Id mal 
auf die serielle Schnittstelle aus. Oder besser: Schreib dir eine 
Prozedur die generell eine CAN_msg_t komplett auf die serielle 
Schnittstelle ausgibt, und ruf die Prozedur direkt vor dem Senden und 
direkt nach dem Empfang auf.

LG, Sebastian

PS: Du benutzt die Saleae-Software? Die hat einen Analysator für CAN ...

von Kay L. (kgbrus)


Lesenswert?

Ok Nun verstanden.

Da muß ich mal sehen ob das mit der seriellen Schnittstellenausgabe bei 
mir überhaupt geht, da ich nicht mit der Arduino Software das Board 
beschreibe sondern eine kompilierte Binärdatei exportiere und dann mit 
ST - LinkV2 auf den STM32 programmiere.
Ich hab das noch nicht ausprobiert.

ja ich nutze Logic2 von saleae, wohl die Freewareversion. Bis Dato hab 
ich noch keinen CAN Analysator gefunden.

Gruß

Kay

: Bearbeitet durch User
von Kay L. (kgbrus)


Angehängte Dateien:

Lesenswert?

So CAN Analyser gefunden.

Screenshot anbei Ch1 ist TX am Sender. ist Async Serial die ID? dann ist 
die 0xFF und nicht 0x000001 was das verhalten erklären würde. Ich aber 
(noch) keinen blassen Schimmer habe warum die ID falsch ist.

Ausserdem zeigt er mir zweimal Error  an.

ich muß jetzt leider weg. Ich werde morgen die funktionierenden Sketche 
in die STMs einprogramieren und erneut messen. Mal sehen ob die Fehler 
dann weg sind.

Und wieder mal, vielen Dank Sebastian.

Gruß

Kay

: Bearbeitet durch User
von Sebastian W. (wangnick)


Angehängte Dateien:

Lesenswert?

Kay L. schrieb:
> Bis Dato hab
> ich noch keinen CAN Analysator gefunden.

Siehe Bild.

Kay L. schrieb:
> einen Screenshot findets Du im Anhang

Ich hab das mal händisch dekodiert. Das ist eine saubere STANDARD DATA 
CAN-Nachricht mit id 0x0001, len 0x01 und data[0] 0x00. Die Prüfsumme 
stimmt, und der Empfänger hat den korrekten Empfang mit ACK quittiert.

Kay L. schrieb:
> Da muß ich mal sehen ob das mit der seriellen Schnittstellenausgabe bei
> mir überhaupt geht.

Alternativ kuck es dir im Debugger an. Aber irgendeine Möglichkeit, 
deine Software im laufenden Betrieb zu untersuchen, wirst du brauchen 
...

LG, Sebastian

von Sebastian W. (wangnick)


Lesenswert?

Kay L. schrieb:
> creenshot anbei Ch1 ist TX am Sender. ist Async Serial die ID? dann ist
> die 0xFF und nicht 0x000001 was das verhalten erklären würde.

Erstens hast du nicht die ganze CAN-Nachricht erwischt, die ersten zwei 
Bits oder so fehlen.

Zweitens ist Async Serial der Analysator für eine serielle 
Schnittstelle. Den solltest du mal deaktivieren oder entfernen, der 
hilft hier nicht.

[[[ Wenn du Debug-Meldungen auf einen seriellen Port ausgibst, dann 
kannst du an diesen Port auch noch den Logik-Analysator anschließen, und 
die Ausgaben mit Async Serial als Text darstellen lassen. So sieht man 
manchmal ganz gut die Programmreaktionen auf eingehende Nachrichten und 
so. ]]]

Drittens musst du dem CAN-Analysator mitteilen, welchen Kanal er 
dekodieren soll. Nimm am besten Empfänger-RX. Sender-RX ginge aber auch, 
es geht nur darum dass der Analysator auch das ACK-Bit sieht.

LG, Sebastian

von Kay L. (kgbrus)


Lesenswert?

Sebastian W. schrieb:
> Ich hab das mal händisch dekodiert. Das ist eine saubere STANDARD DATA
> CAN-Nachricht mit id 0x0001, len 0x01 und data[0] 0x00. Die Prüfsumme
> stimmt, und der Empfänger hat den korrekten Empfang mit ACK quittiert.

Dann ist ja alles wie es sein sollte. Trotzdem empängt der nur wenn ich 
zu

die else funktion nach der if ID = 0x0001 einfüge.  Da mus da doch 
irgendwo ein Bock sein.
Blöde Frage; Spaces werden ignoriert? Nicht das ich etwas suche, was man 
nicht sieht.

PS: zum "händisch dekodoert, hast du ev einen Link wo ich nachschauen 
kann wie man das macht?

GRuß

Kay
PPS: Mit mir hast Du dir ja ganz schön einen ans Bein gebunden..... ;-)

von Kay L. (kgbrus)


Lesenswert?

Hallo zusammen,

sorry das ich mich jetzt erst melde aber ich hatte irgendwo einen Bock 
reingebaut somit hab ich nochmal von vorne mit CAN begonnen und leider 
in letzter Zeit wenig Zeit gehabt mich darum zu kümmern. ich bin jetzt 
wieder soweit das ich die Zustände meiner Lichtschranken getrennt 
übertragen kann.

Dies aber nur sehr umständlich:
1
  if (LEDan == 0)CAN_TX_msg.data[0] = 0x00;
2
      if (LEDan == 1)CAN_TX_msg.data[0] = 0x01;
3
      if (LED1an == 0)CAN_TX_msg.data[1] = 0x00;
4
      if (LED1an == 1)CAN_TX_msg.data[1] = 0x01;
5
      CAN_TX_msg.len = 2;

da ich, wenn ich das richtig verstehe, in data[0] (0x00 oder 0xff usw) 
256 verschiedene Zustände übertragen kann, macht das so ja gar keinen 
Sinn, das so wie oben zu machen
Ich müsste doch bis zu 8 verschiedene Lichtschranken a 2 Zuständen in 
Data[0] übertragen können?

Nur wie bekomme ich die Zustände der Lichtschranken, insgesamt 5 in das 
data0 byte geschrieben?


Gruß

Kay

von Wastl (hartundweichware)


Lesenswert?

Kay L. schrieb:
> Nur wie bekomme ich die Zustände der Lichtschranken, insgesamt 5 in das
> data0 byte geschrieben?

Indem du für jede der fünf Lichtschranken ein Bit in einem
Byte reservierst.
1
uint8_t state_ls0 = 1;  // willkürlich gewählte 0/1
2
uint8_t state_ls1 = 0;
3
uint8_t state_ls2 = 1;
4
uint8_t state_ls3 = 0;
5
uint8_t state_ls4 = 1;
6
7
CAN_TX_msg.data[0] = (  (state_ls4 << 4) | (state_ls3 << 3) 
8
                      | (state_ls2 << 2) | (state_ls1 << 1)
9
                      | (state_ls0 << 0)  );

Oh mann war das schwierig.

: Bearbeitet durch User
von Sebastian W. (wangnick)


Lesenswert?

Kay L. schrieb:
> Nur wie bekomme ich die Zustände der Lichtschranken, insgesamt 5 in das
> data0 byte geschrieben?

Beitrag "Re: Arduino Blue Pill & CAN mit SN65HVD230"

LG, Sebastian

von Wastl (hartundweichware)


Lesenswert?

Sebastian W. schrieb:
> LG, Sebastian

Ja, sorry, hab übersehen dass das Rad schon erfunden war.

Scheint so als ob sich beim TO da eine gewisse Beratungsresistenz
breit macht. Oder war sie schon immer da?

von Kay L. (kgbrus)


Lesenswert?

Hallo Ihr zwei,

Sorry ich hatte den Post von Sebastian nicht mehr auf dem Schirm...
Vielen Dank


Gruss

Kay

Ps: ich hoffe das ich nicht den Eindruck von beratungresistenz mache ;-)

: Bearbeitet durch User
von Kay L. (kgbrus)


Lesenswert?

Hallo zusammen,

soweit hab ich es jetzt. Es funktioniert. Ich habe aber die Zuweisung 
über den Befehl bitWrite bzw bitRead gemacht. Ich weiß nicht ob das ein 
Arduino spezifischer Befehl ist.

Es funktioniert mit 2 Arduinos In beide Richtungen mit verschiedenen 
Nachrichten!

Vielen vielen dank, nur durch eure Hilfe (und Geduld) hab ich das hin 
bekommen!

nächster Versuch ist dann einen dritten Arduino mit einzubinden!

LG

Kay

: Bearbeitet durch User
von Sebastian W. (wangnick)


Lesenswert?

Kay L. schrieb:
> soweit hab ich es jetzt. Es funktioniert. Ich habe aber die Zuweisung
> über den Befehl bitWrite bzw bitRead gemacht. Ich weiß nicht ob das ein
> Arduino spezifischer Befehl ist.

Ja, die (Makro-)Definition von bitWrite und bitRead finden sich in 
C:\Program Files 
(x86)\Arduino\hardware\arduino\avr\cores\arduino\Arduino.h. Es macht 
sowieso viel Sinn anzufangen im Quellcode von Arduino und den 
Bibliotheken zu stöbern, denn viele wichtige Details sind halt nicht 
dokumentiert.

LG, Sebastian

von Kay L. (kgbrus)


Angehängte Dateien:

Lesenswert?

Hallo nochmal,  ich bins wieder und der Verzweiflung nahe...

Wie ich oben schrieb funktionierte es. Ich konnte nachrichten zwischen 
zwei Arduinos via CAN hin und her senden.

Dann beim versuch den Dritten einzubinden, ging plötzlich nichts mehr. 
Das Programm blieb stehen und zwar an dieser Stelle:
1
 {
2
    Serial.begin(115200);
3
    bool ret = CANInit(CAN_500KBPS, 0);  // CAN_RX mapped to PA11, CAN_TX mapped to PA12
4
    if (!ret) while (true);
5
  }

Alles was vorher im Sketch steht wird ausgeführt, was  danach steht 
nicht mehr. Da ich keinen Fehler finden konnte, hab ich alles neu 
gemacht von ganz vorne. Also ab dem Punkt wo ich die Ursprungsdatei von 
Github in die .ccp und .h Datei zerlegen musste.
Das funktionierte dann auch wieder mit zwei Arduinos.  Dann aber 
plötzlich das gleiche, ab o.g. Zeile bleibt der Sketch  stehen.
Um auszuschließen das es an der HW liegt habe ich 3 verschiedenen 
Arduinos versucht, den ST - Link V2 Programieradapter durcht einen FTDI 
adapter ersetzt und letztendlich über einen anderen Rechner versucht, 
alles mit dem selben Ergebnis. Sketch bleibt stehen.

Kurzer Nachtrag : Ändere ich die:
1
  bool ret = CANInit(CAN_500KBPS, 0);  // CAN_RX mapped to PA11, CAN_TX mapped to PA12
auf
1
  bool ret = CANInit(CAN_500KBPS, 2);  // CAN_RX to PB8, CAN_TX to PB9

funktioniert es. Bleibt der Sketch nicht stehen.

der Aufbau der Auswahl CANInit 0 in der .ccp unterscheidet sich auch zur 
Version 2.  Ich hatte versucht das anzupassen. Also Zeile 246 in d r.ccp 
an Stelle 250 (also hinter if(remap ==0)) zu legen.  das hat aber keine 
Änderung gebracht.
Ich habe mal meine Dateien angehängt, hat jemand eine Idee?

Dank im voraus

Gruß

Kay

: Bearbeitet durch User
von Sebastian W. (wangnick)


Lesenswert?

Kay L. schrieb:
> Das Programm blieb stehen und zwar an dieser Stelle

Welche Nachrichten erscheinen denn auf Serial, wenn du DEBUG in 
stm32f103.cpp auf 1 setzt?

LG, Sebastian

von Kay L. (kgbrus)


Lesenswert?

Sebastian W. schrieb:
> Kay L. schrieb:
>> Das Programm blieb stehen und zwar an dieser Stelle
>
> Welche Nachrichten erscheinen denn auf Serial, wenn du DEBUG in
> stm32f103.cpp auf 1 setzt?
>
> LG, Sebastian

Ich kann Serial in der IDE nicht sehen, da ich eine kompelierte Datei 
exportiere und dann mit ST-Link den Arduino programmiere.

Oder besteht so auch eine Möglichkeit?

Gruß

Kay

: Bearbeitet durch User
von Sebastian W. (wangnick)


Lesenswert?

Kay L. schrieb:
> Ich kann Serial in der IDE nicht sehen

Du hast doch einen Logikanalysator? Häng den doch einfach an den UART 
TX-Pin des BluePill, um die Ausgaben auf dem seriellen Port sehen zu 
können.

Oder schau dir im Debugger an, an welcher Stelle CANInit scheitert ...

LG, Sebastian

: Bearbeitet durch User
von Rahul D. (rahul)


Lesenswert?

Sebastian W. schrieb:
> Oder schau dir im Debugger an, an welcher Stelle CANInit scheitert ...

Gute Witz, denn:
Kay L. schrieb:
> da ich eine kompelierte Datei
> exportiere und dann mit ST-Link den Arduino programmiere.

Aber eigentlich sollte man mit jedem x-beliebigen Terminlaprogramm die 
serielle Ausgabe sehrn können.
Das wäre der einfachste Weg des Debuggings.

von Kay L. (kgbrus)


Lesenswert?

Hallo Sebastian und interessierte,

es scheint der Fehler gefunden, der Fehler war in der Bibliothek.

Beim Remap auf PB8 und 9 wird der Pullup in PB8 aktiviert (Zeile 288). 
PB8 ist  der RX Pin

Beim remap auf PA11 und 12 wird der Pullup in PB12 aktiviert (Zeile 266) 
PB12 ist aber der TX Pin. Schalte ich den Pullup in PA11 (TX PIN) an 
scheint es zu funktionieren (zumindest läuft der Code weiter)

Gruß

Kay

von Kay L. (kgbrus)


Lesenswert?

Kay L. schrieb:
> Hallo Sebastian und interessierte,
>
> es scheint der Fehler gefunden, der Fehler war in der Bibliothek.
>
> Beim Remap auf PB8 und 9 wird der Pullup in PB8 aktiviert (Zeile 288).
> PB8 ist  der RX Pin
>
> Beim remap auf PA11 und 12 wird der Pullup in PB12 aktiviert (Zeile 266)
> PB12 ist aber der TX Pin. Schalte ich den Pullup in PA11 (TX PIN) an
> scheint es zu funktionieren (zumindest läuft der Code weiter)
>
> Gruß
>
> Kay

Sorry ich meinte natürlich:PA11 ist der RX Pin. Sorry

: Bearbeitet durch User
von Kay L. (kgbrus)


Lesenswert?

Hallo zusammen,

Ich bin mittlerweile so weit das ich den ersten "größeren" Bus mit 9 
Teilnehmern, 8 Slave und 1 Master(Zentrale), aufgebaut habe und dieser 
Funktioniert auch einwandfrei.
Ich weiß man kann mehrere Empfänger einer Nachricht zuordnen, aber ist 
das sinnvoll? Bei meinem Beispiel senden die Slaves jeder eine Nachricht 
mit verschiedenen Daten an die Zentrale.  Die Zentrale könnte alle Infos 
in einer Nachricht an alle Arduinos senden. Macht das Sinn oder ist es 
besser, jedem einzelnen Slave eine Nachricht von der Zentrale zu senden?


Gruß

Kay

von Thomas F. (igel)


Lesenswert?

Kay L. schrieb:
> Bus mit 9 Teilnehmern, 8 Slave und 1 Master(Zentrale)

Das Konzept CAN-Bus ist eigentlich nicht als Master-Slave gedacht. 
Vielmehr sind alle Busteilnehmer gleichberechtigt im Senden und 
Empfangen. Sie haben nur unterschiedliche Aufgaben.

> Die Zentrale könnte alle Infos in einer Nachricht an alle Arduinos senden.

Man sendet bei CAN nicht an gezielte Busknoten.
Informationen bündelt man thematisch zu einer Botschaft mit einer ID. 
Die anderen Busknoten empfangen die Botschaft und entscheiden dann (in 
ihrer Software) ob sie diese Informationen auch benutzen wollen.


> jedem einzelnen Slave eine Nachricht von der Zentrale zu senden.

Man spricht den entsprechenden Busknoten nicht direkt an und sagt ihm 
was er tun soll, sondern man schickt das Ziel welches man erreichen will 
über den Bus.

Beispiel aus dem Auto:
Man sagt nicht: "Türsteuergerät Beifahrerseite: Entriegel mal das 
Türschloss."
Sondern: "Türschloss Beifahrerseite bitte entriegeln." Das 
Türsteuergerät BF weiß dass dies seine Aufgabe ist und führt den Befehl 
aus. Die anderen Steuergeräte ignorieren die Botschaft weil sie andere 
Aufgaben haben.

von Kay L. (kgbrus)


Lesenswert?

Hallo Thomas,

sorry da habe ich die falschen Begriffe gewählt.

Zur Beschreibung: Ein Arduino fungiert als  Zentrale in dem das 
eigentliche Programm abläuft.
Jedes Modul hat einen Arduino, der nur die Eingänge abfragt, via CAN zur 
Zentrale sendet und die Ausgänge steuert, so wie die Zentrale es 
vorgibt.

Sorry das ich das als Master Slave bezeichnet habe.

Mir ist auch klar das ich nicht die Knoten anspreche.

Als Beispiel:

an den 8 Arduinos der einzelnen Module hängen in Summe 28 Eingänge. 
Durch die 8 Arduinos werden natürlich  8 Nachrichten an die Zentrale 
versendet.

Die Zentrale soll nun mittels variablen via CAN die Ausgänge an den 
Arduinos in den einzelnen modulen steuern.
Insgesammt hab ich 35 Ausgänge auf den verschiedenen Arduinos.

Ich könnte jetzt:
A) 8 Nachrichten in denn nur die Variablen für die Ausgänge der 
jeweiligen Arduinos übertragen werden
oder
B) ein nachricht in der alle Variablen für die Ausgänge übertragen 
werden
versenden.

bei B würde nur eine Nachricht gesendet, die von allen 8 Adiunos auf den 
Modulen empfangen wird. Die suchen sich dann jeweils die Variable raus, 
die
auf diesem Arduino gebraucht wird.


Gruß

Kay

von Sebastian W. (wangnick)


Lesenswert?

Tja, das sind so Designfragen. Meiner Erfahrung nach sollte man die 
einfachste Lösung wählen, die für genau das aktuelle Problem 
funktioniert. Man kann vielleicht schon fest vorgesehene Erweiterungen 
berücksichtigen. Aber wer für Eventualitäten designt, der hat Angst vor 
späterer Änderung!

LG, Sebastian

von Thomas F. (igel)


Lesenswert?

Kay L. schrieb:
> A) 8 Nachrichten in denn nur die Variablen für die Ausgänge der
> jeweiligen Arduinos übertragen werden

Ich würde es wohl so machen. 8 CAN-IDs (Botschaften) mit den jeweiligen 
Kommando. Auch wenn jede Botschaft dann nur aus 1 oder 2 Byte besteht so 
ist das am Ende doch übersichtlicher und später einfach erweiterbar.


> bei B würde nur eine Nachricht gesendet, die von allen 8 Adiunos auf den
> Modulen empfangen wird.

Geht auch. Aber man hat ja bei CAN genügend IDs zur Verfügung, da muss 
man nicht mit Botschaften geizen.

Letztendlich bist du dein eigener Busarchitekt und musst auch die 
Software dafür schreiben.

von Kay L. (kgbrus)


Lesenswert?

Ok verstehe,

meine "Sorge" ist halt (vielleicht habe ich da auch etwas nicht 
verstanden) das,
wenn mehrere Empfänger eine Nachricht nutzen, dann sendet einer doch ein 
Bit "Übertragung Fehlerfrei" damit hört der Sender (bis zum nächsten 
Intervall) auf diese Nachricht zu senden. Könnte es nicht sein, das ein 
Empfänger dann die Nachricht gar nicht bekommen hat?
Oder ist das "graue Theorie"?

Eigentlich würde ich die Variableren gerne "Abschnittsweise" bei den 
Nachrichten zusammen fassen.
Im Beispiel mit den 8 Arduinos gibt es 3 Abschnitte: Abschnitt SBH1 
(bestehend aus 4 Modulen mit jeweils einem Arduino),
Abschnitt Kreuzung (1 Arduino)
und Abschnitt SBH2 (2 Arduinos).
Die Zentrale würde also alle Variablen für SBH1 in einer Nachricht 
übertragen, ebenso für den Abschnitt Kreuzung und dann noch SBH 2.
Die untere Ebene würde dann mit 3 Nachrichten aus der Zentrale gesteuert
Somit hätte ich auf der ganzen Anlage (insgesmmt 32 Module und ca 9 
"Abschnitte") immer alle Daten zu einem Abschnitt in einer Nachricht 
parat.

Gruß

Kay

von Kay L. (kgbrus)


Lesenswert?

Hallo Zusammen,

bei mir klemmt es gerade wieder.....

Ich kann nur eine Nachricht versenden. Die zweite erscheint auf dem Bus 
erst gar nicht.
Die Nachricht ID 0x100010 erscheint nicht. Kommentiere ich aber 
Nachricht 0x00009 aus wird Nachricht 0x00010 versendet.
1
    // begin CAN senden
2
    {
3
      {CAN_msg_t CAN_TX_msg;                 // Initialisierung Senden
4
        // ----------------------------  Begin CAN Nachricht 0x10009 senden
5
        // eigentliche Daten werden eingefüllt
6
        // mit bitwrite lassen sich einzelne bits innerhalb eines Bytes beschreiben.  Hier Zustand TasterState in Erstes (ganz rechtes) Bit von Data0 schreiben
7
        bitWrite (CAN_TX_msg.data[0], 0, WeicheEinfahrtSBHSudGeradeausState);   // Data 00 Steuerung der Ausgaenge Modul2 Einfahrt SBH Sued
8
        bitWrite (CAN_TX_msg.data[0], 1, WeicheEinfahrtSBHSudAbbiegenState);
9
        bitWrite (CAN_TX_msg.data[1], 0, WeicheSBHSudGleis1geradeausState);     // Data 01 Steuerung der Ausgaenge Modul3 SBH Sued Rechts
10
        bitWrite (CAN_TX_msg.data[1], 1, WeicheSBHSudGleis1abbiegenState);
11
        bitWrite (CAN_TX_msg.data[1], 2, WeicheSBHSudGleis1geradeausState);
12
        bitWrite (CAN_TX_msg.data[1], 3, WeicheSBHSudGleis1abbiegenState);
13
        bitWrite (CAN_TX_msg.data[1], 4, WeicheSBHSudGleis1geradeausState);
14
        bitWrite (CAN_TX_msg.data[1], 5, WeicheSBHSudGleis1abbiegenState);
15
        bitWrite (CAN_TX_msg.data[1], 6, WeicheSBHSudGleis1geradeausState);
16
        bitWrite (CAN_TX_msg.data[1], 7, WeicheSBHSudGleis1abbiegenState);     // Data 02 Steuerung der Ausgänge Modul3 SBH Sued Rechts
17
        CAN_TX_msg.len = 2;                             // Länge der Nachricht
18
        unsigned long currentMillis = millis();         // Senden alle x millisekunden
19
        if (currentMillis - previousMillis >= interval)
20
        {
21
          previousMillis = currentMillis;
22
          if ( ( counter % 2) == 0)
23
          { // Rest der Nachricht wird befüllt
24
            CAN_TX_msg.type = DATA_FRAME;
25
            if (CAN_TX_msg.len == 0) CAN_TX_msg.type = REMOTE_FRAME;
26
            CAN_TX_msg.format = EXTENDED_FORMAT;
27
            CAN_TX_msg.id = 0x100009;                   // nachrichten ID
28
          }
29
          CANSend(&CAN_TX_msg);                         // Übergabe der Nachricht an die Hardware
30
        }
31
32
        //// ----------------------------  Ende CAN Nachricht 0x10009 senden an Modul 2
33
      }
34
      {CAN_msg_t CAN_TX_msg;                 // Initialisierung Senden
35
        // ----------------------------  Begin CAN Nachricht 0x10010 senden  fahrspannungen für SBH Sud
36
        // eigentliche Daten werden eingefüllt
37
        // mit bitwrite lassen sich einzelne bits innerhalb eines Bytes beschreiben.  Hier Zustand TasterState in Erstes (ganz rechtes) Bit von Data0 schreiben
38
        bitWrite (CAN_TX_msg.data[0], 0, FahrstromSBHSudGleis1State);
39
        CAN_TX_msg.len = 1;                             // Länge der Nachricht
40
        unsigned long currentMillis = millis();         // Senden alle x millisekunden
41
        if (currentMillis - previousMillis >= interval1)
42
        {
43
          previousMillis = currentMillis;
44
          if ( ( counter % 2) == 0)
45
          { // Rest der Nachricht wird befüllt
46
            CAN_TX_msg.type = DATA_FRAME;
47
            if (CAN_TX_msg.len == 0) CAN_TX_msg.type = REMOTE_FRAME;
48
            CAN_TX_msg.format = EXTENDED_FORMAT;
49
            CAN_TX_msg.id = 0x100010;                   // nachrichten ID
50
          }
51
          CANSend(&CAN_TX_msg);                         // Übergabe der Nachricht an die Hardware
52
        }

Ich habe schon mit 2 Sende Intervallen für die beiden Nachrichten (100ms 
und 122ms) versucht, damit die nicht gleichzeitig versendet werden. hat 
aber nichts gebracht

Könnt Ihr mir helfen?

Nachtrag: ich habe mit dem Logic Analyse am Rx Pin geschaut, ID 100009 
ist vorhanden, ID 100010 nicht.


Gruß

Kay

: Bearbeitet durch User
von Sebastian W. (wangnick)


Lesenswert?

Kay L. schrieb:
> Ich habe schon mit 2 Sende Intervallen für die beiden Nachrichten (100ms
> und 122ms) versucht, damit die nicht gleichzeitig versendet werden. hat
> aber nichts gebracht

Ich glaube du hast previousMillis nur einmal. Wenn du die zwei 
Nachrichten unabhängig voneinander in bestimmten Intervallen verschicken 
möchtest, musst du dir aber für jede der Nachrichten separat merken wann 
du die vorherige verschickt hast.

LG, Sebastian

PS: Wofür ist diese ((counter % 2) == 0) Abfrage gut?

: Bearbeitet durch User
von Kay L. (kgbrus)


Lesenswert?

Hallo Sebastian,

vielen dank das war es. Wenn man nicht zu Ende überlegt.

Counter ist der Zähler, wie oft eine Nachricht versendet wurde und die 
Zeile stellt sicher, das nur einmal versendet wird.  Da müsste ich dann 
auch für jede Nachricht mit einem eigen counter arbeiten, richtig?

Gruß

Kay

von Ge L. (Gast)


Lesenswert?

Kay L. schrieb:

> meine "Sorge" ist halt (vielleicht habe ich da auch etwas nicht
> verstanden) das,
> wenn mehrere Empfänger eine Nachricht nutzen, dann sendet einer doch ein
> Bit "Übertragung Fehlerfrei" damit hört der Sender (bis zum nächsten
> Intervall) auf diese Nachricht zu senden

Das Acknowledge-Bit sendet jeder Teilnehmer, egal ob er die Botschaft 
nutzt oder nicht.

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.