Forum: Mikrocontroller und Digitale Elektronik STM32F429I Discovery + CAN Bus: Und es geht doch.


von Thomas J. (ichabod)


Angehängte Dateien:

Lesenswert?

Nachdem ich mich jetzt zwei Tage lang mit dem CAN Bus am o.g. Discovery 
Board herumgeschlagen habe, möchte ich meine Erkenntnisse gerne mit euch 
teilen... gleich vorweg: es funktioniert... wenn auch mit einem faden 
Beigeschmack.

Das Setting
===========

Das STM32F429I Discovery Board ist ein etwas kräftigeres Board im 
Vergleich zum STM32F4-Discovery. Der Prozessor selbst ist mit 180 MHz 
etwas flotter (das STM32F4-Disco läuft mit 168 MHz), die Peripherie ist 
mit dem LCD-Touch Display etwas umfangreicher bestückt.

Von mir eingesetzt wird das Board zu Forschungszwecken in der 
Optimalsteuerung, wobei am PC eine Regelstrecke simuliert wird, der 
Regler sitzt auf dem Cortex-M4. Die Kommunikation erfolgt über CAN, 
wobei am PC der Low-Budget OpenSource Adapter "USBtin" als CAN-zu-USB 
Interface unter Linux betrieben wird (Super Teil! Danke, Thomas Fischl!)

Der STM32F429 des Boards verfügt über zwei native CAN Controller. 
Verdrahtet wird das RX/TX des Prozessors mit einem MCP2551 Transciever, 
der (das gibt manchmal Grund zur Diskussion) einfach mit RS ohne 
Widerstand auf Masse geschaltet ist.

Das Problem
===========

Die Umfangreiche Peripherie ist hier leider recht hinderlich. Beide CAN 
Ports werden mit alternativen Beschaltungen entweder für das Display 
(CAN1) oder für den USB to go Anschluss (CAN2) verwendet. Der naive 
Ansatz: wir brauchen den USB Port nicht, also klemmen wir den MCP2551 
einfach auf die GPIOB Pins 12/13 und legen los.

Was bei einigen von Euch wahrscheinlich gleich ein Augenrollen 
verursacht, erschien mir als fachfremde Person (Technomathematik) 
vorerst logisch. Die Quittung kam aber prompt. Das serielle Terminal am 
PC bleibt schwarz. Wie soll es auch anders, wenn das Signal am TX-Pin so 
genuschelt aussieht, wie auf dem ersten Bild? Ganz offensichtlich hängen 
da in der USB-Peripherie ein paar Widerstände und Kondensatoren herum, 
die aus den schönen digitalen Flanken Matschebrei machen.

Die Notlösung
=============

Schweren Herzens trennen wir uns also von der Funktion des LCD-Displays 
und versuchen das gleiche mit dem CAN1. Da die beiden Pins (GPIOA 11/12) 
auf dem Board als Signalleitungen für rote Bildinformationen verwendet 
werden kann (das Board wirbt mit mehreren Mio. Pixel pro Sekunde), 
erwarten wir ein knackiges Signal. Und tatsächlich: Das Signal passt 
(zweites Bild)... für den Preis, dass das LCD-Display nicht verwendet 
werden kann, was den Sinn des teureren STM32F429I Boards irgendwie in 
Frage stellt.

edit: In Kommentaren wurde angeregt, die CAN1-Alternative auf D0/1 zu 
verwenden. Die Ports sind mit dem SDRAM verbunden, was man ja nicht 
unbedingt brauche. Theoretisch ließe sich es sicherlich irgendwie 
hintricksen, wenn man sich die Zeit nehmen will, einen eigenen Display 
Treiber zu bauen. Wenn man aber mit möglichst wenig Aufwand die 
Peripherie-Bibliotheken des Boards verwenden möchte, klappt diese Lösung 
leider nicht, da diese das SDRAM als Frame Buffer verwenden. Weitere 
Portalternativen existieren im LQFP144 Format leider nicht.

Feintuning
==========

Wie auch immer. Was noch zu erwähnen ist: Das Board ist schneller 
getaktet, als das STM32F4-Disco. Viele Beispiele im Netz basieren jedoch 
auf diesem 168 MHz langsameren Board, weshalb wir das Timing des CAN 
Busses neu berechnen müssen... Der ABP1 Bus ist auf diesem Board mit 
einem Prescaler von vier auf 45 MHz getaktet. Die Examples sind für 42 
MHz geschrieben.

