Forum: Mikrocontroller und Digitale Elektronik STM32F103: CAN - Bus funktioniert bei Medium-Density-, nicht aber bei High-Density device


von Jan Bolting (Gast)


Angehängte Dateien:

Lesenswert?

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

von (prx) A. K. (prx)


Lesenswert?

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?

von Matthias K. (matthiask)


Lesenswert?

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?

von Jan Bolting (Gast)


Lesenswert?

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

von Jan Bolting (Gast)


Angehängte Dateien:

Lesenswert?

Und hier noch der Anhang :)

von Markus M. (Firma: EleLa - www.elela.de) (mmvisual)


Lesenswert?

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;

von (prx) A. K. (prx)


Lesenswert?

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.

von (prx) A. K. (prx)


Lesenswert?

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.

von (prx) A. K. (prx)


Lesenswert?

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.

von Matthias K. (matthiask)


Lesenswert?

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
}

von Jan Bolting (Gast)


Lesenswert?

Moin,

danke für die vielen Hinweise und den Beispielcode. Sobald ich mehr 
weiß, schreibe ich hier davon.


Gruß,
Jan

von tecdroid (Gast)


Lesenswert?

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
Noch kein Account? Hier anmelden.