Hallo,
ich arbeite nun schon etwas länger daran wie am besten mehr als 8 Byte
Nutzdaten per CAN Bus überträgt.
Da ich nichts gefunden habe, habe ich mich an kreatives-chaos.com
orientiert. Besser gesagt an deren CAN Bootloader:
http://www.kreatives-chaos.com/artikel/can-bootloader
Dazu vielen Dank an die Macher des Bootloaders und der can-lib!!
Ich habe mich für dieses Protokoll entschieden, da ich Slaves im
Netzwerk über den CAN Bus updaten will. Somit kann das Protokoll für den
Normalbetrieb und den Flashvorgang verwendet werden.
Im Normalbetrieb wird das Protokoll "abgespeckt" verwendet. D.h. z.B.
der Message_Counter wird nicht verwendet. Auch fehlen dann AKN/NAKN da
es sich bei mir im System um nicht so wichtige Daten handelt.
Der Source ist noch nicht 100%'ig und soll als Basis für andere dienen
die mehr als 8 Bytes übertragen wollen.
Ich selber übertrage im Normalfall ca. 10-15 Bytes. Es sind Daten wie
z.b. von einem DS2438 (Spannung & Temp) oder DS18S20 (Temp).
D.h. es werden die großen Distanzen mit CAN Bus überbrückt. Die OneWire
Kabel sind dann eher kurz gehalten.
Flashen mache ich über V-USB. Ich sende 32 Byte Pakete an den
CAN-Master. Dieser zerlegt sie in der SendCANMessage in die einzelnen
CAN Nachrichten und leitet sie an die angegebene Slave NodeID.
Um einen Atmega168 mit MCP2515 ein ~12kB Flash zu übertragen brauche ich
dann bei 10kbps ca. 72 Sekunden.
Wichtig ist noch bei can-lin:
In der "mcp2515_send_message" sollten am besten 2 TX Buffer deakiviert
werden. Somit steht nur ein TX Buffer zur Verfügung und es entsteht
Automatisch ein "Gänsemarsch" der CAN Nachrichten. Ansonsten dreht der
MCP2515 die Nachrichten durcheinander und der Message_Counter kommt aus
dem Takt.
Viel Spass damit!
Beispiel "WHO_IS_ONLINE" Request vom Master ans Netzwerk:
Der CAN Master ist der mit der NodeID 0x00.
Slaves sind mit der NodeID 0x01-0xFF.
Ich habe nur einen Master der die Schnittstelle vom CAN Bus System nach
"Aussen" ist. Die Slaves schicken ihre Daten an den Master, dieser gibt
sie nach Aussen (z.B. über RS232, V-USB,...) ab.
Hallo Hugo,
ich habe mir mal deinen Code angeschaut. Wo verwendest du diese Funktion
"WaitforCANResponse" ? Könntest du eine Beispielapplikation für den
Master hier reinposten ? Das wäre super. Danke.
Die "WaitforCANResponse" ist um auf ein AKN/NAKN zu warten.
Maximal 500ms. Er wartet auf eine Nachricht von der angegeben Node ID.
Andere Nachrichten die sich dazwischen schumeln werden in den Buffer
geladen.
Auch habe ich noch eine neue Funktion hinzugefügt um zu überprüfen ob
gerade ein Transfer aktiv ist: "CANTranserActive"
Ich habe im Master im Timer0 z.B. eine 1-Wire Devices Abfrage. Diese
sollte aber nur durchgeführt werden wenn gerade kein CAN Transfer aktiv
ist um Bufferüberlappungen zu verhindern.
Auch noch kurz zur Erklärung:
In der SendCANMessage wird die Message ID mit der Node Nummer "ver-ort".
D.h.
Master -> Slave:
CAN_NODE_NR = 0x00
aus 0x300 | CAN_NODE_NR = 0x300
Slave -> Master:
CAN_NODE_NR = 0x11
aus 0x300 | CAN_NODE_NR = 0x311
Das bedeutet, dass man durch die CAN_NODE_NR die Priorität der Slaves
steuern kann. Der mit der CAN_NODE_NR = 0x01 hat auf dem CAN Bus
gegenüber den Slave mit der CAN_NODE_NR = 0x02 Vorrang.
Der Filter ist bei den Slaves so eingestellt, dass nur Messages mit
0xX00 und der WHO_IS_ONLINE empfangen werden. Also nur Nachrichten vom
Master.
Die Slaves können sich nichts untereinander schicken. Das kann man aber
durch andere Filtereinstellungen ändern.
Der Master filtert keine Nachrichten und bekommt alle Message IDs.
Kurze Beispiele:
Slave:
1
CAN_HEADERcan_transfer;
2
uint8_tcan_message_count;
3
4
// filter for:
5
// receive only messages with matching node id 0xX00 (Messages from CAN Master)
6
// receive onyl message CAN_WHO_IS_ONLINE for response
7
prog_uint8_tcan_filter[]={
8
// Group 0
9
MCP2515_FILTER(0x000),// Filter 0
10
MCP2515_FILTER(0x000),// Filter 1
11
12
// Group 1
13
MCP2515_FILTER(CAN_WHO_IS_ONLINE),// Filter 2
14
MCP2515_FILTER(CAN_WHO_IS_ONLINE),// Filter 3
15
MCP2515_FILTER(CAN_WHO_IS_ONLINE),// Filter 4
16
MCP2515_FILTER(CAN_WHO_IS_ONLINE),// Filter 5
17
18
MCP2515_FILTER(0x0FF),// Mask 0 (for group 0)
19
MCP2515_FILTER(0x7FF),// Mask 1 (for group 1)
20
};
21
22
intmain(void)
23
{
24
uint8_tbuffer[64];
25
uint8_tlen;
26
27
cli();
28
29
/* Even if you don't use the watchdog, turn it off here. On newer devices,
30
* the status of the watchdog (on/off, period) is PRESERVED OVER RESET!
Die Steuerung der Slaves mache ich über V-USB. Kann aber per RS232
(uart_getc) auch gemacht werden. Die Befehle IDENTIFY, START_APP,
SET_ADDRESS und DATA werden nur für den echten CAN Bootloader für das
Flashupdate benötigt.
Im "receive_buffer" stehen die USB Daten vom Host:
receive_buffer[0]: Report ID
receive_buffer[1]: Command
receive_buffer[2]: Command Parameter
Master -> Slave Handling:
1
/* usbFunctionWrite() is called when the host sends a chunk of data to the
2
* device. For more information see the documentation in usbdrv/usbdrv.h.
returnbytesRemaining==0;/* return 1 if this was the last chunk */
120
}
Man beachte auch, dass maximal 4 * 0x0F an Datalength möglich ist.
Also maximal 64 Bytes die mit einer SendCANMessage möglich sind.
Hier noch ein Beispiel wie ich im Slave im Timer0 überprüfe ob ein neuer
IR-Code empfangen wurde. Die CAN Message ID IRMP_DECODED = 0x300.
1
voidcheck_for_new_irmp_data(void)
2
{
3
if(irmp_get_data(&irmp_data))
4
{
5
if(!(irmp_data.flags&IRMP_FLAG_REPETITION))// first check if the IR command is repeated
6
{
7
RepeatCounter=0;// new command received, reset RepeatCounter
8
}
9
else
10
{
11
RepeatCounter++;// still the same command, inc RepeatCounter
12
}
13
14
if((RepeatCounter==0)|(RepeatCounter>=MinRepeats))// only send interrupt if first command, or Repeatcounter >= MinRepeats
15
{
16
if(RepeatCounter>=MinRepeats)
17
RepeatCounter=MinRepeats;// fix overflow for long key push
Anbei auch ein Bild wie ich dann die Daten per V-USB auf dem Windows PC
auswerte.
Beispiel:
Device Data: USB AVR Device, (USB Device Name)
ReportID: 0x01, (USB Report ID)
NodeID: 0x11, (CAN Node ID von wo die Daten
kommen)
Command: 0x09, (CAN Command (Temperatur CMD))
Length: 0x0E, (Daten länge)
Data: 0x26F610550100002FE900F401A900 (eigentliche Daten)
{26}F61055010000[2F] ({DS2438 Family} Serial [CRC-8]])
E900 (Temperatur: 23,3°C)
F401 (Versorgungsspannung: 5,00V)
A900 (Sensorspannung: 1,69V)
MarcusW schrieb:> Kennst du das hier:>> http://de.wikipedia.org/wiki/ISO_15765-2>> Ansonsten natürlich immer gut, wenn man sich selber Gedanken macht und> eine Lösung findet.
Danke für den Tipp!
Aber mein Ziel war es, dass ich ja von einem CAN Teilnehmer einen
anderen per CAN (CAN Bootloader) updaten kann. Darum habe ich mich an
das "Protokoll" von kreatives-chaos.com gehalten.
Hallo Huga,
erstamal danke für den Code. Was mir noch aufgefallen ist, das die
FUnktion WaitforCANResponse nicht in der Master Applikation verwendet
wird. Eigentlich müsste ein Timeout im Master implementiert werden. Beim
Slave macht es keinen Sinn! Wenn der Master nach einer gewissen Zeit
kein Response vom Slave bekommt dann sollte der Timeout zuschlagen.
Leo schrieb:> Hallo Huga,>> erstamal danke für den Code. Was mir noch aufgefallen ist, das die> FUnktion WaitforCANResponse nicht in der Master Applikation verwendet> wird. Eigentlich müsste ein Timeout im Master implementiert werden. Beim> Slave macht es keinen Sinn! Wenn der Master nach einer gewissen Zeit> kein Response vom Slave bekommt dann sollte der Timeout zuschlagen.
Die WaitforCANResponse verwende ich nur in der usbFunctionWrite.
Also im Master. Hauptsächlich nur wegen den originalen CAN Bootloader.
Die WaitforCANResponse überprüft ca. 500ms lang ob eine passende
Nachricht empfangen wird.
z.b. im switch case IDENTIFY schicke ich eine CAN Message vom Master an
den Slave. Danach wird auf einen Response von dem Slave gewartet.
Im normalen Datentransfer zwischen den CAN Nodes verzichte ich auf eine
Bestätigung.
Sucht mal im Netz unter BOSCH CAN_FD bzw. CAN Flexible Datarate.
Hier geht mehr Datenrate und mehr Payload. Es wird aber noch dauern, bis
die Chips verfügbar sein werden...
Hallo Huga,
mich würde mal ibnteressieren, ob dein CAN Transportprotokoll auch dann
noch funktioniert, wenn niederpriore CAN Nachrichten auf dem Bus
vorhanden sind.
Durchgetestet habe ich es noch nicht zu 100%.
Aber als Beispiel:
Der "Master" empfängt einen Datentransfer von 5 Nachrichten mit der
MSGID 0x302.
Jetzt kommt aber dazwischen ein anderer auf die Idee einen Transfer mit
der MSGID 0x301 auf den Weg zu schicken.
Somit schummelt sich die 0x301 zwischen den 0x302 Nachrichten.
Der "Master" weis aber, dass der angefangen Transfer von der 0x302 noch
nicht fertig ist und buffert somit automatisch die 0x301 Nachrichten.
Erst wenn der Transfer mit der 0x302 vorbei ist wird der Buffer mit den
0x301 Nachrichten abgearbeitet.
Das Priority/Kollision Handling wird von MCP2515 selber erledigt.