MDD Easy STM32

Aus THM-Wiki
Wechseln zu: Navigation, Suche
Kurs
Kursname Modellgetriebene Softwareentwicklung in der Praxis SS 15
Kurstyp Praktikum
Dozent Priefer
Semester SS 15
Studiengang Master
Link http://homepages.thm.de/~dprf53


Dokumentation der Tätigkeiten im Rahmen des Moduls Modellgetriebene Softwareentwicklung in der Praxis SS15 für das Projekt MDD Easy STM32

Team

Das Team, welches das Projekt bearbeitet hat, setzt sich aus folgenden Mitgliedern zusammen:


Einleitung

Bei dem Projekt "MDD Easy STM32" handelt es sich um ein Projekt, welches die Modellbasierte Softwareentwicklung auf Embedded Systems, speziell dem Mikrocontroller STM32F4, bringt.

Fehler beim Erstellen des Vorschaubildes: Datei fehlt

Es geht darum auf einer unkomplizierteren und einfacheren Art auf einem STM32F4 von STMicroelectronics entwickeln zu können. Bei diesem Projekt geht es vor allem darum, das der Anwendungsentwickler sich auf das wesentliche beim Entwickeln mit dem STM32F4 konzentrieren kann. Der Programmierer muss sich nicht lange damit auseinandersetzten wie er alle Schnittstellen bis auf das kleinste zu konfigurieren hat, wenn dieses Prozedere in der Regel bis auf ein paar Parameter immer gleich ist. Der Anwendungsentwickler soll damit in der Lage sein, seine Konfigurationen des Mikrocontrollers schnell und unkompliziert einzurichten, ohne dabei direkt eine große Menge an C-Code schreiben zu müssen.

Was erhoffen wir uns davon? Die Hoffnung liegt darin, dass man es schafft zeitlich effizienter zu Entwickeln und so Projekte schneller fertigstellen kann. Mit der neuen Sprache "stm32f4" können Anwendungen kompakter geschrieben werden und sollen vor allem übersichtlicher wirken, als nativer C-Code. Viele wiederkehrende C-Codeteile mit vielen Codezeilen sollen mit weniger Schreibarbeit erledigt werden.

Fehler beim Erstellen des Vorschaubildes: Datei fehlt
Redundanz im C-Code

Durch die einfache Syntax der Sprache "STM32F4" wird Menschen ohne Kentnisse in der Programmiersprache C die Tore für die Embedded Entwicklung (bezogen auf den MC STM32F4) geöffnet. So wird evtl. die Embedded Entwicklung für Menschen zugänglich gemacht, die sich neu für das Thema interessieren und noch nicht viel Erfahrung damit haben. Oft ist es nicht damit getan, dass man nur in C Programmieren kann, sondern man muss auch viel mit dem Datenblatt und der Dokumentation des Mikrocontrollers auseinandersetzen, da sich die Chips in ihrer Programmierung je nach Modell stark unterscheiden. Es kann also für den ein oder anderen Anfänger abschreckend wirken, wenn er sich gleich mit zwei Baustellen beschäftigen muss, denn die STM32F4 Libary hat oft sehr lange Namen für die eigenen Datenstrukturen und redundante Aufrufe, was oft zu Flüchtigkeitsfehlern führt. Das STM32F4 Discovery Board bietet eine gute Hardwarebasis um sich in die Embedded Welt einzuarbeiten und verschiedene Schnittstellen oder Protokolle kennenzulernen.

Quelle STM32F4 Bild


STM32F4

Fehler beim Erstellen des Vorschaubildes: Datei fehlt

Bei dem STM32F4 handelt es sich um einen Mikrocontroller des Herstellers STMicroelectronics. Ein Mikrocontroller ist ein Chip, der Prozessor, Schnittstellen und Speicher in einem Chip vereint.

Der STM32F4 enthält als Prozessor einen ARM Cortex M4 mit einer Taktfrequenz von 168 MHz. Im Chip enthalten sind zudem Schnittstellen, wie Analog/Digital Wandler (ADC). Ebenfalls enthalten ist die Schnittstelle USART für die serielle Datenübertragen wie z.B. RS232. Das Discovery-Board verfügt zudem über viele frei konfigurierbare Pins, genannt GPIOs (General Purpose Input Output) welche z.B. als digitaler Eingang oder Ausgang und vieles mehr genutzt werden können. Das aufzählen aller Funktionalitäten würde an dieser Stelle den Rahmen dieser Dokumentation sprengen, da das Discovery-Board wirklich sehr viele Funktionalitäten hat.

Discovery Boards werden in der Regel von Hersteller angeboten, damit interessenten den darauf verbauten Mikrocontroller ausprobieren können. Dabei werden eben solche Discovery-Boards mit einiger Peripherie wie USB, Audio-Klinkenkabel etc. ausgestattet. Man braucht evtl. dann selbst keine Schaltung zu entwerfen um zu verifizieren, ob der Chip den Anforderungen genügt, sondern kann dafür das Discovery Board nutzen.

Das STM32F4 Discovery Board ist für unter 17€ zu erwerben.

Weitere informationen findet man unter folgendem Link: STM32F4


Konzept

Um das Konzept von MDD Easy STM32 näher zu beschreiben, ist ein Blick auf folgendes Ablaufdiagramm notwendig:

Fehler beim Erstellen des Vorschaubildes: Datei fehlt

Das Projekt "MDD Easy STM32" bietet eine Reihe von STM32F4 Schnittstellen an, die man später nutzen kann. Um in C eine Schnittstelle zu konfigurieren, sind oft viele Codezeilen nötig. Die Einrichtung einer GPIO z.B. benötigt rund 10 Zeilen C-Code. Mit der neu erstellten Sprache "stm32f4" lässt sich der Aufwand für die Nutzung der STM32F4 Schnittstellen drastisch reduzieren.

  • Hat der Anwendungsentwickler einer STM32F4 Anwendung in der Sprache *.STM32F4 geschrieben
  • Wird aus dieser Datei mithilfe eines C-Code Templates nativer C-Code generiert
  • Zu guter letzt werden alle generierten und benötigten C und H Dateien in ein Projekt zusammengefasst
  • Kompiliert, gelinkt und dann direkt auf den STM32F4 geflasht und ausgeführt.


C-Code Vorlage

Um aus der neu definierten Sprache "stm32f4" einen Code generieren zu können, der auf dem STM32F4 lauffähig ist, werden C Templates genutzt, die daraufhin parametrisiert werden. Somit erhält man syntaktisch korrekten C-Code, der auf dem STM32F4 lauffähig ist. Für die nutzbaren Schnittstellen werden Template Blöcke erstellt, in dem die Parameter aus der *.stm32f4 Datei in die C-Datei generiert werden muss.

GPIO Vorlage:

void init_gpio()
{
	  GPIO_InitTypeDef  GPIO_InitStructure;

	  /* Enable the GPIO Clock */
	  RCC_AHB1PeriphClockCmd(, ENABLE);

	  /* Configure the GPIO_LED pin */
	  GPIO_InitStructure.GPIO_Pin = ;
	  GPIO_InitStructure.GPIO_Mode = ;
	  GPIO_InitStructure.GPIO_OType = ;
	  GPIO_InitStructure.GPIO_PuPd = ;
	  GPIO_InitStructure.GPIO_Speed = ;
	  GPIO_Init(, &GPIO_InitStructure);
}

ADC Vorlage:

void init_ADC()
{
	  //Structures
	  GPIO_InitTypeDef GPIO_InitStructure;
	  GPIO_StructInit(&GPIO_InitStructure);
	  ADC_CommonInitTypeDef ADC_CommonInitStructure;
	  ADC_InitTypeDef       ADC_InitStructure;

	  //for ADC1 on PC0 using IN10
	  RCC_AHB1PeriphClockCmd(, ENABLE);
	  RCC_APB2PeriphClockCmd(, ENABLE);


	 //for ADC1 on PC0 using IN10
	 GPIO_InitStructure.GPIO_Pin = ;
	 GPIO_InitStructure.GPIO_Mode = ;
	 GPIO_InitStructure.GPIO_PuPd = ;
	 GPIO_Init(, &GPIO_InitStructure);


	  ADC_CommonInitStructure.ADC_Mode = ;
	  ADC_CommonInitStructure.ADC_Prescaler = ;
	  ADC_CommonInitStructure.ADC_DMAAccessMode = ;
	  ADC_CommonInitStructure.ADC_TwoSamplingDelay = ;

	  ADC_CommonInit(&ADC_CommonInitStructure);

	  ADC_InitStructure.ADC_Resolution = ;
	  ADC_InitStructure.ADC_ScanConvMode = ;
	  ADC_InitStructure.ADC_ContinuousConvMode = ;
	  ADC_InitStructure.ADC_ExternalTrigConvEdge = ;
	  ADC_InitStructure.ADC_ExternalTrigConv = ;
	  ADC_InitStructure.ADC_DataAlign = ;
	  ADC_InitStructure.ADC_NbrOfConversion = ;


	  ADC_StructInit(&ADC_InitStructure);

	  ADC_Init(ADC1, &ADC_InitStructure);

	  ADC_RegularChannelConfig(, , , );
	  ADC_EOCOnEachRegularChannelCmd(, ENABLE);

	  ADC_Cmd(, ENABLE);    	
}

USART Vorlage:

 void init_usart()
 {
	  GPIO_InitTypeDef GPIO_InitStructure;
	  USART_InitTypeDef USART_InitStructure;

	  RCC_AHB1PeriphClockCmd(, ENABLE);

	  RCC_APB1PeriphClockCmd(, ENABLE);


	  GPIO_PinAFConfig(, , );

	  GPIO_PinAFConfig(, , );

	  GPIO_InitStructure.GPIO_OType = ;
	  GPIO_InitStructure.GPIO_PuPd = ;
	  GPIO_InitStructure.GPIO_Mode = ;

	  GPIO_InitStructure.GPIO_Pin = ;
	  GPIO_InitStructure.GPIO_Speed = ;
	  GPIO_Init(, &);

	  GPIO_InitStructure.GPIO_Mode = ;
	  GPIO_InitStructure.GPIO_Pin = ;
	  GPIO_Init(, &);

	  USART_InitStructure.USART_BaudRate = ;
	  USART_InitStructure.USART_WordLength = ;
	  USART_InitStructure.USART_StopBits = ;
	  USART_InitStructure.USART_Parity = ;
	  USART_InitStructure.USART_HardwareFlowControl = ;
	  USART_InitStructure.USART_Mode =  USART_Mode_Rx | USART_Mode_Tx;
	  USART_Init(, &);


	  USART_Cmd(, );
 }

Zusätzlich zu den neu generierten Dateien, gibt es noch statische C und H Dateien, die in Form als Libaries benötigt werden und unverändert mit in das Projektverzeichnist kopiert werden müssen. Dazu mehr im Laufe der Dokumentation.


Voraussetzungen und benötigte Technologien

Wichtig ist das MDD Easy STM32 nur unter Windows voll Funktionsfähig ist. Viele der unten aufgelisteten Softwarevoraussetzungen sind nicht für Unix Betriebssysteme verfügbar. Die meisten Entwicklungstools von den Herstellern sind generell für Windows ausgelegt

Um MDD Easy STM32 nutzen zu können, sind einige Softwareabhängigkeiten zu erfüllen:


Compile and Flash Service

Fehler beim Erstellen des Vorschaubildes: Datei fehlt
Compile and Flash Service

Hat man aus der *.STM32F4 Datei heraus alle nötigen C und H Dateien generiert, stellt sich nun die Frage, wie dieser Code nun auf das STM32-Board übertragen werden kann. Es wäre wirklich sehr umständlich, wenn der Anwendungsentwickler die Dateien manuell kompilieren, linken und dann zuletzt auf das STM32-Board flashen müsste. Daher bietet MDD Easy STM32 die möglichkeit aus der aktuellen Instanz das fertige Projekt direkt zu kompilieren, linken und auf den STM32 zu flashen.

Hierfür ist die Klasse CAPService (Compile And Flash Service) verantwortlich. Diese macht wie oben schon beschrieben im großen und ganzen folgendes:

  • Kompilieren aller *.c Dateien in abhängigkeit der Include *.h Dateien zu Object *.o Dateien
  • Linken alle *.o Dateien zu einem fertigen Binary *.elf, welches auf den STM32 geflasht werden kann
  • Flashen der binary auf den STM32

Für das kompilieren und linken wird die Software "GNU ARM Embedded Tools 4.6 2012q4" verwendet und zum Flashen die Software "CoFlash" (siehe Kapitel Voraussetzungen).


Die Klasse CAPService setzt voraus, dass ein Projectverzeichnis existiert das wie folgt aufgebaut ist:

  • Verzeichnis Src in dem alle *.c Dateien enthalten sind
  • Verzeichnis Inc in dem alle *.h Dateien enthalten sind
  • Linkertreiber arm-gcc-link.ld zum linken und erzeugen der Binary
  • Flashtreiber STM32F4xx_1024.elf zum Flashen der Binary *.elf auf den STM32
Fehler beim Erstellen des Vorschaubildes: Datei fehlt

Linker und Flashtreiber werden mit MDD Easy STM32 mitgeliefert.

Die Klasse CAPService erzeugt zwei Batch-Skripte *.bat in dem alle nötigen Befehle zum kompilieren, linken und flashen enthalten sind. Im grunde sind dort GCC oder CoFlash Befehle enthalten:


  • In der ersten *.bat Datei sind alle kompilier Befehle enthalten und zuletzt der Linkeraufruf:
arm-none-eabi-gcc.exe -mcpu=cortex-m4 -mthumb -Wall -ffunction-sections -g -O0 -c -DSTM32F407VG -DSTM32F4XX -DUSE_STDPERIPH_DRIVER -D__ASSEMBLY__ 
-I C:\Project\Inc C:\Project\Src\GPIO_test.c -o C:\Project\obj\GPIO_test.o


arm-none-eabi-gcc.exe -mcpu=cortex-m4 -mthumb -g -nostartfiles -Wl,-Map=C:\Project\bin\projMap.map  -O0 -Wl,--gc-sections 
-LC:\Project\Inc -Wl,-TC:\Project\arm-gcc-link.ld -g -o C:\Project\bin\projELF.elf  C:\Project\obj\*


  • In der zweiten *.bat Datei ist der CoFlash Aufruf enthalten, der die gelinkte Binary auf den STM32F4 flasht:
coflash.exe program STM32F407VG C:\Project\bin\projELF.elf --adapter-name=ST-Link --port=SWD 
--adapter-clk=1000000 --erase=affected --driver=C:\Project\STM32F4xx_1024.elf

CAPService erzeugt während der Laufzeit folgende Verzeichnisse:

  • Obj: dort sind alle kompilierten *.c Dateien als Object Datei *.o abgelegt
  • Bin: dort ist die fertige *.elf Datei abgelegt, welche in Abhängigkeit der *.o und *.h Dateien erzeugt wird

Der komplette, kommentierte Quellcode ist unter Git-Projektseite zu finden. Dokumentationen zum GNU Compiler und Co-Flash findet man unter:


Grammatik

Die Grammatik des Easy STM32 liegt in Backus-Naur-Form, als Xtext-Datei vor. Diese beinhaltet einen "Wurzelknoten" das STM32F4, welcher als "Container" für die einzelnen Komponenten dient.

Backus-Naur-Form

Für die Angabe der Kardinalitäten (oder Multiplizitäten) gilt folgende Syntax:

1  pflicht_eigenschaft = Datentyp
2  optionale_eigenschaft = Datentyp?

wobei optionale_eigenschaft einer 0…1-Verbindung entspricht. Für Listen gilt analog:

1 liste_0_zu_N += Datentyp*
2 liste_1_zu_N += Datentyp+

Eine Definition eines eigenen Datentyps wird durch den Bezeichner, gefolgt von einem Doppelpunkt, eingeleitet und durch ein Semikolon abgeschlossen:

1 lModel:
2   "root" root=[Element]
3   "caption" caption=STRING
4   elements+=Element*;

