STM32F4-Discovery

Wechseln zu: Navigation, Suche

Dieser Wiki-Artikel soll den Einstieg in die Prozessorfamilie STM32 von STMicroelectronics erleichtern. Der Artikel begleitet dich von der Installation der benötigten Software bis hin zum flashen des Beispiels in den Prozessor.
Da es für Windows schon einiges im Internet zu finden gibt, wird die Installation der Toolchain für Linux beschrieben. Die verwendeten Tools sind allerdings als Quelltext oder als Windows-Installation verfügbar, somit lassen sich die meisten Schritte auch auf Windows-Betriebssystemen nachvollziehen.

Hardware

Das in diesem Artikel verwendete Board STM32F4-Discovery lässt sich z.B. bei Watterott oder in der Schweiz bei Thinkembedded bestellen. Es lassen sich auch andere Boards verwenden, allerdings müssen die Beispiele dem Schaltplan entsprechend angepasst werden.

Software

Installation Linux

Um das Dateisystem möglicht sauber zu halten installiere ich hier sämtliche Software in das Unterverzeichnis /opt welches für solche Installationen vorgesehen ist. Damit auf dieses Verzeichnis schreibend zugegriffen werden darf sind root-Rechte erforderlich. Ich werde vor den Befehlen immer den Prompt schreiben damit zu erkennen ist welche Rechte notwendig sind.

Es ist natürlich auch möglich alles in sein Heimat-Verzeichnis zu schreiben, hier kommt man dann grössten Teils ohne root-Rechte aus. Das muss aber jeder für sich selbst entscheiden wie er es mag.

Nicht alle Linux-Distributionen sind gleich, ich arbeite hier mit einem (fast) frischem Lubuntu 11.10. Der grösste Teil sollte also mit Ubuntu und Debian-Systemen funktionieren. Für andere Distributionen kann man den entsprechenden Abschnitt editieren oder auf der Diskussion:STM32F4-Discovery zu diesem Artikel vermerken.

Auswahl der Toolchain

Die unten beschriebene "lite-edition" der Sourcery CodeBench Toolchain funktioniert zwar prinzipiell, bietet aber keine optimale Unterstützung der FPU des Cortex-M4F, weil die C-Bibliothek nicht entsprechend gebaut wurde. Damit wird recht ordentlich Geschwindigkeit und Speicher verschenkt. Weitere Informationen im Abschnitt "Compiler" im Artikel ARM.

Sourcery CodeBench Lite Edition for ARM EABI

Sup processors.jpg

Als erstes benötigen wir die Toolchain mit Compiler & Linker. Hier verwenden wir die Sourcery Codebench von Mentor. In der Auswahlbox "Supported Prozessors" wählt man in der Rubrik "ARM processors" den Punkt "Download the EABI Release >" aus.

Leider muss man sich registrieren. Nach der Registrierung erhält man einen Link per E-Mail zur Downloadseite. Man wählt das "Recommended Release" aus und lädt dort die Datei "IA32 GNU/Linux TAR" herunter.

Die Datei muss einfach nur an einem beliebigem Ort entpackt werden und die Umgebungsvariable PATH erweitert werden.

root@linux:/home/user/Downloads# mkdir /opt/CodeSourcery
root@linux:/home/user/Downloads# cd /opt/CodeSourcery
root@linux:/opt/CodeSourcery# tar xvf /home/user/Downloads/arm-2011.09-69-arm-none-eabi-i686-pc-linux-gnu.tar.bz2
root@linux:/opt/CodeSourcery# ls
arm-2011.09

Anpassen der Umgebungsvariable PATH. Die Anpassung ermöglicht es Eclipse den Compiler im Dateisystem zu finden ohne den absoluten Pfad anzugeben.
Es gibt verschiedene Orte wo sich die Variable anpassen lässt. Auf meinem System habe ich die Datei /etc/environment angepasst.

root@linux:/opt/CodeSourcery# echo PATH=\"$PATH:/opt/CodeSourcery/arm-2011.09/bin\" >> /etc/environment
root@linux:/opt/CodeSourcery# source /etc/environment
root@linux:/opt/CodeSourcery# arm-none-eabi-gcc --version
arm-none-eabi-gcc (Sourcery CodeBench Lite 2011.09-69) 4.6.1
Copyright (C) 2011 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

