Forum: Mikrocontroller und Digitale Elektronik Demo-Projekt mit LPC2292/94, TNKernel, MMC-SD-FAT, CodeBlocks


von Gottfried P. (gpra)


Lesenswert?

Demo-Projekt ARM LPC2292/94
===========================

Verwendete Hardware:

  SO-Dimm-Base Board von Embedded Artists mit uCLinux Quickstart Board 
v1.1
  Dieses Board ist ausgerüstet mit einem LPC2292 Controller und
  besitzt ein externes, 16 Bit breites PSRAM. Details siehe
  www.embeddedartists.com.

  J-Link USB JTAG Adapter von Segger, www.segger.com

  Logicport 34 Channel Analyzer von Intronix,www.pcTestInstruments.com


Verwendete Software und Tools, Entwicklung erfolgt unter XP:

  Compiler, Debugger aus WinARM Version 20060606 von Martin Thomas,
http://www.siwawi.arubi.uni-kl.de/avr_projects/arm_projects/index.html#winarm

  IDE Code::Blocks, www.codeblocks.org

  Terminalprogramm Termite, www.compuphase.com/productapps_en.htm


Anwendung:
  Als Ausgangsbasis wurde das Paket LPC2148_Demo_v120 von J.C. Wren,
  erhältlich bei jcwren.com/arm, verwendet.

  Das Paket von J.C. Wren ist ein ausgezeichnetes Beispiel, welches
  das gesamte Spektrum abdeckt, welches vom LPC2148, FreeRTOS und GCC
  geboten wird. Ich empfehle dringend, zuerst die Ausführungen in der
  README von Wren bzw. sein Demo-Projekt zu studieren.
  Ich habe dieses Projekt lediglich an die HW des LPC2292 bzw. LPC2294
  auf dem oben angeführten Entwicklungsboard angepasst. Weggefallen
  ist daher die Unterstützung des USB-Ports, dazugekommen sind die CAN
  -Schnittstellen.

  Weitere Änderungen sind:
  Anstatt des Multitaskers FreeRTOS wurde der TNKernel von Yuri
  Tiomkin  (www.tnkernel.com) eingesetzt.
  Das FAT-Filesystem von Elm Chan (elm-chan.org/fsw/ff/00index_e.html)
  wurde auf Version R0.06 gebracht. Die MMC-Anbindung (low-level
  Routinen) wurden ebenfalls weitgehend von Elm Chan übernommen. Mit
  den von J.C. Wren verwendeten Treibern liefen nicht alle MMC-SD
  Karten.
  Download: http://members.aon.at/gpra/2294tnk.zip

