Inhaltsverzeichnis
Tipps und Tricks
Hardware Design
STM32
Tutorials
- Diller - STM32 Tutorial - veraltet, aber trotzdem gut
- STM32 Bare Metal - Blog zu „STM32 Bare Metal“-Programmierung
Programmierung / KEIL Compiler (MDK µ-Vision)
Als erstes sollte man sich das mal durchlesen:
MDK5 getting started
CMSIS-Driver (Keil)
Tools von ST
- ( Clock-Konfigurations Tool (Excel), … )
Keil - Migrate ARM Compiler 5 to ARM Compiler 6
STVP-STM32 - ST Visual Programmer STM32
Die alte Datei am besten vorher sichern. Da das ganze Handling für die Einstellungen der Farben in der Keil IDE sehr umständlich ist, habe ich obige Vorlage erstellt.
Hinweis: In dieser Datei sind auch meine Templates gespeichert (z.B. für doxygen Blöcke)
Und so sieht es aus
Ansicht global.prop (obiger Link kann direkt gedownloaded werden)
Debugging / Simulator
- Beim Simulieren eines Programmes (ohne Debug-Hardware) kommt es immer wieder vor, dass auf die Adressbereiche von den Hardware Registern nicht zugegriffen werden kann. z.B.
*** error 65: access violation at 0x40021000 : no 'read' permission
Mit foglenden Mapping lässt sich das Problem lösen:
MAP 0x40000000, 0x400FFFFF READ WRITE
Damit man nun nicht immer händisch mit den Bereich im „Memory Map“ im Debugger Menü eintragen muss,
kann man eine „Initializiation File“ anlegen welches den MAP-Befehl enthält.
Hier werden dann die Rechte für den Speicherbereich von 0x40000000 bis 0x400FFFFF auf „Read“ und „Write“ gesetzt.
Falls noch weitere Speicherbereiche benötigt werden, müssen dies hier ebenfalls eingetragen werden.
(simu_stm32f105.ini) - Komfortablere Peripherie-Windows aktivieren:
Dazu im obigen Debug-Setup- TCM.DLL durch TARMSTM.DLL
- -pCM3 durch -pSTM32F103CB ersetzen
Nun erscheinen für den STM32F103 beim Debuggen unter Peripherals komfortablere Menüeinträge für die Peripeherie.
Wie dies auch für den STM32F105 funktioniert, habe ich noch nicht rausgefunden.
In der DLL konnte ich folgende Parameter (somit werden wohl bloss diese Prozessoren unterstützt) finden:
'STM32F101T6', 'STM32F101RD','STM32F103T6', 'STM32F101ZE' 'STM32F101T8', 'STM32F101RE','STM32F103T8', 'STM32F103RE' 'STM32F101C6', 'STM32F101V8','STM32F103C6', 'STM32F103V8' 'STM32F101C8', 'STM32F101VB','STM32F103C8', 'STM32F103VB' 'STM32F101CB', 'STM32F101VC','STM32F103CB', 'STM32F103VC' 'STM32F101R6', 'STM32F101VD','STM32F103R6', 'STM32F103VD' 'STM32F101R8', 'STM32F101VE','STM32F103R8', 'STM32F103VE' 'STM32F101RB', 'STM32F101ZC','STM32F103RB', 'STM32F103ZC' 'STM32F101RC', 'STM32F101ZD','STM32F103RC', 'STM32F103ZD' 'STM32F101RD', 'STM32F101ZE','STM32F103RD', 'STM32F103ZE' 'ST_bare' 'CortexM3' 'STM32F217IG'
Debug Settings Keil
- DBGMCU_Config
Um die Konfiguration (wird ja nur zum Debugging benötigt) nicht im Quellcode aufzuführen, kann man unter „Projektsettings→Debug→Initialzation File“ angeben welches die Konfiguration vornimmt (mittels Keil Configuration Wizard)
- stm32f10x_dbgmcu.ini
-stm32g4xx_dbgmcu.ini - Quelle Keil DFP-Pack 1.2.0
- Hinweis: Bei der STM32CubeIDE kann man unter der Debug-Konfiguration→Startup→Initialization Commands mittels
set *0xE0042004 = 0x7E3FFF07
das DBG-Register beim Starten des Debuggers mit den passenden Werte beschreiben.
- was macht das hier:
# Enable Debug connection in low power modes (DBGMCU->CR) set 0xE0042004 = (0xE0042004) | 0x7
als Beispiel für andere Schreibweise
hier werden die unteren 3-Bits gesetzt.
Target Settings Keil - Hinweise
- Wird als Target z.B. der STM32F105 ausgewählt so wird der C-Compiler mit der Option:
- -DSTM32F10X_CL aufgerufen. Dies hat zur Folge das in der Standard Lib dann automatisch von einen 25 MHz externen Quarz ausgegangen wird wenn das MAKRO HSE_VALUE nicht gesetzt ist und somit wird der HSE_VALUE auf 25000000 gesetzt.
#if !defined HSE_VALUE #ifdef STM32F10X_CL #define HSE_VALUE ((uint32_t)25000000) /*!< Value of the External oscillator in Hz */ #else #define HSE_VALUE ((uint32_t)8000000) /*!< Value of the External oscillator in Hz */ #endif /* STM32F10X_CL */ #endif /* HSE_VALUE */
Aus diesem Grund sollte das MAKRO HSE_VALUE in den C/C++ Compiler Optionen immer auf den den richtigen Wert gesetzt werden.z.B.HSE_VALUE=8000000
- Xtal (Mhz) ( 8 ) - Settings in den Compiler - Target Optionen
Hier wir auch der Wert des externen Quarzes eingetragen. Allerdings spielt dieser Wert nur eine Rolle für die Initialisierung des Debuggers und eines externen Flashers - Das Makro USE_FULL_ASSERT aktiviert die Benutzung des „assert_param()“ Makros. Desweiteren muss dann die Funktion failed_assert(..) implementiert werden. Hier ein Bespiel wenn das UART Retargeting aktiviert ist:
#ifdef USE_FULL_ASSERT /** * @brief Reports the name of the source file and the source line number * where the assert_param error has occurred. * @param file: pointer to the source file name * @param line: assert_param error line source number * @retval None */ void assert_failed(uint8_t* file, uint32_t line) { /* User can add his own implementation to report the file name and line number, ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */ /* Infinite loop */ printf("\n##########[Error]: Zeile: %d in der Datei: %s\n\n",line,file); { u32 i=0; for (i=0;i<120000;i++) { #ifdef WATCHDOG_AKTIV vResetWdg(); #endif } } while (1) { } } #endif
Hier wird dann die entsprechende Fehlerzeile über UART ausgegeben, bevor dann in der Endlos-Schleife beim aktivierten Watchdog-Timer ein Reset ausgelöst wird. - Clock Konfiguration - Um mich nicht immer durch die Header durchwühlen zu müssen, verwende ich eine eigene Clock-Konfigurations Funktion, die immer folgende Werte einstellt:
- externer Quarz mit 8 MHz aktivieren
- 72 MHz Sysclock
- PLL1 als Sysclock Quelle verwenden
- internen Takt abschalten (Beim Schreiben vom Flash muss der HSI aktiv sein)
Somit sieht meine main immer so aus:int main(void) { RCC_Configuration(); // Zuerst den Clock konfigurieren SystemCoreClockUpdate(); if (SysTick_Config(SystemCoreClock / 1000)) { // dann den Systick auf 1ms setzen // Capture error while (1); } NVIC_Configuration(); ....
Und hier noch meine Clock-Konfiguration:/** * @brief RCC_Configuration - Configures the different system clocks. * * Hier wird nun nachträglich der Takt auf 72MHz ( 32MHz bei L100) gestellt (HSE 8MHz => PLL => 32 MHz) (nur bei L100) * @attention Wenn der Speicher knapp wird dann auf diese Funktion verzichten, und nur die Startup-Konfiguration verwenden (diese steht aber noch auf 24 MHz) * @param None * @retval None */ static void RCC_Configuration(void){ RCC_DeInit(); // RCC system reset(for debug purpose) RCC_HSEConfig(RCC_HSE_ON); // Enable HSE HSEStartUpStatus = RCC_WaitForHSEStartUp(); // Wait till HSE is ready #ifdef PROZESSOR_FAMILY_STM32LXX if(HSEStartUpStatus == SUCCESS){ FLASH_ReadAccess64Cmd(ENABLE); // Enables read access to flash by 64 bits FLASH_PrefetchBufferCmd(ENABLE); // Enable Prefetch Buffer FLASH_SetLatency(FLASH_Latency_1); // ???? RCC->APB1ENR |= RCC_APB1ENR_PWREN; // Power enable PWR->CR = PWR_CR_VOS_0; // Select the Voltage Range 1 (1.8 V) while((PWR->CSR & PWR_CSR_VOSF) != RESET) { // Wait Until the Voltage Regulator is ready }; RCC_HCLKConfig(RCC_SYSCLK_Div1); // HCLK = SYSCLK RCC_PCLK2Config(RCC_HCLK_Div1); // PCLK2 = HCLK RCC_PCLK1Config(RCC_HCLK_Div1); // PCLK1 = HCLK RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK); //by aw als Quelle für den SysClk PLL1 verwenden RCC_PLLConfig(RCC_PLLSource_HSE, RCC_PLLMul_12 , RCC_PLLDiv_3);// nun 32MHz // PLL konfigurieren: HSE * 12 / 3 = 96 Mhz /3 = 32 MHz RCC_PLLCmd(ENABLE); // PLL einschalten while(RCC_GetSYSCLKSource() != 0x0C) // 0x0C: PLL used as system clock { }; RCC_HSICmd(DISABLE); //deAktiviert den internen Highspeed Oszillator. #ifdef PROZESSOR_FAMILY_STM32LXX RCC_MSICmd(DISABLE); #endif } // end HSE Startup Success #else if(HSEStartUpStatus == SUCCESS){ FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable); // Enable Prefetch Buffer RCC_HCLKConfig(RCC_SYSCLK_Div1); // HCLK = SYSCLK RCC_PCLK2Config(RCC_HCLK_Div1); // PCLK2 = HCLK // PCLK1 = HCLK RCC_PCLK1Config(RCC_HCLK_Div2); // by AW (72MHz/2 = 36 MHz) wegen Umstelllung auf 72MHz Systemtak // Achtung Timertakt verdoppelt sich dann ??? RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK); //by aw als Quelle für den SysClk PLL1 verwenden RCC_PLLConfig(RCC_PLLSource_PREDIV1,RCC_PLLMul_9); // PLL konfigurieren: HSE / 1 * 9 = 72MHZ RCC_PLLCmd(ENABLE); // PLL einschalten while(RCC_GetSYSCLKSource() != 0x08) // by aw warten bis PLL als Systemquelle genommen wird { } // test von Aw RCC_HSICmd(DISABLE); //deAktiviert den internen Highspeed Oszillator, Beim Flashspeichern, darf der interne nicht abgschaltet werden } // end success #endif } //end RCC_Configuration
Hinweis das Makro PROZESSOR_FAMILY_STM32LXX wird von mir im Header definiert, wenn ich einen STM32L1xx Type verwende:
//#define PROZESSOR_FAMILY_STM32LXX // Makro zum aktivieren, dass die STM32LXX-Variante // verwendet werden soll
Tipps zu Timer Konfigurationen (PWM)
- Prescaller: Der Timertakt für den Timer berechnet sich folgendermassen:
CK_CNT = fCK_PSC / (PSC[15:0] + 1)
Daraus folgt dann z.B. für einen Timerclock von 10kHz := 72 Mhz / (prescaler +1)
prescaler = (72 Mhz / 10 kHz) - 1 ⇒ 7199
Und hier noch ein paar Makros für Timer (PWM)://! PWM Grundfrequenz für Timer2 (960 Hz) #define TIMER2_PWM_FREQUENZ (960) // Grundfrequenz der PWM //! Timer2 Takt auf 8 MHz #define TIMER2_CLOCK (8000000) // Timer2 Clock wird auf 8 MHz festgelegt ( SYSCLK_FREQ_72MHz) //! Prescaler Wert für den Timer1 #define TIMER2_PRESCACLER ( (vu16) ((SystemCoreClock / TIMER2_CLOCK) - 1)) //! PWM Timer2 Period um auf die 960 Hz zu kommen. #define TIMER2_PWM_PERIOD (0x208D) // (0x109E)
und noch ein Beispiel für die PWM initialisierung von 4 PWM-Kanäle:
header.h: //! PWM Timer2 Period um auf die 960 Hz zu kommen. #define TIMER2_PWM_PERIOD (0x208D) // (0x109E) typedef enum extern_inputs_name_en { EXTERN_MOTOR_1 , EXTERN_MOTOR_2 , EXTERN_MOTOR_3 , EXTERN_MOTOR_4 , EXTERN_COUNTS_MOTOR_INPUTS } extern_inputs_name_t; typedef volatile struct pwmStatus_st { struct pwm_st { u32 dutyCycle; u32 newDutyCycle; // wenn wahr dann neuen Wert setzen } pwm[EXTERN_COUNTS_MOTOR_INPUTS]; struct pwm_timer_st { u16 CCRx_Val ; // Wert für die Peridodendauer vom Timer2 Channel x (1-4) void (*pTimSetCompare)(TIM_TypeDef* TIMx, uint16_t compare); // Zeiger auf die TIM_SetCompare Funktion void (*pTimOcInit)(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct); // Zeiger auf die OCxInit Funktion void (*pTimOcPreload)(TIM_TypeDef* TIMx, uint16_t TIM_OCPreload); } pwm_timer[EXTERN_COUNTS_MOTOR_INPUTS]; } pwmStatus_t; extern pwmStatus_t pwmStatus; extern pwmStatus_t* const pPwmStatus; main.c: //! PWM Statusflags über den PWM-Systemzustand pwmStatus_t pwmStatus = { { { PWM_DEFAULT_DUTY_CYCLE,1 } , { PWM_DEFAULT_DUTY_CYCLE,1 } , { PWM_DEFAULT_DUTY_CYCLE,1 } , { PWM_DEFAULT_DUTY_CYCLE,1 } } , { { 0x00 , TIM_SetCompare1, TIM_OC1Init, TIM_OC1PreloadConfig } //CCR, TimeSetCompare(), TIM_OCxInit(), , { 0x00 , TIM_SetCompare2, TIM_OC2Init, TIM_OC2PreloadConfig } , { 0x00 , TIM_SetCompare3, TIM_OC3Init, TIM_OC3PreloadConfig } , { 0x00 , TIM_SetCompare4, TIM_OC4Init, TIM_OC4PreloadConfig } } }; pwmStatus_t* const pPwmStatus = &pwmStatus; /** * @brief Timer2 Kanäle 1-4 für das PWM Ausgangssignal initialisieren * * PWM-Frequenz 940 Hz für alle Kanäle * PORT A1 (T2.1n) * PORT A2 (T2.2n) * PORT A3 (T2.3n) * PORT A4 (T2.4n) * @param u16 defaultTast * @retval None */ void vInitTimer2PWM(u32 defaultTast) { u32 i; // TIM2 clock enable für das Licht PWM-Signal Test RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); // Timer2 Konfiguration PBA2 // Tim2-CLK= auf 4 Mhz festlegen // Time base configuration // PWM Frequenz soll (f= 940 Hz) sein: // allgemein: f=TimerCLK/(ARR+1) ==> ARR=(4 MHz/940Hz)-1 = 4254,32 = 4254 = 109E 0x14F1 // ==> ARR=(8 MHz/940Hz)-1 = 8509,64 = 8510 = 213E PrescalerValue = (vu16) (SystemCoreClock / TIMER2_CLOCK) - 1; // 17 (8 für ( Mhz) TIM_TimeBaseStructure.TIM_Period = TIMER2_PWM_PERIOD ; // 0x109E ==> PWM = 940 Hz TIM_TimeBaseStructure.TIM_Prescaler = PrescalerValue; // Timer1 Clk=4 MHz TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; // keine weiterer Teiler TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; // Vorwärtszähler //TIM_TimeBaseStructure.TIM_RepetitionCounter = 0; // Nur bei Timer1 und Timer8 TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure); // TIM1 Channel3 duty cycle = (TIM1_CCR3/ TIM1_ARR)* 100 = 25% for(i=0; i<EXTERN_COUNTS_MOTOR_INPUTS;i++) { pPwmStatus->pwm_timer[i].CCRx_Val = SetPWM_Tast(defaultTast); TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable; TIM_OCInitStructure.TIM_Pulse = pPwmStatus->pwm_timer[i].CCRx_Val; TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low; pPwmStatus->pwm_timer[i].pTimOcInit(TIM2, &TIM_OCInitStructure); pPwmStatus->pwm_timer[i].pTimOcPreload(TIM2, TIM_OCPreload_Enable); } /* nicht notwendig // Update registers TIM1->EGR |= (1 << TIM_EGR_UG); */ TIM_ARRPreloadConfig(TIM2, ENABLE); /* TIM2 enable counter */ TIM_Cmd(TIM2, ENABLE); // Main Output Enable //nur bei Timer 1, 8 // TIM_CtrlPWMOutputs(TIM2, ENABLE); }
sonstige Keil Tipps
- String an einer festen Adresse platzieren
const char string[] __attribute__((at(0x0xxxxxxx)) = "Version 1.xxxxdfdf";
- Software-Reset:
NVIC_SystemReset();
- in neueren Versionen von core_cm3.h :
__NVIC_SystemReset();
Wobei mittels Makrodefinition auch der alte Name weiterhin verwendet werden kann.
- EEPROM Emualation/Simulation: EEPROM Emulation
Keil / STM32CubeIDE
- apnt_323.pdf - AppNote 323 - Using Keil MDK with STM32CubeIDE
ST-Standard Peripherie Lib
Und noch ein paar Tipps:
- GPIO_PinSource6 - ist die Pinnummer (0..15)
- GPIO_Pin_6 - ist der Wert für den gewählten Pin (1« Pinnummer)
STM32F1 HAL
App-Notes ST
- AN2586 - Getting started with STM32F10xxx hardware development
- AN4776 - STM32 Timer - General-purpose timer cookbook
App-Notes von Keil
Konvertierung eines ST-Links on Board zu J-Link
Die ST-LINK/V2-1 auf den NUCLEO und Discovery-Boards können auf ein J-Link OB geflasht werden.
Die Anleitung von Segger ist hier:
ST-LINK zu J-Link von Segger
STM32 Bootloader Projekte
Diverse andere Projekte verwenden auch den Tiny-USB Stack um für Ihren eigenen Bootloader:
- libusb_stm32 - Lightweight USB Device Stack for STM32
ST-LINK Utility
Normalerweise verwende ich mein JTAG Standardkabel (und Belegung) um die ST's zu programmieren.
Da ich immer wieder danach gefragt werde, hier mal die einfachste Variante (SWD Schnittstelle) hier werden nur 4 Verbindungen benötigt. Die Spannungsversorgung des Prozessors mache ich immer mit dem USB Verbindungskabel.
SWD Schnittstelle
ST-LINK ←→ Interface (meine STM32 Hardware)
1 ---- Vdd -----2 4 ---- GND ---- 4 7 ---- TMS ---- 8 (SWDIO) 9 ---- TCK ---- 7 (SWCLD)
Und hier noch ein Bild: SWD Verbindungen
JTAG Schnittstelle
ST-Utility - Klone
Dieser USB-Stick Klone hat den Vorteil, dass er auch die Versorgungsspannung liefert. Dafür ist er halt etwas langsamer und unterstützt nur das SWD-Schnittstelle. Dieses Teil hatte ich mir nur für Testzwecke zu gelegt.
ST-Klone ←→ Interface (meine STM32 Hardware)
1 ---- Reset ---- 1 (optional) 2 ---- SWDIO ---- 8 (TMS) 4 ---- GND ---- 4 6 ---- SWCLK ---- 7 (TCK) 7 ---- +3,3V ---- 2 (+3,3V MCU)
STM32 Discovery Boards
STM32-VL-DISCOVERY (STM32F100RB)
Sehr einfaches Eval-Board. Hat im Prinzip nur zwei LEDs und einen Taster als Input. Ist aber für kurze Tests gut geeignet
LEDS
- grün (LD3) - PC9
- blau (LD4) - PC8
die beiden anderen LEDS (LD1, LD2) sind fest verdraht und sind für PC-Board Kommunikation (LD1) und Power LED (LD2) vorbehalten.
Taster
- schwarz - Reset - Reset Taster
schaltet nach Masse - blau - PA0 - Benutzertaster (auch für Wake-Up)
schaltet nach +3,3V
Hinweis zu STM32CubeIde und Debugging - In den neueren Versionen wird das Debugging dieses Board nicht unterstützt (wegen ST-LINK V1 auf dem Board). Deswegen verwende ich dann den BMP oder einen ST-LINK-V2, d.h.:
- beide Jumper von CN3 entfernen
- von BMP/ST-LINK V2 dann die Signale:
- +3,3V
- GND
- CLK - PA14
- Data - PA13
verbinden.
STM32F429I-DISCO1
Moving Tux Demo
Ich habe die „Moving Tux Demo“ mal probeweise auf dem Disco1-Board installiert. Eine kurze Beschreibung von den Abweichungen der Installation und die binär Dateien findet ihr hier:
- Linux_auf_STM32 - yCLinux auf STM32F429I-Disco1
GDB Tipps
Da bei der MovinTux Demo auch OpenOCD installiert wird kann man auch den GDB von den ARM-Tools aus dem openOCD Ordner verwenden. Als erstes muss aber der ST-Link GDB-Server mit:
- st-util (lauscht dann auf: Listening at *:4242… )
gestartet werden. - arm-uclinuxeabi-gdb startet dann den Debugger (Der „bin“-Pfad auf den Ordner muss gesetzt sein).
- tar extended-remote :4242 - baut dann die Verbindung zum Target (über den GDB-Server) auf and die Programmausführung wird angehalten.
- continue - führt die aktuelle Programmausführung fort.
- CTRL+C - unterbricht die Programmausführung mittels eines manuell gesetzen Breakpoints
- b (break) - setzt einen Breakpoint an der aktuellen Position
- info b (info break) - Zeigt Informationen über alle Breakpoints an
- del x - x ist die Nummer von der Infoanzeige von einem Breakpoint den man löschen will
- r (run) - startet das Program oder restart
- Hinweis: Die Befehle müssen nicht ausgeschrieben werden, sobald die Abkürzung eindeutig ist, wird der entsprechende Befehl ausgeführt. Z.B.
- continue kann auch als cont geschrieben werden.
- info all ⇒ i all
STM32F429 USB Bootloader
Hier geht's zu meiner Projektseite für STM32F429 USB Bootloader
STLinux
ST bietet noch folgendes an:
- STLinux
muss ich mir mal anschauen.
TouchGFX Designer
Habe ich mit dem 429 Discoveryboard getestet. Hinweise um den Bildschirm zu um 90° zu drehen:
- Display-orientation
Hat genauso funktioniert. - Arbeitet man mit Keil und man hat beim ersten mal das exportierte Projekt geöffnet und zu Keil 5 migriert, so funktioniert der TouchGFX Designer nicht mehr, da er das Keil Projekt nicht mehr findet.
Hier mein erstes Testprojekt für das Lüftermenü:
Alternativen
Hier geht's zum meinen LVGL-Notizen
STM32 unter Linux
- Attolic Truestudio STM32 V9.0.0 - komplett kostenlos für STM32
seit 2018 (news) gibt es die Vollversion für STM32 umsonst.
Und hier sind noch einige interessante White Papers hinterlegt. Bei vielen Assertfehler vor dem Starten:export env SWT_GTK3=0
ausführen.
- gcc-arm-embedded
PPA is available at https://launchpad.net/~team-gcc-arm-embedded/+archive/ubuntu/ppa .
. - Open STM32 AC6 (Eclipse basierend)
Hinweis: Eclipse needs GTK2 (s.FAQ - Eclipse Bug)
User Training Full V1.1.pdf
Step-by-Step: STM32 Development Environment with OpenOCD and Visual Studio Code (Linux)
- libopencm3_cmake.git - Wie man Cmake mit libopencm3 verwenden kann.
32 Runtime Libs unter Ubuntu 16.04
install all dev and docs
VS-Code unter Ubuntu installieren
Unter Ubuntu am besten folgende vorgehensweise (auch für 18.04):
curl https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor > microsoft.gpg sudo mv microsoft.gpg /etc/apt/trusted.gpg.d/microsoft.gpg sudo sh -c 'echo "deb [arch=amd64] https://packages.microsoft.com/repos/vscode stable main" > /etc/apt/sources.list.d/vscode.list' sudo apt update sudo apt install code
Hat den Vorteil das man auch immer die aktuellste Version mittels apt updaten kann. Ab 18.04 ist VS-Code als Package im Software-Center enthalten, aber halt nicht immer ganz aktuell
Tipps zu Busmaster
CAN-Simulationen
Hinweis ab der Version V3.0 hat sich die STCAN_MSG Struktur geändert (vereinfacht). Deshalb müssen bestehende Simulationen angepasst werden. Die automatisch Konvertierung beim Importieren einer älteren Version hat bei mir nicht funktioniert. Eventuell lags daran, dass meine Simulationen schon etwas älter sind und im Header die Busmaster Version: BUSMASTER VERSION [1.7.1] angegeben war.
Hier nun die neu Struktur:
class STCAN_MSG { unsigned int id; bool isExtended; bool isRtr; unsigned char dlc; unsigned char cluster; unsigned char data[64]; unsigned long timeStamp; bool isCanfd; // To set data bool byteAt(int index, unsigned char val); bool wordAt(int index, unsigned short val); bool longAt(int index, unsigned long val); // To get data unsigned char byteAt(int index); unsigned short wordAt(int index); unsigned long longAt(int index); };*Cluster ist die CAN-Kanalnummer vom Interface
Meine CAN Simulationen für Busmaster V3.1.0
- Gateway Knoten zwischen CAN1 und CAN2 (inkl. Manipulationsmöglichkeit der gerouteten CAN-Botschaft)
gateway.cpp
Zum manipulieren einzelner CAN-Botschaften wird das „filterMask“-Array (maskieren von Datenbits) und „filterSet“-Array (zum Setzen einzelner Bits) verwendet. - BWM Diagnose Tester (todo: an das neue Format anpassen)
bwm_diagnose.cpp - Porsche Head Unit Diagnose (inkl. Security Login) (todo: an das neue Format anpassen)
porsche_hu_diagnose_sim.cpp - OBD2-Simulator
Simuliert das Motorsteuergerätes eines Audi und dient zum Testen eines OBD2 Diagnose Dongle
OBD_Simulator.cpp
Folgende Funktionen sind implementiert
- VIN Abfrage
- DTC Fehlercodes
- diverse Messwerte (Speed, RPM, Kühlwassertemp, usw…). - TP2.0 Simulator (todo: an das neue Format anpassen)
VW_TP20_Simulator.cpp - VW Diagnose (todo: an das neue Format anpassen)
VW_Diagnose.cpp
Simuliert einen VW-Tester um eine Diagnose Sitzung zu einem TP2.0 Steuergerät aufzubauen. - KWP 2000 Modul zum Auflösen der SID Nummern in Klartextnamen (wird für Debug-Ausgabe von diversen Simulationen benötigt
- kwp_2000.h
- kwp_2000.c
VS Code Busmaster Settings für die Busmaster Simulationen
Da der integrierte Code Editor vom Busmaster grausam ist, habe ich jetzt eine Lösung gefunden um den Visual Studio Code Editor für die Busmaster Knoten Simulation zu verwenden inkl. der IntelliSense Funktionalität und compilieren des Quellcodes direkt aus VS Code herraus.
Hier folgt nun eine kurze Beschreibung wie man den Visual Studio Editor konfigurieren kann damit man für die Busmaster Simulationen die IntelliSense zur Verfügung steht und man auch direkt unter VS Code compilieren kann, d.h. direkt die DLL Datei für den Busmaster erzeugen kann.
Hier für müssen 2 Konfigurations Dateien angelegt werden:
- c_cpp_properties.json - Konfiguration für IntelliSense
- tasks.json - Konfiguration des Build-Systems, d.h. hiermit wird die Bumsmaster Simulation compiliert
Durch den angepassten „problemMatcher“ werden auch die Fehlermeldungen beim Compilieren in das Problemfenster übernommen, und man kann mit einem Mausklick direkt zur fehlerhaften Zeile springen.
Legendlich der Dateiname ist dann in der alten WIN/MSDOS Schreibweise.
Hier folgt nun eine kurze Beschreibung der wichtigsten Einträge:
- c_cpp_properties.json (Ausschnitt für Win32):
{ "name": "Win32", "intelliSenseMode": "clang-x64", "includePath": [ "${workspaceRoot}", "C:/Program Files (x86)/BUSMASTER_v3.2.2/SimulatedSystems/Include", "C:/MinGW/lib/gcc/mingw32/5.1.0/include/c++", "C:/MinGW/lib/gcc/mingw32/5.1.0/include/c++/mingw32", "C:/MinGW/lib/gcc/mingw32/5.1.0/include/c++/backward", "C:/MinGW/lib/gcc/mingw32/5.1.0/include", "C:/MinGW/include", "C:/MinGW/lib/gcc/mingw32/5.1.0/include-fixed" ], "defines": [ "_DEBUG", "UNICODE", "__GNUC__=6", "__cdecl=__attribute__((__cdecl__))" ], "browse": { "path": [ "C:/Program Files (x86)/BUSMASTER_v3.2.2/SimulatedSystems/Include", "C:/MinGW/lib/gcc/mingw32/5.1.0/include", "C:/MinGW/lib/gcc/mingw32/5.1.0/include-fixed", "C:/MinGW/include/*" ], "limitSymbolsToIncludedHeaders": true, "databaseFilename": "" } }
Hinweis: Die Pfade bei den markierten Zeilen müssen eventuell angepasst werden.
- tasks.json (komplett, s.o.):
{ // See https://go.microsoft.com/fwlink/?LinkId=733558 // for the documentation about the tasks.json format "version": "2.0.0", "tasks": [ { "label": "build OBD_Simulator", "type": "shell", "command": "make -f OBD_Simulatormake", "problemMatcher": [ { "owner": "cpp", "fileLocation": "absolute", "pattern": { "regexp": "^(.*):(\\d+):(\\d+):\\s+(warning|error):\\s+(.*)$", "file": 1, "line": 2, "column": 3, "severity": 4, "message": 5 } } ], "group": { "kind": "build", "isDefault": true } }, { "label": "clean", "type": "shell", "command": "make clean -f OBD_Simulatormake", "problemMatcher": [ "$gcc" ] } ] }
Hinweis: OBD_Simulatormake ist das vom Busmaster erzeugte Makefile für den Compiler und der Name muss an das eigene Simulations-Projekt angepasst werden.
Tipps zu Doku-Wiki
SyntaxHigligther 4
<sxh [brush][; options]> ... code/text ... </sxh>
Beispiel mit Markierung bestimmter Zeilen:
#define CIRCBUF_DEF(x,y) uint8_t x##_space[y]; circBuf_t x = { x##_space,0,0,y} CIRCBUF_DEF(cb, 32); int circBufPush(circBuf_t *c, uint8_t data) { int next = c->head + 1; if (next >= c->maxLen) next = 0; // Cicular buffer is full if (next == c->tail) return -1; // quit with an error c->buffer[c->head] = data; c->head = next; return 0; } int circBufPop(circBuf_t *c, uint8_t *data) { int next; // if the head isn't ahead of the tail, we don't have any characters if (c->head == c->tail) return -1; // quit with an error *data = c->buffer[c->tail]; c->buffer[c->tail] = 0; // clear the data (optional) next = c->tail + 1; if(next >= c->maxLen) next = 0; c->tail = next; return 0; }
Tipps zu Raspberry
pi1_tipps
pi3_tipps
Upgrade von Rpi2 zu Rpi3 - System Upgrade von einer Rpi2 SD-Karte auf 3
I²C Schnittstelle und Raspi - Beispiele mit Python
Git: push over ssh:
cd my-project git remote add origin ssh://user@host/mnt/foo/bar/my-project.git git push origin master
HW Design Eagle
Hier sind ein paar Links zu Eagle Libs für HW Erweiterungen für den Raspi
- rpi-gpio-eagle - Eagle library for the shrouded Raspberry Pi GPIO header
SD-Karte klonen
Mit diesem kleine Windowstool kann man die kompletter SD-Karte inkl. aller Partitionen klonen:
- für nur eine Partion oder zu Schreiben eines kompletten images auf SD-Karte:
Win32 Diskimager ( oder für alles obiges tool nehmen) - (MiniTool Partition Wizard Free Edition 10.2) - Partitionstool
Hinweis: Eventuell muss man auf der Ziel SD-Karte vorher alle bestehende Partitioinen und das Volume mit dem Festplattenmanager löschen, falls es zu write Fehlern kommt (bei Roadkil's Diskimage war dies bei mir erforderlich)
Unter „Linux“ kann man auch „dd“ verwenden um die komplette SD-Karte oder einzelne Partitionen zu klonen.
# Ein Image von einer einzelnen Partion auf sdf erstellen: sudo dd if=/dev/sdf1 of=/home/myusername/raspberry_root-backup-sdf1-2017-05-10.img # komplettest Image erstellen: sudo dd if=/dev/sdf of=/home/myusername/raspberry-backup-sd_card_2017-05-10.img
Image mounten
Die obige erstellten Images können als „Loop Device“ eingebunden werden:
sudo losetup /dev/loop0 # prüfen, ob "loop0" frei ist (falls nichts erkannt wird ist es verfügbar.
sudo losetup /dev/loop0 /home/myusername/raspberry_root-backup-sdf1-2017-05-10.img #image dem loop device zuweisen
sudo mount -t vfat /dev/loop0 /media/sdimage-1 # image mounten, oder unter /mnt/raspi nachträglich als Read Only mounten: sudo mount -o remount,ro /mnt/raspi oder direkt als read only und wenn mehrere partitionen im image sind eine auswählen: sudo mount /dev/loop0p7 /mnt/raspi/ -o ro #read only und die Linux SystemPartition mounten
- …
sudo umount /dev/loop0 sudo losetup -d /dev/loop0
obiges kann mit:
sudo losetup --find --show -P minix203.img
vereinfacht werden, da hier das Image direkt an das erste freie Loop-Device verbunden wird.
SD-Karte formatieren
Fail2ban Tipps
einzelne Fiterregeln (jails) kann man in der shell prüfen:
fail2ban-regex /var/log/auth.log /etc/fail2ban/filter.d/sshd.conf oder mit Ausgabe der Logzeile: fail2ban-regex /var/log/auth.log /etc/fail2ban/filter.d/sshd.conf --print-all-matched
Hinweis: immer den kompletten Pfad zur Konfigurationsdatei verwenden
Fail2Ban Filter und Jails Konfiguration
Weitere Tipps:
fail2ban-client status fail2ban-client status ssh # zeigt alle IPs an die von "SSH" gebannt wurden fail2ban-client get ssh banned # gibt ein Array der gebannte IPs von "SSH" zurück fail2ban-client unban xxx.xxx.xxx.xx # IP für alle Jails wieder freigeben.
ESP32 Pico Kit
ESP32 CAM DEV
Hier eine kurze Beschreibung vom Modul:
ESP32-CAM Dev Board
Links
OCTAVE
Für meine Tests wurde die Version V4.2.1 verwendet. Mit der nachträglichen Installation des Signal Moduls:
pkg install D:\Downloads\chrome\signal-1.3.2.tar.gz
(signal-1.3.2.tar.gz, von Signal Package von Sourceforge)
danach muss das Modul noch mit:
pkg load signal
geladen werden.
FIR-Filter Design
Testfile bitte in *.m umbennenen fir_first_test.m
Octave Beispiele
GIT Extensions
Probleme
- Sollte kein Start von Git Extensions mehr möglich sein, dann liegt es meistens daran das die Settings-Datei beschädigt wurde. Als erstes mal versuchen folgende Datei zu löschen
C:\Users\xxxBenutzernamexxx\AppData\Roaming\GitExtensions\GitExtensions\GitExtensions.settings
Git
Git Submodule
git submodule add ssh://andreas@geier99.de/opt/git/Projekte/Tools/diagLogger.git Andreas/diagLogger
Damit dies funktioniert, muss ein eventuell vorhandener Ordner „diagLogger“ aus dem Index erst gelöscht werden. Beim Pull wird dann auch das diaglogger geklont(oder gepullt)
Obiges Beispiel legt ein Submodul in ein bestehendes geklontes Git-Repository an (eventuell vorher den Ordner vom Submodul löschen)
Obiger Befehl legt auch die Datei .gitmodules an:
[submodule "Andreas/diagLogger"] path = Andreas/diagLogger url = ssh://andreas@geier99.de/opt/git/Projekte/Tools/diagLogger.git
Git Konsole Tipps
Java
Decompiler
GNU Toolchain Links
- GNU Arm Embedded Toolchain - offizelle ARM Version (etwas älter)
- downloads - direkt zu den Downloads