Wer gerne mit der Konsole & vi/emacs arbeitet kann sofort zum Abschnitt stlink springen, für die Klickibunti-Fraktion folgt jetzt die Installation der IDE.

Eclipse IDE

Nach der Installation der Toolchain folgt jetzt die IDE hier habe ich mich für Eclipse entschieden. Zunächst sucht man sich auf eclipse.org aus einen der vielen Pakete das für sich passende raus. Das sinnvollste an dieser Stelle ist "Eclipse IDE for C/C++ Developers". Wer aber vor hat die IDE nicht nur für C/C++ zu verwenden ist mit "Eclipse Classic" vielleicht besser bedient.

Ich werde hier Eclipse Classic 3.7.1 verwenden und zeigen wie das CDT (C/C++ Development Tooling) installiert wird. Um Eclipse zu "installieren" muss das Archiv nur an einem Ort seiner Wahl entpackt werden.

root@linux:/home/user/Downloads# cd /opt
root@linux:/opt# tar xvf /home/user/Downloads/eclipse-SDK-3.7.1-linux-gtk.tar.gz

Die IDE lässt sich nun wie folgt starten:

user@linux:~$ /opt/eclipse/eclipse

Wie ein Starter angelegt wird liest du am besten im Handbuch/Wiki zu deiner Distribution nach.

Als nächstes folgt die Installation der benötigten Plugins. Der Abschnitt "CDT (C/C++ Development Tooling)" kann übersprungen werden, wenn man das Eclipse-Paket "Eclipse IDE for C/C++ Developers" installiert hat.

CDT (C/C++ Development Tooling)

Zum installieren des CDT wird zuerst die IDE gestartet. Im Hauptfenster wählt man dann den Menüpunkt Help > Install New Software... es erscheint ein neuer Dialog. Das Eingabefeld Work with: wird mit http://download.eclipse.org/tools/cdt/releases/indigo ausgefüllt und mit der Return-Taste abgeschickt.

Im unteren Teil des Dialogs werden nun die verfügbaren Plugins aufgelistet, benötigt wird das Plugins C/C++ Development Tools aus der Rubrik CDT Main Features und C/C++ GDB Hardware Debugging aus der Rubrik CDT Optional Features. Einfach ein Haken vor den Plugins machen und auf Next klicken. Es erscheint eine Zusammenfassung und eine Seite weiter die Lizenz, die man sich durchlesen sollte und dann bestenfalls bestätigt. Mit einem klick auf Finish wird das Plugin heruntergeladen und installiert.

Nach der Installation des Plugins sollte Eclipse neu gestartet werden. Auf der Willkommen-Seite ist nun ein Punkt C/C++ Development zusehen bzw. lässt sich im Menü per File > New > Project... ein C oder C++ Projekt anlegen.

GNU ARM Eclipse Plug-in

Mit der jetzigen Installation ist es bereits möglich einfache C/C++ Projekte zu erstellen und Makefiles zu importieren. Jetzt fehlt noch das Bindeglied zwischen der Toolchain und Eclipse. Dazu gibt es das GNU ARM Eclipse Plug-in. Mit dem Plugin kann man nun die Konfiguration des Compilers und Linkers in Eclipse erledigen was sonst in einem Makefile geschieht.

Die Installation des Plugins funktioniert genauso wie die Installation des CDT, nur mit anderer Quelle. Hier die Kurzfassung:

  1. Help > Install New Software...
  2. Work with: mit http://gnuarmeclipse.sourceforge.net/updates ausfüllen und mit Return-Taste bestätigen.
  3. Einen Haken vor CDT GNU Cross Development Tools machen und Next drücken.
  4. Es erscheint eine Zusammenfassung mit Next zu nächsten Seite.
  5. Lizenzvereinbarung lesen und akzeptieren Installation mit klick auf Finish starten.
  6. Es erscheint noch eine Warnung, dass die Dateien nicht signiert sind. Diesen bitte mit OK bestätigen.
  7. Eclipse neu starten.