Um einen Aufzählungstyp zu definieren, verwendet man folgende, leicht abweichende, Syntax:

1 lModel:
2   enum Datentyp:
3   BOOL | STR | INT;

Wobei sich auch alternative Zeichenketten angeben lassen, mit denen die Eingabe im DSL-Editor bessere oder einfach nur gewohnte Benennungen angepasst werden kann:

1 enum Datentyp:
2   BOOL="boolean" | STR="string" | INT="integer";

Xtext

Xtext ist ein Open-Source-Framework für die Entwicklung von Programmiersprachen, sowie domänenspezifischen Sprachen (englisch domain specific language DSL) und ein Teil des Eclipse-Modeling-Framework-Projekts. Im Gegensatz zu normalen Parsergeneratoren wird bei Xtext nicht nur ein Parser generiert, sondern auch ein Klassenmodell für den abstrakten Syntaxbaum und ein in Eclipse integrierter Texteditor sowie die notwendige Infrastruktur für die Implementierung einer modernen Entwicklungsumgebung für die entwickelte Sprache bereitgestellt.

STM32F4

Wie in der Beschreibung schon erwähnt ist in der stm32f4 - Grammatik der Wurzel-Knoten, der STM32F4. Dieser enthält in der derzeitigen Implementierung die "Module" GPIO,ADC und USART.

Fehler beim Erstellen des Vorschaubildes: Datei fehlt




















1 STM32F4:
2 	"STM32F4" "{"
3 		"Name:" name = ID
4 		(GPIO += GPIO?)*
5 		(ADC += ADC?)*
6 		(USART +=USART?)*
7 	"}"	
8 ;


Die jeweiligen GPIO, USART und ADC Knoten können entweder ein template oder eine spezifische Komponente sein. Die jeweiligen spezifischen Knoten enthalten entsprechende "Enumerations", die auf die jeweilige Hardware Komponenten angepasst sind. Die Grammatik ist in dieser Version sehr Hardware nah aufgebaut.

Fehler beim Erstellen des Vorschaubildes: Datei fehlt
Fehler beim Erstellen des Vorschaubildes: Datei fehlt
Fehler beim Erstellen des Vorschaubildes: Datei fehlt


GPIO:

 1 GPIO:
 2 	GPIO_Template | GPIO_SPECIFIC
 3 ;
 4 
 5 GPIO_Template:
 6 	"GPIO_Template" "{"
 7 		"Name:" name=ID		
 8 	"}"	
 9 ;
10 
11 GPIO_SPECIFIC:
12 	"GPIO_SPECIFIC" "{"
13 		"Name:" name=ID
14 		("GPIO_Pin: "(pins +=GPIO_PINS( "|" pins+=GPIO_PINS)*))
15 		("GPIO_Mode: "(mode = GPIO_MODE))?
16 		("GPIO_OType: "(otype = GPIO_OUTPUT_TYPE))?
17 		("GPIO_PuPd: "(pull = GPIO_PULL))?
18 		("GPIO_Speed: " (speed = GPIO_SPEED))?
19 		("GPIO_Init("(GPIO_Pin = GPIO_PERIPH)", &GPIO_InitStructure)")																
20 	"}"	
21 	
22 ;


USART:

 1 USART:
 2 	USART_SPECIFIC | USART_Template	
 3 ;
 4 
 5 USART_Template:
 6 	"USART_Template" "{"
 7 		"Name:" name = ID	
 8 	"}"
 9 ;
10 
11 USART_SPECIFIC:
12  "USART_SPECIFIC" "{"
13 	"Name:" name = ID
14 	"USART_Type: " usart_type = UART_Type
15 	"USART_BaudRate: " usart_baudrate = INT
16 	"USART_WordLength: " usart_word_length = USART_Word_Length
17 	"USART_StopBits: " usart_stopbits = USART_Stop_Bits
18 	"USART_Parity: " usart_parity = USART_Parity
19 	"USART_HardwareFlowControl: "  usart_HWFlowControl= USART_Hardware_Flow_Control
20 	"USART_Mode: " (usart_mode += USART_Mode("|" usart_mode +=USART_Mode)?)
21 	USART_GPIO += GPIO_SPECIFIC*
22 	USART_AFConfig+=GPIO_PinAFConfig*
23 "}"
24 ;
25 
26 GPIO_PinAFConfig:
27 	"GPIO_PinAFConfig" "{"
28 		"GPIO_Pin: " pin = GPIO_PINS
29 		"GPIO_Source: " g_pinsource = GPIO_PinSource
30 		"GPIO_AF: " g_af = GPIO_AF
31 	"}"
32 ;


ADC:

 1 ADC:
 2 	ADC_SPECIFIC | ADC_Template
 3 ;
 4 
 5 ADC_Template:
 6 	"ADC_Template" "{"
 7 		"Name:" name = ID
 8 	"}"
 9 ;
10 
11 ADC_SPECIFIC:
12  "ADC_SPECIFIC" "{"
13 	"Name:" name = ID
14 	"ADC_Nummer: " adc_number = ADC_Number
15 	"ADC_Channel: " adc_channel = ADC_channels
16 	"ADC_Rank: " adc_rank = INT
17 	"ADC_Sample_Time: " sample_time = ADC_sampling_times
18 	"ADC_NbrOfConversion: " nbrofConversion = INT
19 	("ADC_Mode: "(mode = ADC_MODE))?
20 	("ADC_Prescaler: "(adc_prescaler = ADC_Prescaler))?
21 	("ADC_DMAAccessMode: "(dma = ADC_DMAAccessMode))?
22 	("ADC_TwoSamplingDelay: "(samplingDelay = ADC_TwoSamplingDelay))?
23 	("ADC_Resolution: "(resolution = ADC_resolution))?
24 	("ADC_ScanConvMode: "(scan_dis_en = DIS_EN))?
25 	("ADC_ContinuousConvMode: "(conti_dis_en = DIS_EN))?
26 	("ADC_ExternalTrigConvEdge: "(externalTrigCEdge = ADC_ExternalTrigConvEdge))?
27 	("ADC_ExternalTrigConv: "(externalTrigC = ADC_ExternalTrigConv))?
28 	("ADC_DataAlign: "(dataAlgin = ADC_DataAlign))?
29 	ADC_GPIO = GPIO_SPECIFIC							
30 	"}"	
31 ;

Enumerations

GPIO_PINS:

 1 enum GPIO_PINS:
 2 	GPIO_Pin_0 = 'GPIO_Pin_0' | 
 3 	GPIO_Pin_1 = 'GPIO_Pin_1' |
 4 	GPIO_Pin_2 = 'GPIO_Pin_2' |
 5 	GPIO_Pin_3 = 'GPIO_Pin_3' |
 6 	GPIO_Pin_4 = 'GPIO_Pin_4' |
 7 	GPIO_Pin_5 = 'GPIO_Pin_5' |
 8 	GPIO_Pin_6 = 'GPIO_Pin_6' |
 9 	GPIO_Pin_7 = 'GPIO_Pin_7' |
10 	GPIO_Pin_8 = 'GPIO_Pin_8' |
11 	GPIO_Pin_9 = 'GPIO_Pin_9' |
12 	GPIO_Pin_10 = 'GPIO_Pin_10' |
13 	GPIO_Pin_11 = 'GPIO_Pin_11' |
14 	GPIO_Pin_12 = 'GPIO_Pin_12' |
15 	GPIO_Pin_13 = 'GPIO_Pin_13' |
16 	GPIO_Pin_14 = 'GPIO_Pin_14' |
17 	GPIO_Pin_15 = 'GPIO_Pin_15' |
18 	GPIO_Pin_All = 'GPIO_Pin_All'
19 ;

GPIO_STRUCTURE:

1 enum GPIO_STRUCTURE:
2 	GPIO_Pin = 'GPIO_Pin' |
3 	GPIO_Mode = 'GPIO_Mode' |
4 	GPIO_OType = 'GPIO_OType' |
5 	GPIO_PuPd = 'GPIO_PuPd'|
6 	GPIO_Speed = 'GPIO_Speed'
7 ;