Wir berechnen also das Timing für das Board neu. Nehmen wir gleich 
1MBit/s auf dem CAN-Bus (wenn schon, denn schon...). Ein Bit braucht 
also 45*10^6 / 1*10^6 = 45 Takte. Es gilt also

45 Takte = CAN_Prescaler * (1 + CAN_BS1 + CAN_BS2)

Ein CAN_Prescaler von 5 macht sich hier ganz gut. Bleiben noch

CAN_BS1 + CAN_BS2 = 8

übrig. Damit das Sampling in der hinteren Hälfte stattfindet teilen wir 
die acht auf

CAN_BS1 = 5
CAN_BS2 = 3

auf. Und voila... USBtin und Board tauschen munter CAN-Frames aus. 
Leider ohne Display, weshalb der abschließende Erfolg mithilfe der 
beiden User-LEDs gekennzeichnet werden musste.

edit: In Kommentaren wurde angeregt, den Takt des Prozessors einfach in 
der SystemInit anzupassen. Das geht natürlich auch. Ich war so bequem, 
einfach die SystemInit des Touch-Panel Beispiels zu verwenden welche den 
Prozessor mit maximalen 180 MHz taktet. Die selektive Anpassung des 
CAN-Bus Takts ist hier sinnvoll, da andere Systemkomponenten davon nicht 
betroffen sind (im Gegensatz zum Ändern des Systemtakts).

Etwas Quellcode für Copy-Paster
===============================

Konfiguration der Ports:
1
GPIO_PinAFConfig(GPIOA, GPIO_PinSource11, GPIO_AF_CAN1);
2
GPIO_PinAFConfig(GPIOA, GPIO_PinSource12, GPIO_AF_CAN1);
3
4
GPIO_InitTypeDef GPIO_InitStructure;
5
6
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11 | GPIO_Pin_12;
7
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
8
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
9
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
10
GPIO_InitStructure.GPIO_PuPd  = GPIO_PuPd_UP;
11
GPIO_Init(GPIOA, &GPIO_InitStructure);

CAN Controller initialisieren
1
CAN_InitTypeDef CAN_InitStructure;
2
3
CAN_DeInit(CAN1);
4
5
CAN_InitStructure.CAN_TTCM = DISABLE;
6
CAN_InitStructure.CAN_ABOM = DISABLE;
7
CAN_InitStructure.CAN_AWUM = DISABLE;
8
CAN_InitStructure.CAN_NART = DISABLE;
9
CAN_InitStructure.CAN_RFLM = DISABLE;
10
CAN_InitStructure.CAN_TXFP = DISABLE;
11
CAN_InitStructure.CAN_Mode = CAN_Mode_Normal;
12
CAN_InitStructure.CAN_SJW = CAN_SJW_1tq
13
CAN_InitStructure.CAN_BS1 = CAN_BS1_5tq;
14
CAN_InitStructure.CAN_BS2 = CAN_BS2_3tq;
15
CAN_InitStructure.CAN_Prescaler = 5;   // Baudrate 1Mbaud
16
if (CAN_Init(CAN1, &CAN_InitStructure)) {
17
  GPIOG->BSRRL = GPIO_Pin_13; // Lichtle an, wenn's geklappt hat
18
}

CAN Filter soll alles rein lassen
1
CAN_FilterInitTypeDef CAN_FilterInitStructure;
2
3
CAN_FilterInitStructure.CAN_FilterNumber = 0;
4
CAN_FilterInitStructure.CAN_FilterFIFOAssignment = 0;
5
CAN_FilterInitStructure.CAN_FilterMode = CAN_FilterMode_IdMask;
6
CAN_FilterInitStructure.CAN_FilterScale = CAN_FilterScale_32bit;
7
CAN_FilterInitStructure.CAN_FilterIdHigh = 0x0000;
8
CAN_FilterInitStructure.CAN_FilterIdLow = 0x0000;
9
CAN_FilterInitStructure.CAN_FilterMaskIdHigh = 0x0000;
10
CAN_FilterInitStructure.CAN_FilterMaskIdLow = 0x0000;
11
CAN_FilterInitStructure.CAN_FilterActivation = ENABLE;
12
CAN_FilterInit(&CAN_FilterInitStructure);