Beim erstellen eines neuen C oder C++ Projekts kann nun die Toolchain ARM Linux GCC (Sourcery G++ Lite) gewählt werden. Bevor mit den Beispielen begonnen werden kann muss noch die Frage geklärt werden wie die Daten auf den Chip kommen.

stlink

Das Entwicklungsboard STM32F4-Discovery von ST kann über USB per STLinkV2 programmiert werden. Für Linux gibt es da den "stm32 discovery line linux programmer"

Die Tools liegen als Quelltext vor und müssen zuerst kompiliert werden. Dann mal los! Solltest du mit deinem Linux noch nie ein Programm kompiliert haben siehe am besten erst in dem Handbuch/Wiki zu deiner Distribution nach was du benötigst (Ubuntu benötigt z.B. die Pakete build-essential und git).

Als erstes die Quelltexte laden

user@linux:~/src$ git clone git://github.com/texane/stlink.git

Um die Tools nun kompilieren zu können werden noch die Quelltexte der libusb 1.0 benötigt. Bei einem Ubuntu-System ist dies das Paket libusb-1.0.0-dev (Lubuntu 11.10).Bei einem Debian-System könnte auch folgendes Paket autogen fehlen.
Jetzt kann der Quelltext kompiliert werden.

user@linux:~/src$ cd stlink
user@linux:~/src/stlink$ ./autogen.sh
user@linux:~/src/stlink$ ./configure
user@linux:~/src/stlink$ make

Wenn das ganze fehlerfrei durch gelaufen ist, kann man den ganzen Ordner, oder alternativ auch nur ./flash/flash und ./gdbserver/st-util, kopieren und per Umgebungsvariable PATH verfügbar machen.
Achtung: Im folgendem Block benenne ich flash in st-flash um, weil ich flash nicht besonders passend finde wenn man es per Umgebungsvariable verfügbar macht.

root@linux:~# mkdir /opt/stlink
root@linux:~# cd /opt/stlink
root@linux:/opt/stlink# cp /home/user/src/stlink/flash/flash ./st-flash
root@linux:/opt/stlink# cp /home/user/src/stlink/gdbserver/st-util .
root@linux:/opt/stlink# echo PATH=\"$PATH:/opt/stlink\" >> /etc/environment
root@linux:/opt/stlink# source /etc/environment

Nun brauchen die beiden Tools noch Schreibrechte für das USB-Gerät.

root@linux:~# cp /home/user/src/stlink/49-stlinkv*.rules /etc/udev/rules.d
root@linux:~# udevadm control --reload-rules

Wird nun das STM32F4-Discovery an den PC gesteckt wird ein neues Device erzeugt, bei mir war das /dev/stlinkv2_2.
Für Boards mit STLink v1 solltest du dir einmal die README zu stlink durchlesen.

Sollte das soweit alles geklappt haben, ist das jetzt der perfekte Zeitpunkt um ein Backup der Firmware zu machen.

user@linux:~$ st-flash read ~/STM32F4-Discovery.bin 0x8000000 0x100000

Mit folgendem Befehl kann die Datei wieder zurück geschrieben werden.

user@linux:~$ st-flash write ~/STM32F4-Discovery.bin 0x8000000

stlink in Eclipse einbinden

Als nächstes wird der GDB-Server in Eclipse integriert. Man wählt aus dem Hauptmenu Run > External Tools > External Tools Configurations....

Ein Klick mit der rechten Maustaste auf Program und New auswählen. Als Name ST-Link eintragen. Auf der Registerkarte Main unter Location: /opt/stlink/st-util und bei Working Directory: ${workspace_loc}${project_path} eintragen. Auf der Registerkarte Build wird der Haken vor Build before Launch raus genommen. Auf der Registerkarte Common einen Haken vor External Tools im Feld Display in Favorites menu machen. Ein Klick auf Apply und den Dialog mit einem Klick auf Close schließen.

Installation Windows

Keil MDK-ARM Lite

Unter Windows kann man unter anderem auch die Keil MDK-ARM Lite IDE benutzen.

Eclipse

siehe Artikel STM32 Eclipse Installation

AtollicTrueStudio