GPIO_PERIPH:

 1 enum GPIO_PERIPH:
 2 	GPIOA = 'GPIOA'|
 3 	GPIOB = 'GPIOB'|
 4 	GPIOC = 'GPIOC'|
 5 	GPIOD = 'GPIOD'|
 6 	GPIOE = 'GPIOE'|
 7 	GPIOF = 'GPIOF'|
 8 	GPIOG = 'GPIOG'|
 9 	GPIOH = 'GPIOH'|
10 	GPIOI = 'GPIOI'
11 ;

GPIO_MODE:

1 enum GPIO_MODE:
2 	GPIO_Mode_IN = 'GPIO_Mode_IN'|
3 	GPIO_Mode_OUT = 'GPIO_Mode_OUT'|
4 	GPIO_Mode_AF = 'GPIO_Mode_AF'|
5 	GPIO_Mode_AN = 'GPIO_Mode_AN'	
6 ;

GPIO_OUTPUT_TYPE:

1 enum GPIO_OUTPUT_TYPE:
2 	GPIO_OType_PP = 'GPIO_OType_PP'|
3 	GPIO_OType_OD = 'GPIO_OType_OD'
4 ;

GPIO_SPEED:

1 enum GPIO_SPEED:
2 	GPIO_Speed_2MHz = 'GPIO_Speed_2MHz'|
3 	GPIO_Speed_25MHz = 'GPIO_Speed_25MHz'|
4 	GPIO_Speed_50MHz = 'GPIO_Speed_50MHz'|
5 	GPIO_Speed_100MHz = 'GPIO_Speed_100MHz'
6 ;

GPIO_PULL:

1 enum GPIO_PULL:
2 	GPIO_PuPd_NOPULL = 'GPIO_PuPd_NOPULL'|
3 	GPIO_PuPd_UP = 'GPIO_PuPd_UP'|
4 	GPIO_PuPd_DOWN = 'GPIO_PuPd_DOWN'
5 ;

ADC_MODE:

 1 enum ADC_MODE:
 2 	ADC_Mode_Independent = 'ADC_Mode_Independent'|                
 3 	ADC_DualMode_RegSimult_InjecSimult = 'ADC_DualMode_RegSimult_InjecSimult'|        
 4 	ADC_DualMode_RegSimult_AlterTrig = 'ADC_DualMode_RegSimult_AlterTrig'|     
 5 	ADC_DualMode_InjecSimult ='ADC_DualMode_InjecSimult'|            
 6 	ADC_DualMode_RegSimult = 'ADC_DualMode_RegSimult'|            
 7 	ADC_DualMode_Interl = 'ADC_DualMode_Interl'|                      
 8 	ADC_DualMode_AlterTrig = 'ADC_DualMode_AlterTrig'|                    
 9 	ADC_TripleMode_RegSimult_InjecSimult = 'ADC_TripleMode_RegSimult_InjecSimult'|      
10 	ADC_TripleMode_RegSimult_AlterTrig  = 'ADC_TripleMode_RegSimult_AlterTrig'|       
11 	ADC_TripleMode_InjecSimult = 'ADC_TripleMode_InjecSimult'|           
12 	ADC_TripleMode_RegSimult ='ADC_TripleMode_RegSimult'|             
13 	ADC_TripleMode_Interl = 'ADC_TripleMode_Interl'|              
14 	ADC_TripleMode_AlterTrig = 'ADC_TripleMode_AlterTrig'	
15 ;

ADC_Prescaler:

1 enum ADC_Prescaler:
2 	ADC_Prescaler_Div2 = 'ADC_Prescaler_Div2'| 
3 	ADC_Prescaler_Div4 = 'ADC_Prescaler_Div4'| 
4 	ADC_Prescaler_Div6 = 'ADC_Prescaler_Div6'| 
5 	ADC_Prescaler_Div8 = 'ADC_Prescaler_Div8'
6 ;

ADC_DMAAccessMode:

1 enum ADC_DMAAccessMode:
2 	ADC_DMAAccessMode_Disabled = 'ADC_DMAAccessMode_Disabled'|
3 	ADC_DMAAccessMode_1 = 'ADC_DMAAccessMode_1'|
4 	ADC_DMAAccessMode_2 = 'ADC_DMAAccessMode_2'|
5 	ADC_DMAAccessMode_3 = 'ADC_DMAAccessMode_3'
6 ;

ADC_TwoSamplingDelay:

 1 enum ADC_TwoSamplingDelay:
 2 	ADC_TwoSamplingDelay_5Cycles = 'ADC_TwoSamplingDelay_5Cycles'|
 3 	ADC_TwoSamplingDelay_6Cycles = 'ADC_TwoSamplingDelay_6Cycles'|
 4 	ADC_TwoSamplingDelay_7Cycles = 'ADC_TwoSamplingDelay_7Cycles'|
 5 	ADC_TwoSamplingDelay_8Cycles = 'ADC_TwoSamplingDelay_8Cycles'|
 6 	ADC_TwoSamplingDelay_9Cycles = 'ADC_TwoSamplingDelay_9Cycles'|
 7 	ADC_TwoSamplingDelay_10Cycles = 'ADC_TwoSamplingDelay_10Cycles'|
 8 	ADC_TwoSamplingDelay_11Cycles = 'ADC_TwoSamplingDelay_11Cycles'|
 9 	ADC_TwoSamplingDelay_12Cycles = 'ADC_TwoSamplingDelay_12Cycles'|
10 	ADC_TwoSamplingDelay_13Cycles = 'ADC_TwoSamplingDelay_13Cycles'|
11 	ADC_TwoSamplingDelay_14Cycles = 'ADC_TwoSamplingDelay_14Cycles'|
12 	ADC_TwoSamplingDelay_15Cycles = 'ADC_TwoSamplingDelay_15Cycles'|
13 	ADC_TwoSamplingDelay_16Cycles = 'ADC_TwoSamplingDelay_16Cycles'|
14 	ADC_TwoSamplingDelay_17Cycles = 'ADC_TwoSamplingDelay_17Cycles'|
15 	ADC_TwoSamplingDelay_18Cycles = 'ADC_TwoSamplingDelay_18Cycles'|
16 	ADC_TwoSamplingDelay_19Cycles = 'ADC_TwoSamplingDelay_19Cycles'|
17 	ADC_TwoSamplingDelay_20Cycles = 'ADC_TwoSamplingDelay_20Cycles'
18 ;

ADC_resolution:

1 enum ADC_resolution:
2 	ADC_Resolution_12b = 'ADC_Resolution_12b'|
3 	ADC_Resolution_10b = 'ADC_Resolution_10b'|
4 	ADC_Resolution_8b = 'ADC_Resolution_8b'|
5 	ADC_Resolution_6b = 'ADC_Resolution_6b'
6 ;

ADC_ExternalTrigConvEdge:

1 enum ADC_ExternalTrigConvEdge:
2 	ADC_ExternalTrigConvEdge_None = 'ADC_ExternalTrigConvEdge_None'|
3 	ADC_ExternalTrigConvEdge_Rising = 'ADC_ExternalTrigConvEdge_Rising'|
4 	ADC_ExternalTrigConvEdge_Falling = 'ADC_ExternalTrigConvEdge_Falling'|
5 	ADC_ExternalTrigConvEdge_RisingFalling = 'ADC_ExternalTrigConvEdge_RisingFalling'
6 ;

ADC_ExternalTrigConv:

 1 enum ADC_ExternalTrigConv:
 2 	ADC_ExternalTrigConv_T1_CC1 = 'ADC_ExternalTrigConv_T1_CC1' |
 3  	ADC_ExternalTrigConv_T1_CC2 = 'ADC_ExternalTrigConv_T1_CC2' |             
 4  	ADC_ExternalTrigConv_T1_CC3 = 'ADC_ExternalTrigConv_T1_CC3' |             
 5  	ADC_ExternalTrigConv_T2_CC2 = 'ADC_ExternalTrigConv_T2_CC2' |              
 6  	ADC_ExternalTrigConv_T2_CC3 = 'ADC_ExternalTrigConv_T2_CC3' |              
 7  	ADC_ExternalTrigConv_T2_CC4 = 'ADC_ExternalTrigConv_T2_CC4' |              
 8  	ADC_ExternalTrigConv_T2_TRGO = 'ADC_ExternalTrigConv_T2_TRGO'|              
 9  	ADC_ExternalTrigConv_T3_CC1 = 'ADC_ExternalTrigConv_T3_CC1' |            
