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


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
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. (stefanus)


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.

: Bearbeitet durch User
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. (stefanus)


Lesenswert?

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

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

: Bearbeitet durch User
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..... ;-)

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.