siehe Artikel STM32 LEDBlinken AtollicTrueStudio

Beispiel-Projekte

Vorbereitungen

Standard Peripherals Library

Bevor jetzt der erste Quelltext in den Editor gehackt wird, kann man sich das Leben etwas leichter machen. STMicroelectronics stellt für seine Microprozessoren Bibliotheken bereit, die einem eine ganze Menge Arbeit abnimmt.

Die Rede ist von der "Standard Peripherals Library", diese lässt sich auf der Seite von STMicroelectronics herunter laden. Der Weg dorthin ist dank einer wunderschön gestalteten Homepage etwas steinig.
Auf der Hauptseite wählt man zuerst in der Rubrik Products die Kategorie Micros & Memories und danach Mikrocontrollers. Als nächstes wird auf die Registerkarte Resources gewechselt. Im Bereich Software Resources wird der Punkt Firmware ausgewählt. Es öffnet sich ein neues Browserfenster/-tab mit einer Liste von Dateien. Im oberen Bereich gibt es ein Suchfeld. Hier kann nach den "standard peripherals library" gesucht werde Für das STM32F4-Discovery benötigen wir die Datei STM32F4 DSP and standard peripherals library

[Direkter Link zur Std Lib]

Die Datei kann an einen beliebigen Ort entpackt werden.

Neues Projekt anlegen

Jetzt kann mit der Programmierarbeit begonnen werden. Falls noch nicht geschehen kann nun die IDE gestartet werden, im Terminal geht das bei meiner Installation mit:

user@linux:~$ /opt/eclipse/eclipse

Nun wird ein neues Projekt geöffnet folgende Schritte sind nötig:

  1. File > New > Project...
  2. C/C++ > C Project; Next
  3. ARM Cross Target Application > Empty Project
  4. Toolchains = ARM Linux GCC (Sourcery G++ Lite)
  5. Project name = (Hier den Projektnamen eingeben); Finish
  6. Eventuell wird nach der C/C++ Perspective gefragt, diesen Dialog mit Yes beantworten.

Auf der linken Seite im Project Explorer siehst du nun das neue Projekt, sobald du die Baumstruktur öffnest sollte bereits ein Ordner Includes vorhanden sein, dort gibt es bereits 3 Einträge:

  • /opt/CodeSourcery/arm-2011.09/arm-none-eabi/include
  • /opt/CodeSourcery/arm-2011.09/lib/gcc/arm-none-eabi/4.6.1/include
  • /opt/CodeSourcery/arm-2011.09/lib/gcc/arm-none-eabi/4.6.1/include-fixed

Wenn diese Einträge nicht vorhanden sind, ist bis hierhin etwas schief gegangen. Vermutlich wurde die Umgebungsvariable PATH nicht korrekt gesetzt.

Wenn bis hierhin alles geklappt hat können nun die weiteren Einstellungen vorgenommen werden. Zuerst werden die Header-Datei der Standard Peripherals Library hinzu gefügt.

  1. Project > Properties
  2. C/C++ General > Paths and Symbols
  3. Configuration = [All configurations]
  4. Reiter Includes, Languages = GNU C

Hier werden nun die Pfade zu den Header-Dateien der Standard Peripherals Library eingetragen. Ich habe das von ST heruntergeladene Archiv nach /home/user/eclipse/STM32/ entpackt. daraus ergeben sich für mich folgende Pfade die eingetragen werden müssen:

  • /home/user/eclipse/STM32/STM32F4xx StdPeriphLib V1.0.0/Libraries/CMSIS/Include
  • /home/user/eclipse/STM32/STM32F4xx StdPeriphLib V1.0.0/Libraries/CMSIS/Device/ST/STM32F4xx/Include
  • /home/user/eclipse/STM32/STM32F4xx StdPeriphLib V1.0.0/Libraries/STM32F4xx_StdPeriph_Driver/inc
  • /${ProjDirPath}

Als nächstes werden die Quellcode-Dateien der Standard Peripherals Library hinzugefügt.

  1. Reiter Source Location
  2. Link Folder..., Folder Name = StdPeriph
  3. Link to folder in the filesystem aktivieren
  4. Browse..., Verzeichniss = /user/eclipse/STM32/STM32F4xx StdPeriphLib V1.0.0/Libraries/STM32F4xx_StdPeriph_Driver/src

