ARM Embedded

Antworten
mse
Beiträge: 2013
Registriert: Do 16. Okt 2008, 10:22
OS, Lazarus, FPC: Linux,Windows,FreeBSD,(MSEide+MSEgui 4.6,git master FPC 3.0.4,fixes_3_0)
CPU-Target: x86,x64,ARM

Re: ARM Embedded

Beitrag von mse »

Mathias hat geschrieben:
Die units müssen in "uses" aufgeführt werden, es werden die in 'Projekt'-'Options'-'Debugger'-'Source directories' aufgeführten Verzeichnisse durchsucht.

Dies ist ein Problem, das die STM32xxxx Unit automatisch eingebunden ist, ähnlich der Unit system.

Man kann die unit vor FPC verbergen:

Code: Alles auswählen

 
program stm32l100c;
{$ifdef debugging}
uses
 stm32f10x_ld;
{$endif}
var
 testvar: int32;
begin
 porta.crl:= 0;
 while true do begin
  testvar:= testvar + 1;
 end;
end.
 
Dateianhänge
debugginguses1.png

Mathias
Beiträge: 6160
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: ARM Embedded

Beitrag von Mathias »

Könntest du zu deinen Examples noch einen einfach Blinker hinzufügen ?
Diese wäre für das Tutorial interessant, wen man ein erstes Project hat, in dem die PC13 blinkt.

Code: Alles auswählen

program Blinker_PC13;
 
procedure Delay;
var
  i: uint32;
begin
  for i := 0 to 500000 do begin
    asm nop end; // Leerbefehl
  end;
end;
 
begin
  // PortC einschalten
  RCC.APB2ENR := RCC.APB2ENR or (%1 shl 4);
 
  // Pin P13 von PortC aud Output.
  PortC.CRH := $00300000;
 
  // Hinweis: Die LED leuchtet bei LOW.
  while true do begin
 
    // Pin13 -- High
    PortC.BSRR := 1 shl 13;
    Delay;
 
    // Pin13 -- Low
    PortC.BRR := 1 shl 13;
    Delay;
  end;
end.


Im Englischen Forum gibt es einen Beitrag, wie man DebugWire unter Lazarus nutzen kann:

Ich sehe schon, FPC unterstützt die AVR/ARM besser als Arduino. Bei Arduino habe ich nie was gelesen von externen Debugen ausser Serial.Write .
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

mse
Beiträge: 2013
Registriert: Do 16. Okt 2008, 10:22
OS, Lazarus, FPC: Linux,Windows,FreeBSD,(MSEide+MSEgui 4.6,git master FPC 3.0.4,fixes_3_0)
CPU-Target: x86,x64,ARM

Re: ARM Embedded

Beitrag von mse »

Das Demoprogramm ist gedacht für stm32l100cdiscovery board:
http://www.st.com/en/evaluation-tools/3 ... overy.html
Es hat den Prozessor STM32L100RCT6 welcher von Free Pascal nicht direkt unterstützt wird. Darum das Minimalprogramm ohne Peripherie-Ansprache.

Mathias
Beiträge: 6160
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: ARM Embedded

Beitrag von Mathias »

Jetzt habe ich gerade etwas merkwürdiges entdeckt.

Ich habe gerade versucht, einen 2. STM32 zu programmieren. Das komische dabei, dieser STM32 läuft schneller ( Die LED blinkt schneller ).
Könnte es sein, das ich mit der Arduino IDE die Taktfrequenz geänderd habe ? Die STM32 hatte ich zuerst mit der Arduino-IDE programmiert gehabt.

Vielleicht habe irgend ein Fuse oder ähnlichen Parameter verändert, so wie man es beim AVR dies möglich ist.
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

mse
Beiträge: 2013
Registriert: Do 16. Okt 2008, 10:22
OS, Lazarus, FPC: Linux,Windows,FreeBSD,(MSEide+MSEgui 4.6,git master FPC 3.0.4,fixes_3_0)
CPU-Target: x86,x64,ARM