Beschreibung:
  Meine Zielsetzung ist ein schlankes und schnelles System, welches
  aus einem Multitasker, einem Filesystem und einem proprietären CAN-
  Bus besteht. Die Demo von Wren war eine ausgezeichnete
  Ausgangsbasis, an dieser Stelle meinen herzlichen Dank dafür!

  Leider läßt sich die Wren-Demo nicht so ohne weiteres unter WinARM
  übersetzen, Schuld daran ist die NewLib, welche sich in den
  aktuellen Versionen durch reentrante Fähigkeiten auszeichnet.
  Abgesehen von den nicht unerheblichen Änderungen, welche die
  zusätzlich notwendigen Stubs verursachen, ist der Preis
  für reentrante Eigenschaft ein hoher, für mich ein zu hoher.
  Konkret gibt es da den Impure-Pointer und die zugehörige
  Datenstruktur, welche von allen reentranten Funktionen benützt und
  daher vom Linker angelegt wird. Damit ist auf einen Schlag ca. 1K
  RAM weg, was bei den zur Verfügung stehenden 16K für mich
  unerträglich ist. Der Nutzen steht in keiner Relation: man kann eine
  Error-Variable abfragen und aus der Impure Struktur erfahren, warum
  ein konkurrierender File- oder Streamzugriff gescheitert ist. Lustig
  finde ich auch, dass diese Struktur auch dann angelegt wird, wenn
  die NewLib ohne reentrante Eigenschaft übersetzt wird!
  Das ist z.B. bei der Yagarto Distribution der Fall. Für das konkrete
  Projekt geht der Nutzen gegen Null, weil das Elm-Chan Filesystem
  nicht reentrant ist. Die Absicherung gegen nicht erlaubte
  konkurrierende Zugriffe erfolgt daher mit einer Mutex.
  Leider gibt es anscheinend keine Alternative zur NewLib, ich
  verwende daher deren Funktionen nur sehr verhalten. Auch der Code
  von Yuri Tiomkin geht in diese Richtung, so dass von putchar() bis
  printf() alles alternativ erstellt wurde. Auch malloc() musste
  eigenen Routinen weichen.
  Das vorliegende, sehr schlichte Mem_Alloc verwendet an Stelle einer
  verlinkten Liste eine Bitmap zur Kontrolle der Speicherbelegung.
  Zusätzlich kann gewählt werden, ob internes oder externes RAM
  alloziert werden soll.

  Kernel:
  Der TNKernel erscheint mir insgesamt schlanker und weniger mit
  Features überladen als FreeRTOS. Er ist sehr nahe an die ARM-
  Architektur angepasst und sehr klar strukturiert. Preemptives
  Multitasking, welches bei FreeRTOS die Standardbetriebsart zu sein
  scheint, erachte ich für Microcontroller-Anwendungen für wenig
  notwendig. Auch im kooperativen Modus wird ein Task, der z.B. in
  einer Endlos-Schleife läuft, unterbrochen, sobald ein höher
  priorisierter Task aktiv wird. Beim TNKernel kann, falls gewünscht,
  Round- Robin gezielt aktiviert werden.

  Interrupts:
  IRQ-Interrupts werden vom VIC vektorisiert. Der Kernel verwendet
  einen PWM- Kanal zur Erzeugung eines 1ms Interrupts. Die Timer sind
  somit dzt. unbenutzt.
  Im tn_cpu_irq_handler wird mittels tn_tick_int_processing das Task-
  Switching durchgeführt. Weiters werden die UARTS gepollt, derzeit
  nur UART0. Ja, richtig: die UARTS lösen keinen eigenen Interrupt
  aus. Diese Methode ist wesentlich effizienter, weil die UARTS ein
  16 Byte Fifo besitzen und somit locker die Zeit bis zum nächsten 1ms
  -IRQ überstehen, ohne dass der Fifo überläuft. Das funktioniert
  bestens bis einschließlich 115200 Bd.
  Für jedes Zeichen einen Interrupt auslösen ist
  Resourcenverschwendung!
  Die Problematik sporadischer Interrupts ist mit einem default-
  Handler abgedeckt und der Assemblercode entsprechend der NXP-
  Empfehlung ahingehend angepasst, dass IRQ- und FIQ-Flag nicht im
  selben cpsr-Zugriff gesetzt werden. Der FIQ wird dem CAN-Bus
  zugewiesen.

  CAN-Bus:
  Für die Demo wurde ein Task angelegt, welcher periodisch Daten im
  Kanal 1 versendet und eingehende CAN-Messages entgegennimmt. Der
  Sender wird mit einem Monitorkommando aktiviert: "misc cantx 1" und
  mit "misc cantx 0" wieder abgeschaltet. Es müssen externe CAN-Bus-
  Treiber angeschlossen sein, ansonsten versagt die Initialisierung
  der HW. Alle an den Bus ngeschlossenen CAN-Receiver empfangen die
  Daten und lösen einen RX- Interrupt aus.
  Alle CAN-Rx-Interrupts landen in der selben FIQ-ISR. Die eingehenden
  CAN-Messages werden eine Daten-Queue gestellt. Der CAN-Task nimmt
  die Messages am anderen Ende der Queue heraus und gibt sie via
  Console aus.
  Ich habe mein Demo-Board auf einen LPC2294 umgerüstet und kann somit
  alle 4 Kanäle nutzen. Außerdem wurde der Quarz von 14.7456 MHz auf
  12 MHz getauscht, damit die für CAN üblichen Baudraten erreicht
  werden können.
  Quarzfrequenz und Controllertyp sind in config.h definiert.


  FAT Filesystem, MMC-SD:
  Leider besitzt der LPC2292/94 erst in neueren Versionen SSP, der
  Datenstrom muss daher mit dem langsameren SPI-Interface erzeugt
  werden. Je nach SD-Karte lassen sich damit Transferraten bis ca. 230
  KByts erreichen.
  Im Monitor ist dafür ein Test eingebaut, "thruput" ohne Parameter.
  Wie schon erwähnt, sind alle File-Funktionen per Mutex gesichert.
  Alle File- Funktionen beginnen mit einem Underscore und
  unterscheiden sich etwas vom üblichen Standard: der Rückgabewert ist
  0 oder positiv für erfolgreiche Aktionen, negative Werte sind die
  Fehlercodes. Die Enumeration der Fehler wurde in ff.h  entsprechend
  geändert.

  Monitor:
  Vieles, was nur in der Wren-Demo Sinn macht, wurde entfernt. Die
  Stringkonstanten sind aus dem data- in den text-Bereich gewandert.
  "mem stacks" zeigt die System- und Task-Stacks mit Auslastung an.
  "mem map" zeigt die Speicherzuordungen an.
  "misc cantx 0|1" zum Testen der CAN-Busse.

  RTC:
  Die RTC des LPC2292/2294 kann leider nicht unabhängig von der CPU
  mit Backup- Strom betrieben werden. Auf die Zeitumrechnungen via
  NewLib wurde aus o.a. Gründen komplett verzichtet. Die RTC wird dzt.
  nur vom Filesystem benutzt, alle von J.C. Wren eingeführten
  Kommandos funktionieren aber.