Jetzt noch 3 Symbole anlegen:

  1. Reiter Symbols, Languages = GNU C
  2. Add..., Name: = USE_STDPERIPH_DRIVER > OK
  3. Add..., Name: = USE_STM32_DISCOVERY > OK
  4. Add..., Name: = HSE_VALUE Value: = 8000000 > OK

Damit durch den Indexer auch alle Header-Files der Standard-Libs berücksichtigt werden ist die Konfiguration des Indexers noch anzupassen:

  1. Project > Properties
  2. C/C++ General > Indexer
  3. Folgende Optionen (Checkboxen) wählen:
    1. Enable project specific settings
    2. Store settings with project
    3. Enable indexer
    4. Index source files not included in the build
    5. Index unused headers
    6. Index source and header files opened in editor
    7. Allow heuristic resolution of includes

Nun noch ein Linker-Script aktivieren.

  1. C/C++ Build > Settings
  2. Configuration = [All configurations]
  3. ARM Sourcery Linux GCC Linker > General
  4. Script File (-T) = /${ProjDirPath}/stm32_flash.ld

Als letztes noch das Ausgabeformat auf Binary einstellen.

  1. ARM Sourcery Linux GNU Create Flash Image > Output
  2. Output file format (-O) = binary

Der Dialog kann nun mit OK geschlossen werden.

Jetzt müssen noch 3 Dateien ins Projekt kopiert werden.

  • /home/user/eclipse/STM32/STM32F4xx StdPeriphLib V1.0.0/Project/STM32F4xx_StdPeriph_Templates/TrueSTUDIO/STM324xG_EVAL/stm32_flash.ld
  • /home/user/eclipse/STM32/STM32F4xx StdPeriphLib V1.0.0/Libraries/CMSIS/Device/ST/STM32F4xx/Source/Templates/system_stm32f4xx.c
  • /home/user/eclipse/STM32/STM32F4xx StdPeriphLib V1.0.0/Libraries/CMSIS/Device/ST/STM32F4xx/Source/Templates/TrueSTUDIO/startup_stm32f4xx.s

Die Dateiendung der Datei startup_stm32f4xx.s muss noch in ein großes S geändert werden. Ausserdem muss in der Datei folgende Anweisung auskommentiert werden.

/* Call static constructors */
//    bl __libc_init_array 

Hinweis zur Ausgabedatei
Die kompilierte Datei befindet sich im Ordner Debug oder Release im Projektverzeichniss. Die Datei besitzt den Namen des Prejekts und endet auf .hex. Die Endung ist zwar hex beinhaltet aber trotzdem ein Binary.

Jetzt kann mit der Programmierung begonnen werden.

Debugging mit GDB

Dieser Abschnitt zeigt wie der GDB-Server von stlink in Eclipse verwendet wird.

Bei geöffnetem Projekt klickt man im Hauptmenü auf Run > Debug Configurations.... In der Liste links klickt man mit der Rechten Maustaste auf GDB Hardware Debugging und wählt New.

Bei Name trägt man den Namen der Konfiguration ein z.B. STM32F4-Discovery ST-Link. Die Datei für C/C++ Application: wählt man am besten aus, indem man auf Search Project... klickt. Das Eingabefeld Project: sollte bereits ausgefüllt sein. Auf der Registerkarte Debugger wird in das Eingabefeld GDB-Command: arm-none-eabi-gdb eingetragen. In das Feld Port Number: wird 4242 eingetragen. Abschließend wird auf die Registerkarte Common gewechselt. Hier wird ein Haken vor Debug im Feld Display in Favorites menu gemacht. Ein Klick auf Apply und Close schließt die Konfiguration ab.

Um ein Projekt zu debuggen wählt man zuerst aus dem Hauptmenu Run > External Tools > ST-Link dadurch wird der GDB-Server gestartet.

Sollte man die Meldung erhalten Variable References empty selection: ${project_path} hilft es einmal in eine Projektdatei oder den Projekt-Explorer zu klicken.

