STM32CubeMX Testprojekt für die STM32-CAN Hardware

Dies ist mein erster Versuch um mich mit dem CubeMx vertraut zu machen.
Hinweise, was man besser machen kann sind willkommen!

Das Projekt ist auf Github hinterlegt:  Github: STM32-CAN - CubeMX Testprojekt 

Ziel ist es erst mal nur die LEDs anzusteuern zu können und über  CAN1 (Hight-Speed Treiber) CAN-Botschaften zu senden und empfangen zu können.

Dazu sind im Cube-Mx erst mal folgende Schritte erforderlich:

  1. Konfiguration der Prozessor Pins im Reiter "Pinout"

    CubeMX Pin Konfiguration
    Abb. 1.1 - Pin Konfiguration

    Hier werden die Pins für :
    - externer Quarz
    - CAN1/2   Tx/Rx Pins
    - CAN_RS - Steuerleitung für den High-Speed CAN-Treiber (low=aktiv, high bzw. Input Float  =standby Mode)
    - nCAN2_STB - Steureleitung für den Low-Speed CAN-Treiber
    - Inputs (PullUp) für den Jumper S2  (PA2,PC2)
    - LED Ausgänge (Push Pull)

  2. Clock Konfiguration:
    Der STM wird auf die maximale mögliche Clocks die mit einem externen 8 MHz Quarz möglich sind konfiguriert (Systemtak 72Mhz mittels PLL)

    CubeMx- Clockkonfiguration
    Abb 1.2  Clock-Konfiguration



  3. Konfiguration der einzelnen Hardwaremodule

    Konfigurationsübersicht aller CubeMX Module
    Abb. 1.3 Konfigurations übersicht

    CubeMX - CAN1 Parameter Settings
    Abb.1.4 CAN1-Parameter

    CAN1 Settings:
    - Baudrate 500 kBit
    - normal Mode  


    CubeMx - CAN1 ISR
    Abb. 1.5  ISR-Settings

    CubeMX - CAN1 GPIO-Settings
    Abb. 1.6 CAN1-GPIO-Settings

    CAN2 wird auf gleicherweise konfiguriert, wird hier aber nicht weiter betrachtet, das hier erst mal nur CAN1 verwendet wird.


    CubeMX - GPIO Pins Konfiguration
    Abb. 1.7  GPIO-Pin Konfiguration


    Die restlichen Einstellungen bleiben auf Default und jetzt kann mit "Generate Code" kein Keil V5 Projekt erzeugt werden.

    Dies Keil-Project hat dann folgenden Aufbau:

    Projekt Struktur vom generierten Keil Projekt


Achtung ist veraltet und gilt nur für die HAL-Version < 1.7

Anpassungen im erzeugten Keil-Projekt

 Bei Anpassungen im Code sollte man darauf Achten, dass man seinen Code nur in den  "USER CODE" Bereichen:
 /* USER CODE BEGIN 2 */

 /* USER CODE END 2 */

ändert, damit die Anpassungen nicht beim erneuten Generieren vom Keil Projekt überschrieben werden.
Die genaue Anpassungen im Code könnnen dem fertigen Projekt (s.o) entnommen werden.