Re: ARM Embedded

Beitrag von mse »

Die Taktfrequenz wird vielleicht in der FPC Startup Routine gesetzt, ich kenne mich damit nicht aus. In rtl/embedded/arm/cortexm3_start.inc findet sich nichts.
startup.png

Nach Reset springt MSEide mit 'Target'-'Step Instruction' auf die erste Operation des geladenen Programms, danach kann die Initialisierung verfolgt werden.
Über allfällige "fuses" zur Takteinstellung müsste das Datenblatt des uP Auskunft geben. Ein Blick in
http://www.st.com/resource/en/datasheet/stm32f103c4.pdf
liefert:
 
2.3.7
Clocks and startup
System clock selection is performed on startup, however the
internal RC 8 MHz oscillator is selected as default CPU clock on reset.
 

Nichts von "fuses".
Genaueres steht hier:
http://www.st.com/content/ccc/resource/ ... 171190.pdf
unter 7.2 Clocks.

Die Verwendung einer Loop als Timer ist sowieso keine gute Idee. Die Laufzeit einer NOP Schlaufe ist von zu vielen Bedingungen abhängig.
Besser ist ein Hardwaretimer welcher z.B. einen 1ms Tick Interrupt erzeugt. Die Interrupts werden in einer Tickcount Variable gezählt und können als Zeitstrahl verwendet werden. Diese Demo von ST verwendet das Prinzip:
https://gitlab.com/mseide-msegui/mseuni ... inkerdebug
Bitte berücksichtige README.TXT.

Mathias
Beiträge: 6160
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: ARM Embedded

Beitrag von Mathias »

Nichts von "fuses".
Genaueres steht hier:
http://www.st.com/content/ccc/resource/ ... 171190.pdf
unter 7.2 Clocks.
Ich habe da mal kurz rein geguckt, über 1'000 Seiten ! :shock:
Wahnsinn, was das Teil alles kann.

Die Verwendung einer Loop als Timer ist sowieso keine gute Idee. Die Laufzeit einer NOP Schlaufe ist von zu vielen Bedingungen abhängig.
Besser ist ein Hardwaretimer welcher z.B. einen 1ms Tick Interrupt erzeugt. Die Interrupts werden in einer Tickcount Variable gezählt und können als Zeitstrahl verwendet werden. Diese Demo von ST verwendet das Prinzip:
Da hast du recht, dies ist Müll, aber zuerst muss ich mal rausfinden, wie das mit den Timern geht.

Bisschen etwas hab ich schon probiert:

Code: Alles auswählen

procedure TIM2_global_interrupt; public Name 'TIM2_global_interrupt'; interrupt;
begin
  PortC.ODR := $FFFF;
end;
 
begin
  Timer2.SR := 0;
  //Timer2.PSC := 0; 
//  Timer2.CR1 := Timer2.CR1 or TIM_CR1_CEN; 
//  while Timer2.SR and TIM_SR_UIF do begin
//  end;

Da werde ich wohl zuerst mit der Arduino-IDE anfangen müssen. C++ Beispiele wird man sicher irgendwo finden.
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

mse
Beiträge: 2013
Registriert: Do 16. Okt 2008, 10:22
OS, Lazarus, FPC: Linux,Windows,FreeBSD,(MSEide+MSEgui 4.6,git master FPC 3.0.4,fixes_3_0)
CPU-Target: x86,x64,ARM

Re: ARM Embedded

Beitrag von mse »

Mathias hat geschrieben:
unter 7.2 Clocks.
Ich habe da mal kurz rein geguckt, über 1'000 Seiten ! :shock:

Ausdrucken muss man es erst noch selber.

Da werde ich wohl zuerst mit der Arduino-IDE anfangen müssen. C++ Beispiele wird man sicher irgendwo finden.

Dies
https://gitlab.com/mseide-msegui/mseuni ... inkerdebug
ist ein entsprechendes Beispiel.
Bitte berücksichtige README.TXT.

Mathias
Beiträge: 6160
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: ARM Embedded