Danach wählt man aus dem Hauptmenü Run > Debug Configurations..., in der Liste links wählt man die angelegte Configuration unter GDB Hardware Debugging aus und klickt auf Debug. Eclipse möchte nun in die Debug-Perspektive wchseln, das sollte mit Yes beantworten werden.

Das Programm wird in den Mikrocontroller geladen und nach dem Flashvorgang direkt gestoppt. Mit F8 kann die Ausführung wieder gestartet werden.

Hinweis: Ausführung des GDB bleibt bei 85% stehen
In diesem Fall sollte geprüft werden, ob sich "arm-none-eabi-gdb" auf der Kommandozeile ohne Fehler ausführen lässt. Teilweise fehlen u.U. (32-Bit) Bibliotheken.

Beispiel: Blinky

Hier ein Beispiel welches die 4 LEDs um den MEMS-Sensor herum leuchten lässt.

main.c

#include "stm32f4xx.h"

GPIO_InitTypeDef  GPIO_InitStructure;

void Delay(__IO uint32_t nCount) {
  while(nCount--) {
  }
}

int main(void) {
  /* GPIOD Periph clock enable */
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE);

  /* Configure PD12, 13, 14 and PD15 in output pushpull mode */
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
  GPIO_Init(GPIOD, &GPIO_InitStructure);

  while (1) {
    /* Set PD12 Green */
    GPIOD->BSRRL = GPIO_Pin_12;
    /* Reset PD13 Orange, PD14 Red, PD15 Blue */
    GPIOD->BSRRH = GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15;
    Delay(10000000L);

    /* Set PD13 Orange */
    GPIOD->BSRRL = GPIO_Pin_13;
    /* Reset PD12 Green, PD14 Red, PD15 Blue */
    GPIOD->BSRRH = GPIO_Pin_12 | GPIO_Pin_14 | GPIO_Pin_15;
    Delay(10000000L);

    /* Set PD14 Red */
    GPIOD->BSRRL = GPIO_Pin_14;
    /* Reset PD12 Green, PD13 Orange, PD15 Blue */
    GPIOD->BSRRH = GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_15;
    Delay(10000000L);

    /* Set PD15 Blue */
    GPIOD->BSRRL = GPIO_Pin_15;
    /* Reset PD12 Green, PD13 Orange, PD14 Red */
    GPIOD->BSRRH = GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14;
    Delay(10000000L);
  }
}

stm32f4xx_conf.h

#ifndef __STM32F4xx_CONF_H
#define __STM32F4xx_CONF_H

/* Includes ------------------------------------------------------------------*/
/* Uncomment the line below to enable peripheral header file inclusion */
// #include "stm32f4xx_adc.h"
// #include "stm32f4xx_can.h"
// #include "stm32f4xx_crc.h"
// #include "stm32f4xx_cryp.h"
// #include "stm32f4xx_dac.h"
// #include "stm32f4xx_dbgmcu.h"
// #include "stm32f4xx_dcmi.h"
// #include "stm32f4xx_dma.h"
// #include "stm32f4xx_exti.h"
// #include "stm32f4xx_flash.h"
// #include "stm32f4xx_fsmc.h"
// #include "stm32f4xx_hash.h"
#include "stm32f4xx_gpio.h"
// #include "stm32f4xx_i2c.h"
// #include "stm32f4xx_iwdg.h"
// #include "stm32f4xx_pwr.h"
#include "stm32f4xx_rcc.h"
// #include "stm32f4xx_rng.h"
// #include "stm32f4xx_rtc.h"
// #include "stm32f4xx_sdio.h"
// #include "stm32f4xx_spi.h"
// #include "stm32f4xx_syscfg.h"
// #include "stm32f4xx_tim.h"
// #include "stm32f4xx_usart.h"
// #include "stm32f4xx_wwdg.h"
// #include "misc.h"

#ifdef  USE_FULL_ASSERT
  #define assert_param(expr) ((expr) ? (void)0 : assert_failed((uint8_t *)__FILE__, __LINE__))
  void assert_failed(uint8_t* file, uint32_t line);
#else
  #define assert_param(expr) ((void)0)
#endif

#endif