Moin, ich habe hier ein Problem mit dem CAN - Bus des STM32. Beschreibung: Ein Testprogramm (in C/C++) schickt in einer Schleife Messages über den CAN - Bus und lässt in derselben Schleife eine LED blinken. Fall 1: Das Programm wird kompiliert für und läuft auf einem STM32F103RBT6 (medium density line, 128k, 20k). Am Oszilloskop sind die Bits der Message am CAN_TX - Pin zu sehen (idle: 3,3V). Die LED blinkt. Fall 1: Das gleiche Programm wird kompiliert für und läuft auf einem STM32F103RET6 (high density line, 512k Flash, 64k SRAM). Der CAN_TX - Pin bleibt allerdings auf 3,3 V. Die LED blinkt. Einziger Unterschied zwischen den Kompilierungen: verschiedene Linkerskripts (die sich im Anhang befinden). Hat vielleicht jemand eine Idee, woran das liegen könnte? Gruß, Jan
Die Platinen sind identisch? Die korrekte Funktion der CAN-Pins wurde mit GPIO-Operationen verifiziert? Die Testumgebung war in beiden Fällen identisch, auch was den angeschlossenen CAN-Bus angeht?
Welcher Compiler? Zeig uns das Programm. Wenn Du die FW Lib benutzt: Hast Du die globalen Symbole USE_STDPERIPH_DRIVER, STM32F10X_MD (STM32F10X_HD) korrekt gesetzt?
Moin, schon mal danke für die Anregungen. Die STM32F10X_HD/MD - defines waren tatsächlich falsch gesetzt, leider hat die Korrektur nichts verändert. Ich habe mal eine hoffentlich übersichtliches Testprogramm ohne allen irrelevanten Code angehängt. Der Compiler ist arm-none-eabi-g++, Version 4.4.1 Zum ausprobieren: einfach ein CANTestcase - Objekt erzeugen und die sendTestMessageInALoop() - Methode aufrufen. Dann wird in einer Schleife ca. alle 10ms eine CAN -Message gesendet und eine LED umgeschaltet (GPIO - Port und Pinnummer ggf. in CANTestcase::toggleLED() anpassen, im Moment ist es GPIOC.12) Code zum testen:
1 | CANTestcase cantest; |
2 | cantest.sendTestMessageInALoop(); |
Wenn der Pin als general-purpose push/pull configuriert wird, kann er geschaltet werden, das geht also. Leider sind die 2 verschiedenen Chips auf 2 verschiedenen Platinen. Der CAN - Transceiver ist allerdings vom gleichen Typ (SN65HVD230: http://www.ti.com/lit/ds/symlink/sn65hvd230.pdf). Gruß, Jan
Und hier noch der Anhang :)
Ist das gesetzt? RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE); Dann probiere mal das: CAN_InitStructure.CAN_ABOM = ENABLE; CAN_InitStructure.CAN_AWUM = ENABLE; CAN_InitStructure.CAN_NART = DISABLE;
NB, hat nichts mit dem Problem zu tun: // TODO why has the loop variable to be marked as volatile? It's just a standard for-loop, the actual value // of the variable should be evaluated without that. Schleifen ohne irgendwelche Auswirkungen auf den Rest vom Code dürfen geschlossen rausfliegen, wenn das nicht durch "volatile" verhindert wird. Ein Schalter "erzeuge besonders langsamen und platzraubenden Code" gehört noch nicht zum Inventar heutiger Compiler.
Könnte interessant sein, was das CAN_ESR Register zu vermelden hat. Nochmal die Frage: War in beiden Tests die exakt gleiche Testumgebung am CAN Bus aktiv? Befand sich beides Mal mindestens eine weitere CAN Node am Bus, die in gesendete Paketen das ACK setzt? Andernfalls befindet der CAN Controller auf "das war nix, nochmal versuchen", schaltet nach zu vielen Retries auf "bus off" und stellt sich tot.
Bevor man in eine TX Mailbox etwas reinschreibt sollte man sicher sein, dass sie nicht aktiv ist. "All TX registers are write protected when the mailbox is pending transmission (TMEx reset)." Die Lib stellt das zwar sicher, aber das führt ggf. dazu, dass sie effektiv nichts tut, nur den entsprechenden Fehlercode zurück liefert. Generell: Wenn etwas nicht funktioniert sollte man alle Möglichkeiten nutzen, etwas über den Erfolg/Misserfolg von Lib-Aufrufen zu erfahren und sich den Zustand des CAN-Controllers mal ansehen (diverse Status- und Error-Register). "Augen zu und durch" ist die falsche Strategie, insbesondere wenn ja schon weiss das sie nicht funktioniert.
Hier mein Testprogramm, welches auf einem 103RE läuft. can_send_test() hat noch einige Debugfunktionen drin (TFT...), weil ich damals auch Probleme beim senden hatte. Vielleicht hilft es Dir weiter.
1 | // Programm: CAN Funktionen
|
2 | // Achtung! KEINE GLEICHZEITIGE NUTZUNG MIT USB MÖGLICH!!!
|
3 | // Mikrocontroller: STM32F103RE
|
4 | // Speicher: 512KB FLASH, 64KB SRAM
|
5 | // Taktfrequenz: 8MHz, PLL: 72MHz
|
6 | |
7 | // System-Inlude
|
8 | #include <stddef.h> |
9 | #include "stm32f10x.h" |
10 | |
11 | #include <string.h> // Stringfunktion |
12 | #include <stdio.h> // Standardfunktion |
13 | #include <stdlib.h> // Standardbibliothek |
14 | |
15 | //***********************************************************************************************
|
16 | // CAN Initialisierung
|
17 | //***********************************************************************************************
|
18 | void init_can (void) { |
19 | CAN_InitTypeDef CAN_InitStructure; |
20 | CAN_FilterInitTypeDef CAN_FilterInitStructure; |
21 | NVIC_InitTypeDef NVIC_InitStructure; |
22 | |
23 | // CAN RX0 Interrupt
|
24 | NVIC_InitStructure.NVIC_IRQChannel = USB_LP_CAN1_RX0_IRQn; |
25 | NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; |
26 | NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; |
27 | NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; |
28 | NVIC_Init(&NVIC_InitStructure); |
29 | |
30 | |
31 | // CAN1 Periph clock enable
|
32 | RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE); // CAN1 Takt freigeben |
33 | RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE); // AFIO Takt freigeben (für Remapping) |
34 | |
35 | // PB8 als GPIO_Mode_IPU, PB9 als GPIO_Mode_AF_PP definiert (50MHz!)
|
36 | // Remapping CANRX und CANTX von PA11 und PA12 auf PB8 und PB9
|
37 | // (PA11/12 sind die USB-Pins)
|
38 | GPIO_PinRemapConfig(GPIO_Remap1_CAN1, ENABLE); |
39 | |
40 | // CAN Register init
|
41 | CAN_DeInit(CAN1); |
42 | CAN_StructInit(&CAN_InitStructure); |
43 | |
44 | // CAN cell init
|
45 | CAN_InitStructure.CAN_TTCM=DISABLE; |
46 | CAN_InitStructure.CAN_ABOM=DISABLE; |
47 | CAN_InitStructure.CAN_AWUM=DISABLE; |
48 | CAN_InitStructure.CAN_NART=DISABLE; |
49 | CAN_InitStructure.CAN_RFLM=DISABLE; |
50 | CAN_InitStructure.CAN_TXFP=DISABLE; |
51 | CAN_InitStructure.CAN_Mode=CAN_Mode_LoopBack; |
52 | //CAN_InitStructure.CAN_Mode = CAN_Mode_Normal;
|
53 | |
54 | // CAN Bitrate
|
55 | CAN_InitStructure.CAN_SJW=CAN_SJW_1tq; // SJW (1 bis 4 möglich) |
56 | CAN_InitStructure.CAN_BS1=CAN_BS1_12tq; // Samplepoint 72% |
57 | CAN_InitStructure.CAN_BS2=CAN_BS2_5tq; // Samplepoint 72% |
58 | |
59 | //CAN_InitStructure.CAN_Prescaler=1; // 2000 kbit/s
|
60 | //CAN_InitStructure.CAN_Prescaler=2; // 1000 kbit/s
|
61 | //CAN_InitStructure.CAN_Prescaler=4; // 500 kbit/s
|
62 | //CAN_InitStructure.CAN_Prescaler=5; // 400 kbit/s
|
63 | //CAN_InitStructure.CAN_Prescaler=8; // 250 kbit/s
|
64 | //CAN_InitStructure.CAN_Prescaler=10; // 200 kbit/s
|
65 | //CAN_InitStructure.CAN_Prescaler=16; // 125 kbit/s
|
66 | CAN_InitStructure.CAN_Prescaler=20; // 100 kbit/s |
67 | //CAN_InitStructure.CAN_Prescaler=40; // 50 kbit/s
|
68 | //CAN_InitStructure.CAN_Prescaler=80; // 40 kbit/s
|
69 | //CAN_InitStructure.CAN_Prescaler=200; // 10 kbit/s
|
70 | //CAN_InitStructure.CAN_Prescaler=1023; // ganz langsam
|
71 | |
72 | CAN_Init(CAN1, &CAN_InitStructure); |
73 | |
74 | // CAN filter init
|
75 | CAN_FilterInitStructure.CAN_FilterNumber=1; |
76 | CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask; |
77 | CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit; |
78 | CAN_FilterInitStructure.CAN_FilterIdHigh=0x0000; |
79 | CAN_FilterInitStructure.CAN_FilterIdLow=0x0000; |
80 | CAN_FilterInitStructure.CAN_FilterMaskIdHigh=0x0000; |
81 | CAN_FilterInitStructure.CAN_FilterMaskIdLow=0x0000; |
82 | CAN_FilterInitStructure.CAN_FilterFIFOAssignment=CAN_FIFO0; |
83 | CAN_FilterInitStructure.CAN_FilterActivation=ENABLE; |
84 | CAN_FilterInit(&CAN_FilterInitStructure); |
85 | |
86 | // CAN FIFO0 message pending interrupt enable
|
87 | CAN_ITConfig(CAN1, CAN_IT_FMP0, ENABLE); |
88 | }
|
89 | |
90 | //***********************************************************************************************
|
91 | // CAN Messange senden
|
92 | //***********************************************************************************************
|
93 | void can_send_test (void) { |
94 | uint8_t CanMailBox; |
95 | uint8_t CanTxStatus; |
96 | |
97 | printf_tft(1,60,"CAN Test: Senden einer Message"); |
98 | |
99 | // CAN Message senden
|
100 | CanTxMessage.StdId=0x00; |
101 | CanTxMessage.ExtId=0x1234; |
102 | CanTxMessage.IDE=CAN_ID_EXT; |
103 | CanTxMessage.RTR=CAN_RTR_DATA; |
104 | CanTxMessage.DLC=3; |
105 | CanTxMessage.Data[0] = 'P'; |
106 | CanTxMessage.Data[1] = 'R'; |
107 | CanTxMessage.Data[2] = 'O'; |
108 | CanMailBox = CAN_Transmit(CAN1, &CanTxMessage); // Rückgabe Mailbox-Nr. 0,1,3 (4=keine Mailbox frei) |
109 | if (CanMailBox == CAN_NO_MB) { |
110 | // Mailboxen voll mit ungesendeten Messages
|
111 | printf_tft(1,75,"--> keine Mailbox frei"); |
112 | } else { |
113 | // Mailbox verfügbar
|
114 | // Sendevorgang läuft
|
115 | sprintf(tft.buffer,"--> Mailbox-Nr.: %u",CanMailBox); |
116 | printf_tft(1,75,tft.buffer); |
117 | while(1) { |
118 | CanTxStatus = CAN_TransmitStatus(CAN1, CanMailBox); // Rückgabe 0=Fehler, 1=ok, 2=senden läuft noch |
119 | |
120 | sprintf(tft.buffer,"--> TxStatus: %u",CanTxStatus); |
121 | printf_tft(1,90,tft.buffer); |
122 | if (CanTxStatus == CANTXPENDING) { |
123 | // Message Sendevorgang läuft gerade
|
124 | printf_tft(1,105,"--> Sendevorgang aktiv!"); |
125 | |
126 | sprintf(tft.buffer,"EWG:%u EPV:%u BOF:%u TEC:%u",CAN_GetFlagStatus(CAN1, CAN_FLAG_EWG),CAN_GetFlagStatus(CAN1, CAN_FLAG_EPV), CAN_GetFlagStatus(CAN1, CAN_FLAG_BOF), (uint16_t)(CAN1->ESR >> 16) & 0x000000FF); |
127 | printf_tft(1,120,tft.buffer); |
128 | |
129 | }
|
130 | if (CanTxStatus == CANTXFAILE) { // CANTXFAILED bis V3.4.0 - V3.5.0 dann CANTXFAILE |
131 | // Fehler Message nicht gesendet
|
132 | printf_tft(1,135,"--> Senden nicht erfolgreich"); |
133 | break; |
134 | }
|
135 | if (CanTxStatus == CANTXOK) { |
136 | // Message gesendet und bestätigt
|
137 | printf_tft(1,135,"--> Senden OK"); |
138 | break; |
139 | }
|
140 | }
|
141 | }
|
142 | }
|
143 | |
144 | ...
|
145 | |
146 | // Interrupt Handler
|
147 | /*******************************************************************************
|
148 | * USB_LP_CAN1_RX0_IRQHandler
|
149 | *******************************************************************************/
|
150 | void USB_LP_CAN1_RX0_IRQHandler(void) { |
151 | |
152 | /*
|
153 | if (CAN_GetITStatus(CAN1, CAN_IT_FMP0) == SET) {
|
154 | // CAN Fifo0 Receive
|
155 | CAN_ClearITPendingBit(CAN1, CAN_IT_FMP0);
|
156 | }
|
157 | if (CAN_GetITStatus(CAN1, CAN_IT_FOV0) == SET) {
|
158 | // CAN Fifo0 Receive Overrun
|
159 | CAN_ClearITPendingBit(CAN1, CAN_IT_FOV0);
|
160 | }
|
161 | if (CAN_GetITStatus(CAN1, CAN_IT_FF0) == SET) {
|
162 | // CAN Fifo0 Receive Buffer full
|
163 | CAN_ClearITPendingBit(CAN1, CAN_IT_FF0);
|
164 | }
|
165 | */
|
166 | CAN_Receive(CAN1, CAN_FIFO0, &CanRxMessage); |
167 | |
168 | // if((CanRxMessage.ExtId==0x1234) && (CanRxMessage.IDE==CAN_ID_EXT) && (CanRxMessage.DLC==3)) {
|
169 | CanRxReady = 1; |
170 | // }
|
171 | }
|
Moin, danke für die vielen Hinweise und den Beispielcode. Sobald ich mehr weiß, schreibe ich hier davon. Gruß, Jan
Matthias K.(und alle anderen...) Wenn ich da mal fragen darf: PB8/9 werden bei dir nicht initialsiert. Ist das nicht notwendig? Ich krieg es irgendwie nicht ans rennen :(
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.