10  	ADC_ExternalTrigConv_T3_TRGO = 'ADC_ExternalTrigConv_T3_TRGO'|	
11  	ADC_ExternalTrigConv_T4_CC4  = 'ADC_ExternalTrigConv_T4_CC4' |            
12  	ADC_ExternalTrigConv_T5_CC1  = 'ADC_ExternalTrigConv_T5_CC1' |            
13  	ADC_ExternalTrigConv_T5_CC2 = 'ADC_ExternalTrigConv_T5_CC2' |              
14  	ADC_ExternalTrigConv_T5_CC3 = 'ADC_ExternalTrigConv_T5_CC3' |               
15  	ADC_ExternalTrigConv_T8_CC1 = 'ADC_ExternalTrigConv_T8_CC1' |             
16  	ADC_ExternalTrigConv_T8_TRGO = 'ADC_ExternalTrigConv_T8_TRGO'|
17  	ADC_ExternalTrigConv_Ext_IT11 = 'ADC_ExternalTrigConv_Ext_IT11'             
18 ;

ADC_DataAlign:

1 enum ADC_ExternalTrigConv:
2 	ADC_DataAlign_Right = 'ADC_DataAlign_Right'|
3 	ADC_DataAlign_Left = 'ADC_DataAlign_Left'
4 ;

ADC_channels:

 1 enum ADC_channels: 
 2 	ADC_Channel_0 = 'ADC_Channel_0'|
 3 	ADC_Channel_1 = 'ADC_Channel_1'|
 4 	ADC_Channel_2 = 'ADC_Channel_2'|
 5 	ADC_Channel_3 = 'ADC_Channel_3'|
 6 	ADC_Channel_4 = 'ADC_Channel_4'|
 7 	ADC_Channel_5 = 'ADC_Channel_5'|
 8 	ADC_Channel_6 = 'ADC_Channel_6'|
 9 	ADC_Channel_7 = 'ADC_Channel_7'|
10 	ADC_Channel_8 = 'ADC_Channel_8'|
11 	ADC_Channel_9 = 'ADC_Channel_9'|
12 	ADC_Channel_10 = 'ADC_Channel_10'|
13 	ADC_Channel_11 = 'ADC_Channel_11'|
14 	ADC_Channel_12 = 'ADC_Channel_12'|
15 	ADC_Channel_13 = 'ADC_Channel_13'|
16 	ADC_Channel_14 = 'ADC_Channel_14'|
17 	ADC_Channel_15 = 'ADC_Channel_15'|
18 	ADC_Channel_16 = 'ADC_Channel_16'|
19 	ADC_Channel_17 = 'ADC_Channel_17'|
20 	ADC_Channel_18 = 'ADC_Channel_18'|
21 	ADC_Channel_19 = 'ADC_Channel_19'|
22 	ADC_Channel_20 = 'ADC_Channel_20'
23 ;

ADC_sampling_times:

 1 enum ADC_sampling_times:
 2 	ADC_SampleTime_3Cycles = 'ADC_SampleTime_3Cycles'|
 3 	ADC_SampleTime_15Cycles = 'ADC_SampleTime_15Cycles'|
 4 	ADC_SampleTime_28Cycles = 'ADC_SampleTime_28Cycles'|
 5 	ADC_SampleTime_56Cycles = 'ADC_SampleTime_56Cycles'|
 6 	ADC_SampleTime_84Cycles = 'ADC_SampleTime_84Cycles'|
 7 	ADC_SampleTime_112Cycles = 'ADC_SampleTime_112Cycles'|
 8 	ADC_SampleTime_144Cycles = 'ADC_SampleTime_144Cycles'|
 9 	ADC_SampleTime_480Cycles = 'ADC_SampleTime_480Cycles'
10 ;

ADC_Number:

1 enum ADC_Number:
2 	ADC1 = 'ADC1'|
3 	ADC2 = 'ADC2'|
4 	ADC3 = 'ADC3'
5 ;

UART_Type:

1 enum UART_Type:
2 	USART1 = 'USART1'|
3 	USART2 = 'USART2'|
4 	USART3 = 'USART3'|
5 	UART4 = 'UART4'|
6 	UART5 = 'UART5'|
7 	USART6 = 'USART6'	
8 ;

USART_Word_Length:

1 enum USART_Word_Length:
2 	USART_WordLength_8b = 'USART_WordLength_8b'|
3 	USART_WordLength_9b = 'USART_WordLength_9b'
4 ;

USART_Stop_Bits:

1 enum USART_Stop_Bits:
2 	USART_StopBits_1 = 'USART_StopBits_1'|
3 	USART_StopBits_0_5 = 'USART_StopBits_0_5'|
4 	USART_StopBits_2 = 'USART_StopBits_2'|
5 	USART_StopBits_1_5 = 'USART_StopBits_1_5'
6 ;

USART_Parity:

1 enum USART_Parity:
2 	USART_Parity_No = 'USART_Parity_No'|
3 	USART_Parity_Even = 'USART_Parity_Even'|
4 	USART_Parity_Odd = 'USART_Parity_Odd'
5 ;

USART_Hardware_Flow_Control:

1 enum USART_Hardware_Flow_Control:
2 	USART_HardwareFlowControl_None = 'USART_HardwareFlowControl_None'|
3 	USART_HardwareFlowControl_RTS = 'USART_HardwareFlowControl_RTS'|
4 	USART_HardwareFlowControl_CTS = 'USART_HardwareFlowControl_CTS'|
5 	USART_HardwareFlowControl_RTS_CTS = 'USART_HardwareFlowControl_RTS_CTS'
6 ;

DIS_EN:

1 enum DIS_EN:
2 	DISABLE = 'DISABLE'|
3 	ENABLE = 'ENABLE'
4 ;

GPIO_AF:

1 enum GPIO_AF:
2 	GPIO_AF_USART1 = 'GPIO_AF_USART1'|
3 	GPIO_AF_USART2 = 'GPIO_AF_USART2'|
4 	GPIO_AF_USART3 = 'GPIO_AF_USART3'	
5 ;

GPIO_PinSource:

 1 enum GPIO_PinSource:
 2 	GPIO_PinSource0 = 'GPIO_PinSource0'|
 3 	GPIO_PinSource1 = 'GPIO_PinSource1'|
 4 	GPIO_PinSource2 = 'GPIO_PinSource2'|
 5 	GPIO_PinSource3 = 'GPIO_PinSource3'|
 6 	GPIO_PinSource4 = 'GPIO_PinSource4'|
 7 	GPIO_PinSource5 = 'GPIO_PinSource5'|
 8 	GPIO_PinSource6 = 'GPIO_PinSource6'|
 9 	GPIO_PinSource7 = 'GPIO_PinSource7'|
10 	GPIO_PinSource8 = 'GPIO_PinSource8'|
11 	GPIO_PinSource9 = 'GPIO_PinSource9'|
12 	GPIO_PinSource10 = 'GPIO_PinSource10'|
13 	GPIO_PinSource11 = 'GPIO_PinSource11'|
14 	GPIO_PinSource12 = 'GPIO_PinSource12'|
15 	GPIO_PinSource13 = 'GPIO_PinSource13'|
16 	GPIO_PinSource14 = 'GPIO_PinSource14'|
17 	GPIO_PinSource15 = 'GPIO_PinSource15'
18 	
19 ;

Wie man vielleicht schon ahnen kann, passiert hinter den Kulissen eine ganze Menge mit der definierten Grammatik. Es wird nicht nur ein passendes Plug-in für Eclipse gebaut, auch das DSL-Dokument wird geparst und ein entsprechender Syntaxbaum, das EMF-Ecore-Meta-Model, daraus erzeugt. Um nun dies zu nutzen legt Xtext die Datei MyDslGenerator.xtend im Generator Verzeichnis an.