Bequemen Frame-Empfang per Interrupt initialisieren
1
NVIC_InitTypeDef  NVIC_InitStructure;
2
3
NVIC_InitStructure.NVIC_IRQChannel = CAN1_RX0_IRQn;
4
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x0;
5
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x0;
6
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
7
NVIC_Init(&NVIC_InitStructure);
8
9
CAN_ITConfig(CAN1, CAN_IT_FMP0, ENABLE);

... und zu guter Letzt: Interrupt implementieren
1
void CAN1_RX0_IRQHandler(void)
2
{
3
  GPIOG->BSRRL = GPIO_Pin_14; // rotes LED an
4
5
  CanRxMsg RxMessage;
6
  CAN_Receive(CAN1, CAN_FIFO0, &RxMessage);
7
  /* .... Nachricht behandeln .... */
8
}

Fazit: Es geht, aber es bleibt fraglich, ob man nicht lieber das etwas 
kleinere STM32F4-Discovery Board verwenden sollte, wenn man nicht ohne 
CAN kann. Es kostet weniger und ist etwas leichter...

Trotzdem... viel Erfolg damit!

: Bearbeitet durch User
von Detlef K. (adenin)


Lesenswert?

Du kannst CAN1 alternativ auf GPIOD0 (RX) und GPIOD1 (TX) verlegen.

von pitschu (Gast)


Lesenswert?

Im Reference Manual (Tabelle 12 ab Seite 73) habe ich insgesamt 4 
alternative Pins für z.B. CAN1_RX gesehen. Irgendwas davon sollte doch 
frei sein.

von holger (Gast)


Lesenswert?

>Wie auch immer. Was noch zu erwähnen ist: Das Board ist schneller
>getaktet, als das STM32F4-Disco.

Nö, man kann es schneller takten, muss man aber nicht.

>Viele Beispiele im Netz basieren jedoch
>auf diesem 168 MHz langsameren Board, weshalb wir das Timing des CAN
>Busses neu berechnen müssen.

Nö, musst du nicht. Du kannst das Board auch mit 168MHz takten.
Wenn man USB benutzen möchte muss man das sogar.

>.. Der ABP1 Bus ist auf diesem Board mit
>einem Prescaler von vier auf 45 MHz getaktet.

Nö, hängt vom Haupttakt ab und ist nicht fix.

von Detlef K. (adenin)


Lesenswert?

GPIOD 0/1 hängen am SRAM.
PD0 an D2
PD1 an D3
Wenn Du den SRAM nicht benutzt müsste das gehen, und dein LCD ist wieder 
verwendbar.

von Grundschüler (Gast)


Lesenswert?

Thomas J. schrieb:
> dass das LCD-Display nicht verwendet
> werden kann, was den Sinn des teureren STM32F429I Boards irgendwie in
> Frage stellt.

Du kannst das lcd im spi-Modus benutzen. Das ist allemal schnell genug.

von Ert (Gast)


Lesenswert?

Es ist halt ein Discovery Board. Was haste den erwartet eine fertige 
Lösung für genau dein Problem?

Freu dich lieber das dein Anwendungsfall teilweise mit dieser 
Konfiguration gelöst werden konnte. :-)

von Thomas J. (ichabod)


Lesenswert?

Vielen Dank für die vielen Hinweise. Ich habe ein paar davon in dem 
How-To oben eingearbeitet. Port D0/1 zu verwenden geht leider nicht 
ad-hoc. Oben steht mehr dazu.

Ert schrieb:
> Es ist halt ein Discovery Board. Was haste den erwartet eine fertige
> Lösung für genau dein Problem?
Wieso eine fertige Lösung? Sicherlich nicht. Erwartet hatte ich 
naiverweise, alle für mich wichtigen Prozessorfunktionen verwenden zu 
können, und das gleichzeitig. Aber wie gesagt... naiverweise :)

> Freu dich lieber das dein Anwendungsfall teilweise mit dieser
> Konfiguration gelöst werden konnte. :-)
Habe ich... lautstark ;-)

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