Entwicklungsumgebung

  Das Projekt compiliert und läuft fehlerfrei unter WinARM und sollte
  auch in anderen Umgebungen funktionieren.
  Im Makefile kann als RUN_MODE entweder Flash oder EXTERNES RAM auf
  0x81000000 gewählt werden. Mit U-boot im Flash und einem TFTP-Server
  kann eine sehr bequeme Übertragung ins X-RAM erfolgen. Damit das
  auch mit einem 12MHz-Quarz funktioniert, habe ich U-Boot
  entsprechend angepasst. Dieses U-Boot Image liegt hier:
  http://members.aon.at/gpra/u-boot-2294-12.zip
  Mit LPC21ISP und dem Philips-Flash-Tool funktioniert die
  Baudratenerkennung bei 12MHz nur bis 38400 Bd.

  Debuggen:
  Die Embedded-Artists Basisplatine hat einen Fehler in der Belegung
  der JTag- Stiftleiste. Pin 15 (Reset) ist dort mit dem Signal RST-
  out verbunden, Pin 15 muss natürlich mit RST-in verbunden werden!
  Das Debuggen mit dem J-Link-Adaper und GDB funktioniert bestens. Der
  Start von GDB kann z.B. mit der Batch-Datei Debug_RAM.cmd erfolgen,
  die Monitor- Kommandos stellen den J-Link auf die korrekten
  Parameter ein.
  Als bester Debug-Parameter für GCC hat sich ggdb3 erwiesen. Damit
  wird auch  der Inhalt der LPC21xx.h mit den Registerdefinitionen in
  die Debug- Info gestellt. Allerdings kennt z.B. GDB 6.8.50 aus
  Yagarto diese Definitionen nicht mehr unterhalb des main()-Levels,
  GDB 6.6 dagegen schon.

  IDE:
  Eine tolle (und freie) IDE ist Code::Blocks. Obwohl für Embedded-
  Projekte noch nicht optimal angepasst, ist diese Umgebung sehr, sehr
  brauchbar und gefällt mir besser als Eclipse. Die Übersetzung kann
  per Makefile oder aus eigener Kraft per Projektverwaltung geschehen.
  Ich bevorzuge letzteres, die Einstellmöglichkeiten lassen keine
  Wünsche offen.
  Das einzige Problem in der aktuellen Version 8.02 ist das Remote-
  Debuggen. Es gibt da zwei Problempunkte:
    a) Start der Debuggersitzung:
      Unter Properties/Debugger/Additional Commands/After Connection/
      werden die Kommandos eingetragen, die das JTag-Interface per
      monitor xxxx konfigurieren. Dort sind üblicherweise auch die
      Kommandos um das Target zu laden, starten und bis zum ersten
      Breakpoint auf main() zu fahren. Klickt man anschließend in der
      IDE die Schaltfläche Debug/Continue, dann sendet diese das
      Kommando run, sollte natürlich continue sein. Je nach GDB-
      Version wird das entweder ignoriert oder GDB verabschiedet sich.
    b) Break-Signal
      Wenn man das Target per continue ohne erreichbaren Breakpoint
      laufen lässt, kann man den Ablauf nur stoppen, indem man Ctrl-C
      an den Debugger sendet. Wohlgemerkt ist das aber kein
      Tastendruck, sondern ein Signal, welches vom Betriebssystem
      gesendet werden muss. Aufgrund von Windows-Gegebenheiten
      funktioniert das derzeit nicht, unter Linux aber wohl. Man kann
      das Target also nie mehr anhalten und muss den GDB-Server
      beenden, damit es weitergeht.

   Ich habe mich in der SVN-Version von Code::Blocks umgesehen und
   kann dzt. folgende Lösungen anbieten:
     a) Bei Remote-Sitzungen wird immer continue gesendet
     b) Weiss zu wenig über Wxsmith, WxWidgets um das Problem
        grundsätzlich lösen zu können, kann aber einen praktikablen
        Workaround anbieten:
        Der Debuggerprozess erstellt ein (leeres) Konsolenfenster. In
        diesem kann man dann bei Bedarf das rettende Ctrl-C eintippen
        und landet dann mit gestopptem Target wieder in der IDE.

   Ich stelle meinen modifizierten Code::Blocks zum Download bereit.
   Zusätzlich zu o.a. Änderungen ist Patch #2458 eingearbeitet. Es
   sind nur die gezippten Files, falls das nicht laufen sollte, dann
   zuerst CB 8.02 installieren.
   http://members.aon.at/gpra/CodeBlocks.zip
   Ich hoffe aber doch, dass die CB-Entwickler nicht locker lassen und
   ihre Ankündigungen bzgl. Embedded Entwicklung bald wahr machen!