MyDsl.png


Code-Generator

Bei der Codegenerierung wird der eigentliche nutzen der Grammatik erst sichtbar. Die "Einsprungsdatei" des Generators ist die "MyDslGenerator.xtend". Durch die Größe des Systems und wegen Kapselungs-Gründen wird die Codegenerierung ist verschiede Dateien aufgeteilt.

  • MyDslGenerator.xtend, enthält die Aufrufe der Codegenerierung der einzelnen Module. Darüber hinaus wird in dieser Datei die "main.c" Datei erzeugt.
  • GPIO_Generator.xtend, enthält die Codegenerierung der Module GPIO-Template und GPIO-Specific.
  • ADC_Generator.xtend, enthält die Codegenerierung der Module ADC-Template und ADC-Specific.
  • USART_Generator.xtend, enthält die Codegenerierung der Module USART-Template und USART-Specific.

Die Generierung teilt sich in die folgenden Teilschritte auf:

Workflow.png

Hierbei ist ersichtlich, dass der erste Schritt das Löschen der Vorhandenen Daten ist. Dies ist erforderlich, da sonst redundante Datensätze vorhanden sind. Hierbei werden die Verzeichnisse Inc,Src und Obj gelöscht. Im Generierungsvorgang werden diese Verzeichnisse erstellt und mit neuen Daten gefüllt.

Die essentiellste Funktion im Codegenerator ist die "doGenerate" Funktion. In dieser wird über jede Komponente im Model iteriert und der entsprechende Code generiert.

 1 override void doGenerate(Resource resource, IFileSystemAccess fsa) {
 2   genData = new JavaIoFileSystemAccess(registry, encodingProvider)
 3   var String ProjektPath = System.getProperty("user.dir");
 4 
 5   var File srcFolder = new File(ProjektPath+"/Project/Cmsis_Libraries");
 6   var File destFolder_c = new File(ProjektPath+"/Project/Src");
 7   var File destFolder_h = new File(ProjektPath+"/Project/Inc");
 8 		
 9   Dir.deleteDir(new File(ProjektPath+"/Project/Inc"));
10   Dir.deleteDir(new File(ProjektPath+"/Project/Src"));
11   Dir.deleteDir(new File(ProjektPath+"/Project/Obj"));
12 		
13   genData.setOutputConfigurations(mapOutputConfigurations("Project", ProjektPath))
14 			
15   for(a: resource.allContents.toIterable.filter(typeof(ADC))){
16 	genData.generateFile("Src\\"+"ADC_"+a.name.toString() + ".c", ADC_Generator.compile(a))
17 	genData.generateFile("Inc\\"+"ADC_"+a.name.toString() + ".h", ADC_Generator.hcompile(a))
18   }
19 		
20   for(u: resource.allContents.toIterable.filter(typeof(USART))){
21 	genData.generateFile("Src\\"+"USART_"+ u.name.toString() + ".c", USART_Generator.compile(u))
22 	genData.generateFile("Inc\\"+"USART_"+u.name.toString() + ".h", USART_Generator.hcompile(u))
23   }
24 		
25   for(g: resource.allContents.toIterable.filter(typeof(GPIO))){
26 	  if((g.eContainer.eClass.name.equals("STM32F4"))){	
27 	  	genData.generateFile("Src\\"+"GPIO_"+g.name.toString() + ".c", GPIO_Generator.compile(g))
28 	  	genData.generateFile("Inc\\"+"GPIO_"+g.name.toString() + ".h", GPIO_Generator.hcompile(g))
29 	  }
30   }	
31 	  							
32   for(e: resource.allContents.toIterable.filter(typeof(STM32F4))  ){
33           genData.generateFile("Src\\"+"main.c", e.compile)	
34   }	   
35 }

Wie hier zu sehen ist wird für jede Komponente ein Source-Datei (.c) und eine Header-Datei (.h) erzeugt und die Hauptdatei main.c. In jeder dieser For-Schleifen wird die jeweilige "Compile"- Funktion der Komponente aufgerufen. In dieser Funktion wird über die Grammatik Variablen und Template Code die jeweiligen Dateien gefüllt.

Der Code-Generator ist nicht nur zur Generierung des jeweiligen Source - Codes zuständig, sonder er sorgt auch für die richtige Ordner Struktur und die Kommunikation mit dem Mikrocontroller.

Projekt-Struktur

Die Projekt-Struktur ist einer der wichtigsten Bestandteile des Systems. Diese sieht wie folgt aus:

Fehler beim Erstellen des Vorschaubildes: Datei fehlt

Hierbei ist zu beachten, dass das die beiden Dateien "arm-gcc-link.ld" und "STM32F4xx_1024.elf" für eine erfolgreiches Kompilieren und Flashen des Mikrokontrollers benötigt wird. Das Verzeichnis "Cmsis_Libraries" enthält alle wichtigen Source und Header - Dateien für das System. Diese werden vor dem "Buildvorgang" des Compile and Flash Mechanismus in die Verzeichnisse Inc und Src kopiert.

1   var String ProjektPath = System.getProperty("user.dir");
2   var File srcFolder = new File(ProjektPath+"/Project/Cmsis_Libraries");
3   var File destFolder_c = new File(ProjektPath+"/Project/Src");
4   var File destFolder_h = new File(ProjektPath+"/Project/Inc");
5  
6   copyFolder(srcFolder,destFolder_c,destFolder_h);

Der Kopiervorgang ist nicht der einzige Vorgang, welcher im Bezug auf die Projektstruktur erfolgt. Das "JavaIoFileSystemAccess" ist Standardmäßig auf eine andere Projektstruktur konfiguriert. Somit musste für die Generierung dies geändert werden. Dies erfolgt über die "Map" Funktion. Durch diese wird der richtige Pfad für die Codegenerierung einstellt.

 1   
 2 genData = new JavaIoFileSystemAccess(registry, encodingProvider)
 3 var String ProjektPath = System.getProperty("user.dir");
 4 
 5 genData.setOutputConfigurations(mapOutputConfigurations("Project", ProjektPath))
 6 
 7 def Map<String, OutputConfiguration> mapOutputConfigurations(String order, String path) {
 8        var OutputConfiguration defaultOutput = new OutputConfiguration(IFileSystemAccess.DEFAULT_OUTPUT);
 9        defaultOutput.setDescription("Output Folder");
10        defaultOutput.setOutputDirectory(path + "\\" + order);
11        defaultOutput.setOverrideExistingResources(true);
12        defaultOutput.setCreateOutputDirectory(true);
13        defaultOutput.setCleanUpDerivedResources(true);
14        defaultOutput.setSetDerivedProperty(true);
15        var Map<String, OutputConfiguration> mapconfig = new HashMap()
16        mapconfig.put("DEFAULT_OUTPUT", defaultOutput)
17 
18        return mapconfig
19 }

Kommunikation mit dem STM32F4

DIe Kommunikation mit dem STM32F4 wird über den "Compile and Flash" Mechanismus durchgeführt, welcher im Kapitel 7 näher beschrieben ist. Der Aufruf dieses Vorgangs wird durch die Klasse "CAPService.java" durchgeführt. Diese liegt in dem selben Generatorverzeichnis. Wurde der jeweilige Code der Komponenten erzeugt, wird danach der Build Vorgang gestartet.

 1 try {
 2   var CAPService caps = new CAPService(ProjektPath+"\\Project");
 3   caps.buildProject();
 4   caps.downloadProject();
 5   } catch (Throwable e) { 	
 6 	System.out.println("Es ist liegt ein Fehler im CAPService vor.");
 7 	System.out.println("Laden Sie sich bitte die GCC Tools");
 8 	System.out.println("Die .bat Dateien wurden generiert.");
 9 	System.out.println(e.getMessage());							
10 }


Aufgetretene Schwierigkeiten

Im laufe des Projekts sind viele Schwierigkeiten aufgetreten. Die wichtigsten dieser Schwierigkeiten wird im folgenden beschrieben.

