mit dieser Library kann die CAN-Schnittstelle vom STM32F4 benutzt werden
die CAN-Pins die benutzt werden sollen, müssen im C-File eingetragen werden
(im H-File kann die CAN-Baudrate eingestellt werden)
es gibt zwei identische Librarys, getrennt für CAN-1 und CAN-2
die Filter-Funktionen vom STM32F4 sind sehr Umfangreich. Ich habe versucht alles so einfach wie möglich zu halten, aber es wurden trotzdem 4 Funktionen.
(Beschreibung siehe unten)
es können CAN-Frames in den 4 Modes :
[standard_Data, standard_Remote, extended_Data, extended_Remote]
gesendet und empfangen werden
es muss ein externer CAN-Transeiver-IC angeschlossen werden (z.B. SN65HVD230D) und der Terminations-Widerstand (120 Ohm) für den BUS darf nicht vergessen werden.
Filterbeschreibung :
Die Filter dienen dazu um CAN-Frames die für die CPU nicht wichtig sind wegzufiltern. Es können Filter für “standard” und “extended” CAN-Frames gesetzt werden.
Direkt nach der Init Funktion sind keine Filter aktiv und alle Frames werden empfangen.
Für CAN1 können bis zu 14 Filter eingerichtet werden (Nr. 0…13)
Für CAN2 könen bis zu 14 Filter eingerichtet werden (Nr. 14 bis 27)
Filter-Liste : alle empfangenen CAN-Frames werden mit den Einträgen in der Liste verglichen, wenn die ID+Mode übereinstimmt landet der Frame im Empfangspuffer.
dieser Filter kann man dann einsetzen, wenn man einzelne CAN-IDs freigeben will.
(z.B. 4 einzelne IDs : 0×123, 0×463, 0×228, 0×447)
Filter-Maske : alle empfangenen CAN-Frames werden mit einer Maske versehen und dann mit der ID+Mode verglichen, bei Übereinstimmung landet der Frame im Empfangspuffer.
Alle Bits die in der Maske auf ’1′ stehen, müssen mit der ID übereinstimmen.
Alle Bits die in der Maske auf ’0′ stehen, können einen beliebigen wert haben.
diesen Filter kann man dann einsetzen, wenn man ganze ID-Blöcke freigeben will.
(z.B. 16 IDs : 0×120 bis 0x12F)
Bilder :
im Beispiel wurde CAN-1 mit dieser Pin-Belegung benutzt :
1 2 | CAN_TX an PB9 CAN_RX an PB8 |
Voraussetzungen :
1 2 | Benutzte Module der CooCox-IDE : GPIO, CAN, MISC Benutzte Librarys : keine |
Enumerationen (für CAN1) :
1 2 3 4 5 6 | typedef enum { CAN1_STD_DATA =0, // standard Daten-Frame CAN1_STD_REMOTE, // standard Remote-Frame CAN1_EXT_DATA, // extended Daten-Frame CAN1_EXT_REMOTE // extended Remote-Frame }CAN1_FRAME_MODE_t; |
:
1 2 3 4 | typedef enum { CAN1_RX_EMPTY =0, // noch kein CAN-Frame empfangen CAN1_RX_READY // CAN-Frame wurde empfangen }CAN1_STATUS_t; |
TX-Struktur :
1 2 3 4 5 | typedef struct { uint32_t can_id; // STD=11bit EXT=29bit uint8_t anz_bytes; // anzahl der daten [0...8] uint8_t data[8]; // datenbytes }CAN1_TX_FRAME_t; |
RX-Struktur :
1 2 3 4 5 6 | typedef struct { CAN1_FRAME_MODE_t frame_mode; // Frame-Mode uint32_t can_id; // STD=11bit EXT=29bit uint8_t anz_bytes; // anzahl der daten [0...8] uint8_t data[8]; // datenbytes }CAN1_RX_FRAME_t; |
Funktionen (für CAN1) :
1 2 3 4 5 6 | void UB_CAN1_Init(void); // zum init der CAN-Schnittstelle ErrorStatus UB_CAN1_send_std_data(CAN1_TX_FRAME_t tx_frame); // zum senden von standard data frames ErrorStatus UB_CAN1_send_std_remote(CAN1_TX_FRAME_t tx_frame); // zum senden von standard remote frames ErrorStatus UB_CAN1_send_ext_data(CAN1_TX_FRAME_t tx_frame); // zum senden von extended data frames ErrorStatus UB_CAN1_send_ext_remote(CAN1_TX_FRAME_t tx_frame); // zum senden von extended remote Frames CAN1_STATUS_t UB_CAN1_receive(CAN1_RX_FRAME_t *rx_frame); // zum empfangen von Frames |
Filter-Funktionen (für CAN1) :
1 2 3 4 | void UB_CAN1_std_FilterList(CAN1_STD_FL_t filter, uint8_t nr); // 1...4 Filter für std-ID void UB_CAN1_std_FilterMask(CAN1_STD_FM_t filter, uint8_t nr); // 1..2 Filter+Maske für std-ID void UB_CAN1_ext_FilterList(CAN1_EXT_FL_t filter, uint8_t nr); // 1..2 Filter für ext-ID void UB_CAN1_ext_FilterMask(CAN1_EXT_FM_t filter, uint8_t nr); // 1 Filter+Maske für ext-ID |
Beispiel :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 | //-------------------------------------------------------------- // File : main.c // Datum : 14.09.2013 // Version : 1.0 // Autor : UB // EMail : mc-4u(@)t-online.de // Web : www.mikrocontroller-4u.de // CPU : STM32F4 // IDE : CooCox CoIDE 1.7.4 // GCC : 4.7 2012q4 // Module : CMSIS_BOOT, M4_CMSIS_CORE // Funktion : Demo der CAN-LoLevel-Library // Hinweis : Diese zwei Files muessen auf 8MHz stehen // "cmsis_boot/stm32f4xx.h" // "cmsis_boot/system_stm32f4xx.c" //-------------------------------------------------------------- #include "main.h" #include "stm32_ub_led.h" #include "stm32_ub_can1.h" int main(void) { uint32_t delay=0; uint8_t wert=0; CAN1_TX_FRAME_t myTXFrame; // Puffer für TX-Daten CAN1_RX_FRAME_t myRXFrame; // Puffer für RX-Daten SystemInit(); // Quarz Einstellungen aktivieren // Init der LEDs UB_Led_Init(); // Init vom CAN-1 (an PB8+PB9) UB_CAN1_Init(); while(1) { //--------------------------- // senden //--------------------------- delay++; if(delay>5000000) { // zyklisch ein CAN-Telegramm senden delay=0; UB_Led_Toggle(LED_GREEN); // telegramm erstellen myTXFrame.can_id=0x123; // ID ist egal myTXFrame.anz_bytes=1; // ein Datenbyte wird gesendet myTXFrame.data[0]=wert; // Datenwert // Frame senden UB_CAN1_send_std_data(myTXFrame); // Datenwert wird nach jedem senden incrementiert wert++; } //--------------------------- // empfangen //--------------------------- if(UB_CAN1_receive(&myRXFrame)==CAN1_RX_READY) { // es wurde etwas empfangen UB_Led_Toggle(LED_BLUE); // Datenbyte auswerten (nur als Demo) if((myRXFrame.data[0]&0x02)!=0) { // beim empfangenen Datenwert ist das Bit1 gesetzt UB_Led_Toggle(LED_RED); } } } } |
Hier die Library zum Download :
Hier der komplette CooCox-Projektordner zum Download :
Super Arbeit. Danke sehr.
Ich habe hier viel gelernt…
Seit ein Paar Tage versuche ich CAN und USB gleichzeitig zu nutzen, aber es sieht, das beide libs nicht kompatibel sind… CAN schnittstelle functioniert einwandfrei bis man einen USB Stick anschließt. Und beide, CAN und USB libs funktionieren bei mir ohne Probleme, aber nur getrennt…
Hast du es irgendwann zufälligerweise probiert?
Beim STM32F1 geht die Kombination nicht…beim F4 müsste es eigentlich laufen, habe es aber selbst nicht ausprobiert.
Hallo nochmals,
ich kapiere leider noch nicht warum beide Beispiele, CAN und USB_HOST, beim F4DISCOVERY nicht kompatible sind… Beide funktionieren ohne Probleme aber sobald ich beide CooCox Projekte fusioniere, läuft CAN nur bis ich den USB Stick einschließe und danach nicht mehr. Test-Datei „USB_File.txt” wird generiert, aber auch nur das erste Mal, dass den USB Stick eingeschlossen wird… Hat jemand Ahnung, warum es sein kann?
Danke sehr!
SOLVED: Ich habe den STM Board einfach per USB eingeschaltet, aber mein Laptop gibt nicht genug Strom um USB und CAN gleichzeitig nutzen zu können, und deswegen funktionierten beide nicht gleichzeitig… verrückt!
Deine Website ist super. Daumen hoch.
Meine Frage ist, ob es möglich ist mit dem F4 per CAN im DMA-Mode zu senden und empfangen. Mit der UART ist das problemlos möglich. Aber auch mit CAN?
so wie ich das im RefManual gesehen habe nicht.
Ich möchte mal ein Dankeschön für diese Arbeit aussprechen, die du hier geleistet hast. Deine ganzen Beispiele haben es mir ermöglicht, innerhalb kurzer Zeit das STM32F4 Discovery Board zu verstehen und damit einen CAN Bus aufzubauen.
Das war und ist definitiv eine große Unterstützung gewesen
MfG
Niko
Hallo,
zunächst möchte ich mich für diese super Seite bei dir bedanken! Hat mir schon viel weitergeholfen.
Im Moment versuche ich gerade an meinem STM32F4 Disco Board den CAN in Betrieb zu nehmen, allerdings habe ich folgendes Problem:
Ich habe zum Testen deine CAN_LO_Level Demo heruntergeladen und kompiliert. Alles prima soweit. Wenn ich nun aber ein Oszi an die beiden CAN Pins hänge (PB8 + PB9) kommen da einfach nur dauerhaft ~3 V raus.
Dann hab ich gesehen, dass du schreibst ein externer Transciever sollte dran sein, also hab ich den ISO1050 den ich im Projekt verwenden möchte dran gehängt, inkl. 120 Ohm Abschlusswiderstand und dann gemessen. Nun komen aus den beiden Pins dauerhaft ~ 1,6 V raus, aber ein Signal kann ich leider nicht erkennen.
Kannst du mir da weiterhelfen?
Viele Grüße
Ralph
CAN braucht eine Gegenstelle sonst bricht das senden einfach ab. Du musst das Oszi auf “Single-Trigger” stellen um da was zu sehen. Oder mach den ISO1050 nochmal weg und verbinde PB9 und PB8 vom Prozessor, dann werden zwar ständig Telegramme gesendet aber zumindest siehst du was am TX-Pin PB9.
Hallo,
erstmal möchte ich die tolle Arbeit loben. Das hat mich beim Verständnis sehr geholfen.
Ich wollte zusätzlich den CAN2 nutzen und habe dein Code erweitert.
Aber das Problem ist, dass ich über CAN2 nur senden kann, aber nicht empfangen.
CAN1 kann ich ganz normal senden und empfangen.
Ich habe festgestellt, dass CAN2_RX0_IRQHandler() gar nicht aufgerufen wird wenn eine neue Botschaft über CAN2 kommt.
Gibt es da ein Trick?
Ich wäre sehr dankbar wenn jemand mir helfen könnte.
ich habe damals CAN1 und CAN2 getestet (allerdings nicht CAN1+CAN2). Lass mal in der Software die CAN1-Files komplett weg (event. stören die sich) und setze keine Filter ob es dann funktioniert.
Hast du verifiziert das die Pegel am RX-Pin der CPU stimmen ?
Es lag an der falschen Filterbank. Filterbank 0 bus 13 sind für CAN1 und Filterbank 14 bis 27 sind für CAN2. Deshalb konnte über CAN2 nichts empfangen werden, weil eben der Filter nichts durchgelassen hat.
Danke!
ok, diese Info steht oben im Text, im Sourcecode und im RefManual
und in meinem Quellcode wird eine falsche Filternummer gar nicht zugelassen.