Erstellt am 16. 9. 2008
G.P.G

von Werner B. (werner-b)


Lesenswert?

> ... was bei den zur Verfügung stehenden 16K ...

Soweit ich mich erinnere hat das SO-DIMM Board von EA einige Megabyte 
Pseudo-SRAM auf dem Board. Die muss man nur aktivieren.

von Daniel B. (Gast)


Lesenswert?

Hi Gottfried,

vielen Dank für diesen Post.
Ich versuche derzeit die YAGARTO GNU ARM toolchain, CodeBlocks v8.02 und 
den AT91SAM7X256 (OLIMEX SAM7-EX256 + ARM-USB-TINY) unter einen Hut zu 
bringen. Allerdings bin ich bisher gescheitert.

Ich habe ein "Empty Project" als Ausgangspunkt gewählt und unter 
"Project build options" die Compilereinstellungen konfiguriert (einige 
Checkboxen + "Other options" -mcpu=arm7tdmi -T sram.lds). In den 
"Project/targets options" habe ich zudem die Checkbox "Auto-generate 
filename extension" deaktiviert und den "Output filename" auf *.elf 
gesetzt. Ergebnis ist zwar ein *.elf-File, aber das scheint nicht zu 
funktionieren.

Kannst du eine Beschreibung geben, wie du vorgegangen bist bzw. was du 
alles wo eingestellt hast?

Vielen Dank
Daniel

von Daniel B. (Gast)


Lesenswert?

Hallo nochmal,

hab's hin bekommen. Wenn mann die Linker-Option "-T sram.lds" als 
Compiler-Option angibt geht's halt nicht.
Jetzt stehe ich vor dem Debugging-Problem, das du oben beschrieben hast. 
Werde mich da jetzt reinarbeiten und ggf. nochmal melden.

Daniel

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.