Aus Zwei muss Eins

Die meisten Mikrocontroller der heutigen Zeit werden nicht mit Eclipse, bzw. Java betrieben. Somit musste eine Möglichkeit gefunden werden, die eigentlichen Entwicklungswerkzeuge in Verbindung mit Eclipse zu nutzen. Hierbei wurde ein Vorgang entwickelt, welcher über die Kommandozeile die benötigten Vorgänge durchführt.

Abhängigkeiten

In Eclipse ist alles von einander abhängig, insbesondere in Verknüpfung mit Xtext. Somit bestand die Schwierigkeit dem System die Abhängigkeiten für das Apache commons-exec-1.3 zu konfigurieren. Nachdem die benötigten .jar Dateien in die Plugin Ordner der Eclipse Instanz kopiert wurden, konnte über einen Quickfix diese ins System eingebunden werden.

Der Ordner Src-gen

Das System war auf die Projektstruktur konfiguriert, welche im Kapitel 9.1 erläutert wurde. Die Generierung des Quellcodes aus dem Model wurde jedoch in ein anderes Verzeichnis generiert. Dieses war das Src-gen Verzeichnis. Die Schwierigkeit hierbei war die Standard Projektstruktur auf die benötigte Projektstruktur umzustellen.

Git-Repository

Mit einem Git - Repository sollte es eigentlich alles leichter sein. Dies war in diesem Projekt Fehlanzeige. Das Git Repository kämpfte zu erst mit zu langen Datenpfaden. Durch ein Konfiguration wurde dies jedoch beseitigt. Anschließend wurden Verzeichnisse und Metadaten der Eclipse IDE nicht gepusht und es entstand ein durchgehender Fehler. Die Lösung hierfür war der Umstieg auf einen USB-Stick.

Redundanz

Durch Namensänderung der jeweiligen Komponenten des Models wurden die vorhanden Source und Header Dateien nicht entfernt und lagen somit in der Projekt Struktur. Es musste sich somit ein Vorgang entwickelt werden, wodurch alte generierte Daten gelöscht werden und die benötigten Bibliotheken des Mikrocontrollers bestehen bleiben. Dies wurde durch den Vorgang gelöst, welcher in Kapitel 9.1 erläutert wird.

Eigentlich ein Normal

Durch einen benötigten Kopiervorgang musste ein byte Array angelegt werden. Dies war in Xtext nicht ohne weiteres möglich. Es musste somit eine Klasse JavaHelper erstellt werden, welche eine Funktion byteArray enthält und ein byte Array zurück gibt.

1 public  byte[] byteArray(int length) {
2   return new byte[length];
3 }


Getting Started

In dieser Anleitung wird das Projekt Easy STM32 beschrieben. Beginnend von der Installation bis hin zum fertigen stm32f4 Programm.

Download der Projektdateien

Die Projekt Source-Dateien können unter:

    Link Repository:  git@git.thm.de:agms24/MDD_Easy_STM32.git
    Download: https://git.thm.de/agms24/MDD_Easy_STM32/repository/archive.zip

heruntergeladen werden. Das starten des Projekts in der Eclipse IDE erfolgt über die Auswahl des Projektverzeichnisses als Eclipse "Workspace" und es benötigt somit keiner Import Anweisung. Ist der Workspace erfolgreich auf das Projekt Konfiguriert, erhält man folgende Ansicht:

STM Transition

Der Explorer zeigt die 4 Verzeichnisse.

  • org.xtext.Easy_STM32F4
  • org.xtext.Easy_STM32F4.sdk
  • org.xtext.Easy_STM32F4.tests
  • org.xtext.Easy_STM32F4.ui

an, wobei uns vorerst nur die Verzeichnisse "org.xtext.Easy_STM32F4" und "org.xtext.Easy_STM32F4.ui" interessieren. Das Verzeichnis "org.xtext.Easy_STM32F4" beinhaltet die Grammatik und den Code-Generator des Easy_STM32 und das Verzeichnis "org.xtext.Easy_STM32F4.ui" wird benötigt um das User Interface zu starten.

Grammatik

Nachdem das Projekt erfolgreich in der Eclipse IDE eingebunden ist, kann die Grammatik des Easy_STM betrachtet werden. Diese befindet sich als XText Datei unter dem Verzeichnis "org.xtext.Easy_STM32F4" und heißt MyDsl.xtext.

Fehler beim Erstellen des Vorschaubildes: Datei fehlt

Diese Grammatik kann nach belieben angepasst werden. Zurzeit sind die Module GPIO,ADC und USART implementiert, jedoch nicht mit allen Erweiterungen. Hat man seine Grammatik ergänzt, kann über einen "Rechtsklick" auf "GenerateMyDsl.mwe2" oder "MyDsl.xtext" die Grammatik übersetzt werden.

Fehler beim Erstellen des Vorschaubildes: Datei fehlt

Im Übersetzvorgang erfolgt in der Konsole eine Meldung, zu laden eines Paketes. Dieses wird mit einem "y" bestätigt. War die Übersetzung erfolgreich, ist das letzte Kommando in der Konsole ein "Done".

Fehler beim Erstellen des Vorschaubildes: Datei fehlt

Generator

Nach dem Übersetzen der Grammatik muss der Generator erstellt und konfiguriert werden. Unter dem Packet org.xtext.example.mydsl.generator befinden sich die Generator Xtend Dateien der Easy_STM32.

Fehler beim Erstellen des Vorschaubildes: Datei fehlt

Diese sind hier aufgeteilt in die Hauptdatei "MyDslGenerator.xtend" und weiter Generator-Dateien, welche die einzelnen Komponenten des STM32F4 abbilden. Darüber hinaus enthält das Projekt einige Hilfsklassen,welche in den vorherigen Kapiteln erläutert sind.

Der Generator benötigt um Korrekt zu Arbeiten noch einige Einstellungen. Da der Generator Quellcode auf das STM32F4 kompeliert und flasht, werden die "Apache commons-exec-1.3" Bibliotheken benötigt. Diese müssen unter die "Plug-in Dependencies" eingebunden werden. Über die Projekt Eigenschaften (Properties) kann geprüft werden, ob diese darin enthalten sind.

Fehler beim Erstellen des Vorschaubildes: Datei fehlt

Unter der Option "Java Build Path" und dem Reiter "Libraries" und "Plug-in Dependencies" muss die Bibliothek "commons-exec-1.3.jar" enthalten sein.

Fehler beim Erstellen des Vorschaubildes: Datei fehlt

Konfiguration und Start

Ist die Konfiguration des Generators abgeschlossen muss sichergegangen werden, ob die erforderlichen Dateien, des STM32F4, im Projektverzeichnis enthalten sind. Hierbei muss unter dem Projektpfad das Verzeichnis "Project" vorhanden sein.

STM Transition

Dieses Verzeichnis enthält die benötigte Ordner und Datei Struktur, welche im Kapitel Code-Generator näher erläutert wurde.

Fehler beim Erstellen des Vorschaubildes: Datei fehlt

Die abschließende Einstellung vor dem Start, ist die Umkonfiguration des "Working Directories" der Eclipse IDE. Dies wird unter den "Run Configurations" durchgeführt.

Fehler beim Erstellen des Vorschaubildes: Datei fehlt

Hierbei ist zu beachten, dass das "Working Directory" unter "File System..." auf das Unterverzeichnis "Eclipse" eingestellt ist.

Fehler beim Erstellen des Vorschaubildes: Datei fehlt

Dies wird benötigt, damit das System den Pfad für die generierten Dateien kennt. Hierdurch sind alle notwendigen Konfigurationen durchgeführt und dann Programm kann gestartet werden.

Fehler beim Erstellen des Vorschaubildes: Datei fehlt

Easy STM32

Ist das Programm erfolgreich gestartet, erhält man ein leeren "Project Explorer". Zu aller erst benötigt es nun ein leeres Projekt. Dies erfolgt über einen "Rechtsklick" auf den "Project Explorer", auf den Reiter "New2 und anschließend auf "Others".

Fehler beim Erstellen des Vorschaubildes: Datei fehlt