Hier möchte ich nur auf ein paar grundsätzliche Dinge eingehen:

  • Ansteuerung der LEDs und sonstige Pins:
    Die Pins können direkt mit der Funktion HAL_GPIO_WritePin(...); angesteuert werden. Und zwar unter Verwendung der Namen die bei der Pinkonfiguration für die Pins eingetragen wurden. 
    /* USER CODE BEGIN 2 */ 
    HAL_GPIO_WritePin(LED_RED_GPIO_Port,LED_RED_Pin,GPIO_PIN_SET);
    HAL_GPIO_WritePin(LED_BLUE_GPIO_Port,LED_BLUE_Pin,GPIO_PIN_RESET); HAL_GPIO_WritePin(CAN_RS_GPIO_Port,CAN_RS_Pin,GPIO_PIN_RESET); // enable 82C250 HS


    Obiges Beispiel schaltet die rote LED ein und setzt die Ausgänge für die blaue LED und den CAN_RS Pin auf 0.

  • CAN Messages senden/empfangen
    Für das CAN-Handling sind ein paar Schritte mehr nötig:

    1.)  Variablen für die CAN-Daten anlegen:
    /* USER CODE BEGIN PV */
    static CanTxMsgTypeDef myTxMessage; 
    static CanRxMsgTypeDef myRxMessage; 
    static CAN_FilterConfTypeDef myFilter; 
    /* USER CODE END PV */ 


    2.) Prototypen für den CallbackHandler für Rx-Botschaften anlegen

    /* USER CODE BEGIN PFP */
    /* Private function prototypes -----------------------*/ 
    void HAL_CAN_RxCpltCallback(CAN_HandleTypeDef* hcan); 


    Diese Funktion wird jedesmal beim Empfang einer CAN-Botschaft aufgerufen

    3) Senden einer CAN Botschaft (std Format):
    hcan1.pTxMsg = &myTxMessage; 
    
    myTxMessage.DLC = 4; 
    myTxMessage.StdId = 0x234; 
    myTxMessage.IDE = CAN_ID_STD; 
    
    HAL_CAN_Transmit_IT(&hcan1); 


    Wichtig hierbei ist nur, dass man nicht vergisst als erstes den Pointer auf die TxMessage zu setzen, da man sonst irgendeinen Speicherbereich überschreibt, was meistens in einen Hardfault endet.
    Im obigen Besipiel wird folgende CAN-Botschaft: 
    0x234 4 00 00 00 00 
    gesendet.

    Und hier noch ein Beispiel für eine Extende CAN-Botschaft:
    myTxMessage.DLC = 3; 
    myTxMessage.ExtId = 0x14F00500; 
    myTxMessage.IDE = CAN_ID_EXT; 
    myTxMessage.Data[0] = 0xAA; 
    
    HAL_CAN_Transmit_IT(&hcan1); 

    4) Empfang einer CAN-Botschaft
    Jetzt wird als erstes der CallBackHandler für die Rx-Botschaften definiert:
    /* USER CODE BEGIN 4 */ 
    void HAL_CAN_RxCpltCallback(CAN_HandleTypeDef* hcan) { 
        HAL_GPIO_TogglePin(LED_BLUE_GPIO_Port,LED_BLUE_Pin);
    
        // todo  ... CAN-Daten verarbeiten
    
        __HAL_CAN_ENABLE_IT(hcan, CAN_IT_FMP0); // hier mal fest FMPIE0 wieder freigeben, damit weitere CAN-Botschaften (CAN RX ISR ausgelöst werden)
    }
    Die blaue LED wird beim Empfang einer CAN-Botschaft getoggelt.

    Die Rx-Botschaften sollen im nicht blockiert Modus (ISR) abgearbeitet werden. Dazu sind folgende Schritte erforderlich:
    1) Empfangs Filter einrichten (alle IDs mittels Filtermaske erlauben)
    2) Pointer auf die Empfangs Struktur setzen.
    3) ISR empfangsroutinge Aufrufen  ( auf eine Fehlerbehandlung wird erst mal verzichtet)

    myFilter.FilterNumber = 0; 
    myFilter.FilterMode = CAN_FILTERMODE_IDMASK; 
    myFilter.FilterScale = CAN_FILTERSCALE_32BIT; 
    myFilter.FilterIdHigh = 0x0000; 
    myFilter.FilterIdLow = 0x0000; 
    myFilter.FilterMaskIdHigh = 0x0000; 
    myFilter.FilterMaskIdLow = 0x0000; 
    myFilter.FilterFIFOAssignment = 0; 
    myFilter.FilterActivation = ENABLE; 
    
    HAL_CAN_ConfigFilter(&hcan1,&myFilter); 
    
    hcan1.pRxMsg= &myRxMessage;
    
    ......  //  und in der main Hauptschleife erfolgt dann der Aufruf:
    /* USER CODE BEGIN 3 */ 
    
    // Korrektur, dieser Aufruf in der Hauptschleife war eine Fehlinterpetation von mir 
    // HAL_CAN_Receive_IT(&hcan1,CAN_FIFO0); 
    
    /* Das Problem ist das die Funktion "HAL_CAN_Receive_IT" vom IRQ-Handler:
       - HAL_CAN_IRQHandler()  aufgerufen wird.
    
         Und in dieser Funktion wird das FMPIE-Bit zurückgesetzt
         // Disable FIFO 0 message pending Interrupt 
         __HAL_CAN_DISABLE_IT(hcan, CAN_IT_FMP0);
    
         Und dieser Handler wird wieder vom CAN-RX ISR aufgerufen.
    
       - CAN1_RX0_IRQHandler() // CAN-ISR Handler
    
       Dies hat nun zur Folge das keine weiteren Empfangs ISR ausgelöst werden.
    
       Lösung:
       In der Call-Back Funktion "CAN_RxCpltCallback()" muss der Fifo0 Interupt wieder freigegeben werden
    
      __HAL_CAN_ENABLE_IT(hcan, CAN_IT_FMP0); // hier mal fest FMPIE0 freigeben
    
     Deshalb wird nun in USER CODE BEGIN 3   nichts eingetragen.
    
    */  
    
    */
     