Beitrag von Mathias »

Ausdrucken muss man es erst noch selber.

Da müsste ich zuerst Papier kaufen. :mrgreen:

Dies
https://gitlab.com/mseide-msegui/mseuni ... inkerdebug
ist ein entsprechendes Beispiel.
Bitte berücksichtige README.TXT.

Fehlt da nicht eine *.pas Datei ?
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

mse
Beiträge: 2013
Registriert: Do 16. Okt 2008, 10:22
OS, Lazarus, FPC: Linux,Windows,FreeBSD,(MSEide+MSEgui 4.6,git master FPC 3.0.4,fixes_3_0)
CPU-Target: x86,x64,ARM

Re: ARM Embedded

Beitrag von mse »

Das ist ein C-Projekt aus der Demo Sammlung des STM32CubeL1 framework.
http://www.st.com/content/st_com/en/pro ... ubel1.html

Mathias
Beiträge: 6160
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: ARM Embedded

Beitrag von Mathias »

Ein C Datei hat es auch keine, nur die Project, ein .elf und die Readme.
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

mse
Beiträge: 2013
Registriert: Do 16. Okt 2008, 10:22
OS, Lazarus, FPC: Linux,Windows,FreeBSD,(MSEide+MSEgui 4.6,git master FPC 3.0.4,fixes_3_0)
CPU-Target: x86,x64,ARM

Re: ARM Embedded

Beitrag von mse »

Ich darf keine St-Dateien zum Download bereitstellen. In README.TXT steht, woher man die Sourcen bekommt. Zum Ausprobieren des Programmes reicht die *.elf Datei.
README.TXT:

Code: Alles auswählen

 
Debug demo project for STM32L100C-Discovery board    2018-04-06 mse
-------------------------------------------------
 
- clone, build and install the texane ST-Link tools:
https://github.com/texane/stlink
see
https://github.com/texane/stlink/blob/m ... mpiling.md
 
- Download the ARM toolchain:
https://developer.arm.com/open-source/g ... /downloads
 extract it to a directory of your choice (<toolchaindir>).
 
- Download the ST firmware STM32CubeL1:
http://www.st.com/content/st_com/en/pro ... are-scroll
 extract it to a directory of your choice (<firmwaredir>).
 
- Run MSEide.
- 'Project'-'Open'-"blinkerdebug.prj".
- 'Project'-'Options'-'Macros', update <toolchaindir> and <firmwaredir>.
- 'Target'-'Download' in order to flash the program.
- 'Target'-'Continue' in order to run the program.
 

siro
Beiträge: 730
Registriert: Di 23. Aug 2016, 14:25
OS, Lazarus, FPC: Windows 11
CPU-Target: 64Bit
Wohnort: Berlin

Re: ARM Embedded

Beitrag von siro »

Der Cortex M3 Kern hat einen internen 24 Bit Abwärtszähler (SysTick)
Dazu lediglich 4 Register von denen ich nur 2 benötige.
Das SysTick reload value register bestimmt den Intervall
hier schreibt man den Wert rein wie oft ein Interrupt auftreten soll
und ein Control Register, wo man festlegt welcher Clock benutzt wird und obo der Interrupt eingeschaltet wird.
Ich hab das so berechnet:

Code: Alles auswählen

 
#define SYSTIMER_IN_FREQ  72000000     // Quarzfrequency 72 MHz
#define SYSTIMER_INTERVAL 1000          // 1000 interrupts per second ==> 1ms
 
STK_LOAD = (SYSTIMER_IN_FREQ / SYSTIMER_INTERVAL)-1;   // 1 Millisekunden Interrupt
STK_CTRL = 7;                                          // counter enable, enable interrupt use processor clock
 


Wichtig ist, dass der Name der Interruptfunktion entsprechend in die Vectorentabelle eingetragen wird.
Hier haben verschiedenen Hersteller anscheinend verschiedene Namen vergeben.
Die stehen meist in der startup datei. Sonst sucht man sich einen Wolf warum der Interrupt nie aufgerufen wird.
im Prinzip wie Du schon gemacht hast:

Code: Alles auswählen

procedure TIM2_global_interrupt; public Name 'TIM2_global_interrupt'; interrupt;


Übrigens braucht man in der Interrupt Funktion bei diesem Timer kein Interrupt Bit löschen.

Bei mir in "C"
sieht das so aus: wobei das "volatile" Problem in Pascal vermutlich nicht existiert..... :wink:

Code: Alles auswählen

 
/* EXTREM wichtig: volatile, sonst erzeugt der C-Compiler FALSCHEN code */
/* bzw. kürz den Code komplett weg....*/
volatile static uint_32t DelayCount;  /* used for delay_ms function */
/*----------------------------------------------------------------------------*/
void Delay_ms(uint_32t ms)
{
  DelayCount = ms;
 
  while (DelayCount)
  {
 
  }
}
/*----------------------------------------------------------------------------*/
/* this Interrupt handler is called every Millisecound */
/* we dont need to clear any interrupt flag in this handler */
 
void SysTick_Handler(void)    // Der Name ist hier ganz entscheidend, damit er in die Vectoren Tabelle eingetragen wird.
{
  if (DelayCount) DelayCount--;
}
/*----------------------------------------------------------------------------*/
void SysTickInit(void)
{
  SYST_RVR = (SYSTIMER_IN_FREQ / SYSTIMER_INTERVAL)-1;
 
 /* Count enable, Interrupt enable, Clock source is Systemclock */
  SYST_CSR = 0x0007;
}
/*----------------------------------------------------------------------------*/



in PASCAL müsste das vermutlich irgendwie so aussehen:

Code: Alles auswählen

 
 
const SYSTIMER_IN_FREQ  = 72000000;     // Quarzfrequenz 72 MHz bei meinem LPC1347
const SYSTIMER_INTERVAL = 1000;         // 1000 interrupts pro Sekunde ==> 1ms
 
const SYSTICK_BASE_ADDRESS = $E000E010;   // Basisadresse beim STM32Fxxx
 
var STK_CTRL  : DWORD absolute SYSTICK_BASE_ADDRESS + 0;    // Steuerung interupt Clock select usw.
var STK_LOAD  : DWORD absolute SYSTICK_BASE_ADDRESS + 4;    // Zaehlerwert welcher beim Erreichen von 0 wieder geladen werden soll
var STK_VAL   : DWORD absolute SYSTICK_BASE_ADDRESS + 8;    // aktuelle Zählerstand des 24 Bit Zählers
var STC_CALIB : DWORD absolute SYSTICK_BASE_ADDRESS + 12;   // $2328 ==> 9000 dez. warum steht der Wert stanbdardmässig auf 9000 ????
 
var delayCount : DWORD;  // für die Delay procedure
 
// !!!! ich weis nicht wie der interrupt heissen muss....bitte den richtigen Namen eintragen
procedure SYSTICK_global_interrupt; public Name 'SYSTICK_global_interrupt'; interrupt;
begin
  if delayCount > 0 then dec(delayCount);
end;
 
procedure Delay_ms(ms:DWORD);
begin
  delayCount := ms;              // gewünschten Zeitwert setzen
  while (delayCount > 0) do ;    // wird dann im SysTick-Interrupt jede Millisekunde runtergezählt
end;
 
// SysTick auf eine Millisekunde initialisieren
// bei meinem LPCxx läuft das zumindest so:
procedure InitDelay;
begin
  STK_LOAD := (SYSTIMER_IN_FREQ DIV SYSTIMER_INTERVAL)-1// 1 Millisekunden Interrupt
  STK_CTRL := 7;                                           // counter enable, enable interrupt, use processor clock
end;
               
 


Der Vorteil von dem internen Zähler des CORTEX M3 ist, das man sich vorerst nicht um den recht komplexen NVIC (Nested Interrupt Vector Controller) kümmern muss... :wink:


Siro
Grüße von Siro
Bevor ich "C" ertragen muß, nehm ich lieber Lazarus...