Unter "Others" wird ein "General Project" ausgewählt und mit einem gewünschten Namen konfiguriert.

Fehler beim Erstellen des Vorschaubildes: Datei fehlt

In diesem Schritt erfolgt die erste eigentliche Nutzung unser Grammatik. Hierbei wird eine neue Datei in dem Projekt erstellt.

Fehler beim Erstellen des Vorschaubildes: Datei fehlt

Wichtig: Diese benötigt die Dateiendung: stm32f4.

STM Transition

Wurde dies durchgeführt, kommt eine Hinweis des Systems, ob die Verbindung zum XtextNature durchgeführt werden soll.

Fehler beim Erstellen des Vorschaubildes: Datei fehlt

Das Projekt ist mit diesem Schritt abgeschlossen. Es kann nun angefangen werden, unter stm32f4 zu programmieren.

Fehler beim Erstellen des Vorschaubildes: Datei fehlt

Hat man einige Komponenten eingefügt, werden durch das Speichern des Projekts automatisch die jeweiligen Komponenten erzeugt, kompiliert und bei einem angeschlossenen Board, geflasht.

Tipp: Mit dem Kommando "Strg + Leertaste" lassen sich die Befehle durch die Autovervollständigung schreiben.


Zukunft und Ausblick

Um das Projekt "MDD Easy STM32" massentauglich zu machen, benötigt es noch weitere Arbeit. Konzeptionell wäre es ein hoch priorisiertes Ziel einen visuellen Editior für das Projekt bereitzustellen, mit dem man z.B. grafisch orientiert arbeiten könnte, so wie man es z.B. auch in Simulink von Mathworks machen kann. Hierfür wäre evtl. Sirius ein geeignetes Mittel. Ein Quellcode Editor für die Sprache stm32f4 ist ebenso angedacht, in dem angepasste Optionen, Buttons etc. verfügbar sind.

Ein weiterer Punkt ist, das noch viele weitere Funktionen des STM32F4 mit aufgenommen werden müssen. Wie schon erwähnt, verfügt der STM32F4 über viele Schnittstellen und Funktionen (DMA, Crypto-Prozessor, DAC, CAN, SPI, I2C und viele mehr), diese müssten noch in das Projekt implementiert werden. Ein stabiles Grundgerüst steht, jedoch muss die Fassade noch ausgebaut werden.

In der Zukunft wäre der Einsatz in Hochschulen zu lehrzwecken denkbar, vor allem für Menschen ohne C-Kentnisse. Auch im industriellen Bereich ist ein Einsatz denkbar. Man könnte Entwicklungszyklen reduzieren, indem man den Quellcode mit MDD Easy STM32 schreibt.


Fazit

Abschließend lässt sich sagen, das der letzte Feinschliff der vielleicht nur 10% des Umfang des Projekts ausmacht, mehr Zeit in Anspruch genommen hat als die restlichen 90% der Entwicklung.

Nachfolgend noch einmal von jedem der Projektteilnehmer ein Fazit:

Ali Gümüs

Ich bin positiv davon überrascht das wir es am Ende geschafft haben eine neue Sprache zu definieren und diese dann erfolgreich auf den Mikrocontroller übertragen zu können. Es hat einiges an Arbeit gebraucht und wir hatten auch mit einigen Problemen zu kämpfen gehabt aber der Aufwand hat sich gelohnt. Ich denke wenn wir noch mehr Zeit in dieses Projekt investieren, könnte man daraus ein erfolgreiches Produkt machen, mit dem man sich einen Namen machen kann und das vor allem in der Industrie und in Hochschulen eingesetzt werden kann. Was mir auch sehr gut gefällt ist das wir keine Bastellösung haben, sondern direkt nach dem erstellen unseres Codes alles auf den Mikrocontroller packen können ohne manuell eingreifen zu müssen.

Max Rasumak

Ein System Modellgetrieben abzubilden ist ein schwieriges Unterfangen. Wurde dies jedoch gut geplant und entwickelt entsteht eine wirkliche Erleichterung für den Anwender. Durch wenige Klicks kann somit ein System entstehen, welches über 10 Daten benötigt. Durch einen Klick kann dieses durch das Projekt sogar geflasht werden. Für ein Eingebettetes System reicht ein textueller Editor nicht aus, es benötigt eine Visuelles Model. Im großen und ganzen werte ich das Projekt als sehr erfolgreich. Die Schwierigkeiten wurden überwunden und das Projekt soweit abgeschlossen, so das der STM32F4 sogar geflasht werden kann und das tut was er soll, arbeiten.


Projektablauf

Den Ablauf unseres Projekts zeigen wir nachfolgend an den Tagen, die wir benötigt haben, auf.

Tag 1, 10. August 2015

  1. Vorbesprechung
  2. Installation Tools
  3. Grobe Planung des Projekts
  4. Wiki und Git angelegt
  5. Erstellung von Quellcode für Peripherien und Schnittstellen
  6. STM Reference Projekte beschafft
  7. Eclipse Xtext Projekt angelegt
  8. Probleme mit Git gelöst
  9. Workflow der Planung / Digital

Tag 2, 11. August 2015

  1. Syntaxkonzept
  2. Erstellen einer STM32F4 Testreferenz
  3. Grammatik Definition GPIO
  4. Xtend Generator Template GPIO
  5. Generierung der ersten C-Datei
  6. Besprechung des weiteren Vorgehens
  7. Erstellen einer Java Klasse zum kompilieren, linken und flashen des C-Codes für den STM32F4

Tag 3, 12. August 2015

  1. Erstellung einer Demo-Anwendung für den STM32F4
  2. Erstellung der Grammatik für den ADC
  3. Generator: Demo Template GPIO LED
  4. Generator: Demo Template Spezifisches GPIO
  5. Generator: Demo Template Spezifischer ADC
  6. Generator: Erzeugung Main.c + alle vorhandenen Komponenten
  7. Generator: Erzeugung Header Dateien (.h) von allen vorhandenen Komponenten
  8. Generator: Einbindung von Template Funktionen in Main.c
  9. Besprechung der nächsten Komponenten
  10. Planung Projekt Lüfter Ansteuerung
  11. Generierung von *.bat Skripten auf Java, um das Projekt ohne eine zusätzliche Enwicklungsumgebung auf das Board zu Flashen
  12. Bug-Fixes
  13. Erstellung einer USART Refernzanwendung
  14. Demo Anwendung USART-Terminal

Tag 4, 13. August 2015

  1. Pinbelegungen für implementierte Schnittstellen
  2. Implementierung USART in die Grammatik
  3. Verlagerung des Generators auf verschieden Xtend Dateien
  4. Doku konnte wegen CAS störung nicht geführt werden
  5. PWM auf STM um Lüfter zu steuern!
  6. Generator: Demo Template USART
  7. Generator: Template USART Specific
  8. Anpassung der Includes der generierten Dateien
  9. BugFixes Grammatik
  10. BugFixes Generator
  11. Einarbeitung in Sirius
  12. Einarbeitung in Java Plugins

Tag 5, 14. August 2015

  1. Einbindung der generierten Header Dateien in die Main.c
  2. Erzeugung einer TemplateAnwendung durch die generierten Templates
  3. Anpassung der Namenskonventionen
  4. Erstellung einer PWM Anwendung für die Demonstration
  5. Integration des Kompilier, Linker und Flashvorgang in die Anwendung
  6. Auslagerung der generierten *.c und *.h Dateien in eine andere Ordnerstruktur
  7. Hinzufügen von Code-teilen um Windows und Unix zu unterscheiden


Nachbearbeitung

Die Zwei wochen zwischen der Blockveranstaltung und der Präsentation wurden komplett genutzt um das Projekt fertigzustellen bzw. abzurunden. Es gab einige Probleme mit der Eclipse Umgebung die unsere Arbeit für einige Zeit blockiert hat, aber gelöst werden konnte.

Weiterhin wurden in der Nachbearbeitungszeit noch Tests und Optimierungen am Projekt durchgeführt. Die Dokumentation und dessen Struktur wurde ebenfalls in der Nachbearbeitungszeit weitergeführt und beendet.