Zur Erinnerung, hier ist das komplette Projekt abgelegt:
 Github: STM32-CAN - CubeMX Testprojekt 

Dort ist auch noch ein eigener SysTickCallBack Handler implementiert um eigene Delay-Varriablen zu Verwalten, um z.B. Botschaften zyklisch senden zu können.

20.02.2016:  Das Projekt auf Github wurde jetzt um die USB-Funktionalität und um das Grundgerüst für die Verarbeitung von Lawicel - Befehle erweitert.  

Mit dem Makro PING_PONG werden alle empfangenen Zeilen auf als Echo zurückgesendet, dies dient nur zum Testen im Terminal um zu sehen, ob die USB-Kommunikation auch funktioniert.
Das Lawicel Grundgerüst besteht erst mal aus den Befehlen:

  • V - Software Versionsnummer
  • v -  Hardware Versionsnummer
  • unbekannte Befehle werden mit dem Error-Status (0x07) quittiert.

 

17.07.2016:  Das Projekt auf Github wurde jetzt um weitere Lawicel - Befehle erweitert, so dass der CAN-Hacker die empfangene CAN-Botschaften in der RX/Trace Liste anzeigt.

Folgende Lawicel Befehle werden jetzt in der Version V0.3 unterstüzt:

  • Sn[CR]  - Auswahl diverser Standardbaudraten
  • sxxyy[CR]  - Auswahl diverser benutzerdeifinierten Baudraten  (s. Dokumentation zu STM32-CAN§)
  • O[CR] - CAN Kanal im "normalen Modus" öffnen
  • L[CR] - CAN Kanal im "Listen only Modus" öffnen
  • C[CR] - CAN Kanal schließen
  • Zn[CR] - Zeitstempel für die empfangene CAN-Botschaften "EIN"/"AUS"
  • Das Senden von Extend/Standard Botschaften vorbereitet (sende immer die gleiche Testmessage
  • Empfang von Standard und Extended CAN-Botschaften (RX: tiiildd...[CR] und Tiiiiiiiildd...[CR])
    Somit werden die Botschaften im CAN-Hacker angezeigt

Das Senden der Testbotschaft beim Anschließen an USB wurde entfernt. Die Testbotschaft wird jetzt nur noch beim Sendewunsch gesendet (Std oder Extend ID).