mse
Beiträge: 2013
Registriert: Do 16. Okt 2008, 10:22
OS, Lazarus, FPC: Linux,Windows,FreeBSD,(MSEide+MSEgui 4.6,git master FPC 3.0.4,fixes_3_0)
CPU-Target: x86,x64,ARM

Re: ARM Embedded

Beitrag von mse »

Eleganter da Tick von sleep() Prozedur unabhängig:

Code: Alles auswählen

 
type
 card32 = cardinal;
var
 tickcount: card32;
 
procedure SysTick_interrupt; public Name 'SysTick_interrupt'; interrupt;
begin
 inc(tickcount);
end;
 
procedure sleep(const ms: card32); //ms < maxint!
var
 timeout: card32;
begin
 timeout:= tickcount + ms;
 while int32(tickcount - timeout) < 0 do begin
  //hier könnte uP in einen geeigneten sleep mode
  //versetzt werden um Strom zu sparen. Ein beliebiger interrupt
  //lässt die procedure weiterarbeiten
 end;
end;
 
Zuletzt geändert von mse am Fr 20. Apr 2018, 07:42, insgesamt 1-mal geändert.

Mathias
Beiträge: 6160
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: ARM Embedded

Beitrag von Mathias »

Ich darf keine St-Dateien zum Download bereitstellen. In README.TXT steht, woher man die Sourcen bekommt. Zum Ausprobieren des Programmes reicht die *.elf Datei.
Ist dies nicht OpenSource ?

// !!!! ich weis nicht wie der interrupt heissen muss....bitte den richtigen Namen eintragen
Die findet man sehr leicht. Diese stehen alle in der Unit stm32f10x_ld.pp.

Mit eurer Hilfe habe ich schon mal den ersten Blinker in einem Timer hingekriegt.

Code: Alles auswählen

procedure SYSTICK_global_interrupt; public Name 'SysTick_interrupt'; interrupt;
const
  z:integer=0;
begin
  inc(z);
  if z > 10 then begin
    PortC.ODR := not PortC.ODR;
    z := 0;
  end;
end;
 
// SysTick auf eine Millisekunde initialisieren
// bei meinem LPCxx läuft das zumindest so:
procedure InitTimer;
begin
  STK_LOAD := (SYSTIMER_IN_FREQ DIV SYSTIMER_INTERVAL)-1// 1 Millisekunden Interrupt
  STK_CTRL := 7;                                           // counter enable, enable interrupt, use processor clock
end
 
begin
  InitTimer; 
 
  // Ports einschalten
  RCC.APB2ENR := RCC.APB2ENR or (%111 shl 2);
 
  // Ports auf Ausgabe schalten
  PortC.CRL := $33333333;
  PortC.CRH := $33333333;   
.....

Mein Ziel wäre, wen ich auch eine Timer-Interrupt anstelle von SYSTICK verwenden kann. SYSTICK. ist etwas, was ich beim AVR/Arduino vermutlich nicht gibt.
Aber immerhin, bin ich wieder ein Schritt weiter gekommen. 8) :wink:
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

Socke
Lazarusforum e. V.
Beiträge: 3158
Registriert: Di 22. Jul 2008, 19:27
OS, Lazarus, FPC: Lazarus: SVN; FPC: svn; Win 10/Linux/Raspbian/openSUSE
CPU-Target: 32bit x86 armhf
Wohnort: Köln
Kontaktdaten:

Re: ARM Embedded

Beitrag von Socke »

Mathias hat geschrieben:Mein Ziel wäre, wen ich auch eine Timer-Interrupt anstelle von SYSTICK verwenden kann. SYSTICK. ist etwas, was ich beim AVR/Arduino vermutlich nicht gibt.
Aber immerhin, bin ich wieder ein Schritt weiter gekommen. 8) :wink:

Auch der AVR hat Timer.
MfG Socke
Ein Gedicht braucht keinen Reim//Ich pack’ hier trotzdem einen rein

Antworten