www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Einsteigerfrage zu Cortex M0 mit LPCXpresso


Important announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
Autor: H. G. (ledi)
Datum:
Angehängte Dateien:
  • preview image for 1.PNG
    1.PNG
    14,4 KB, 196 Downloads

Diesen Beitrag bewerten:
lesenswert
nicht lesenswert
Hallo,

ich bin gerade dabei, auf ARM Cortex M0 Controller (als Ersatz für die 
8-Bitter) umzusteigen und habe eine Frage zu CMSIS und Cortex M0.
Ich verwende das Entwicklerboard LPC1114 mit LPCXpresso und stelle mir 
die Frage:

Woher weiß ich, welche Headerdateien ich z.B. für die I/O-Ports 
einbinden muss usw. (Ich konnte hier keine "Anleitung" bei NXP oder ARM 
finden)

Ich habe in mein Projekt von NXP die CMSIS-Dateien importiert (siehe 
Bild) und mein mainfile wie folgt erstellt:
#ifdef __USE_CMSIS
#include "LPC11xx.h"
#endif

#include <cr_section_macros.h>
#include <NXP/crp.h>

__CRP const unsigned int CRP_WORD = CRP_NO_CRP ;  //Enable Code Read Protect"

// TODO: insert other include files here

// TODO: insert other definitions and declarations here

int main(void)
{
  // Die Std. Peripherie nun Clocks, PLLs usw. einrichten
  SystemInit();
  //GPIOInit();

  while(1)
  {

  }
  return 0 ;
}

Jetzt möchte ich irgendwie die Ports ansprechen um z.B. eine LED blinken 
zu lassen. Welches Headerfile muss ich einbinden?

Autor: G. G. (g_g)
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht lesenswert
Hallo,

schau dir mal die Seite an, hier findest du einen Einstieg:

LPC1100 Series

http://ics.nxp.com/support/lpcxpresso/




Gruß G.G.

Autor: H. G. (ledi)
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht lesenswert
G. G. schrieb:
> Hallo,
>
> schau dir mal die Seite an, hier findest du einen Einstieg:
>
> LPC1100 Series
>
> http://ics.nxp.com/support/lpcxpresso/
>
Da war ich schon. Konnte aber nichts finden, dass mir hier weiterhilft.
Wie ich ein Projekt erstelle oder einbinde, das weiß ich. Wie im obigen 
Beispiel möchte ich auf die I/O-Ports zugreifen.

Wenn ich z.B. die Funktion

GPIOInit();

aufrufe, erhalte ich beim build die Fehlermeldung

undefined reference to `GPIOInit'

Welche Headerdatei muss ich hier einbinden?

Autor: G. G. (g_g)
Datum:
Angehängte Dateien:

Diesen Beitrag bewerten:
lesenswert
nicht lesenswert
H. G. schrieb:

> Wenn ich z.B. die Funktion
> GPIOInit();

> Welche Headerdatei muss ich hier einbinden?

#include "LPC11xx.h"
#include "LPC11xx_GPIO.h"

Wenn alles ordentlich installiert wurde, findet deine Software die 
"LPC11xx.h" usw.. Hier wiederum stehen alle alle weiteren Informationen, 
wo z.B. GPIOInit() definiert ist (Include.. und Haeder... )

Einfacher wäre es sicher, wenn deine Software selbstständig ein Projekt 
eröffnen könnte. Da sind dann die Objekt-Path vorgegeben. (CooCox CoIDE)
Siehe Anlage

CooCox CoIDE is a free software product.

Visit: http://www.coocox.org/CooCox_CoIDE.htm

MfG. G.G.

Autor: Roland H. (batchman)
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht lesenswert
Man muss nicht unbedingt die Funktionen verwenden, man kann auch 
klassisch "Register direkt" verwenden. Dafür sollte #include "LPC11xx.h" 
ausreichen.

Im Falle von GPIO kann "Register direkt" sogar obligatorisch sein, wenn 
die entsprechenden GPIO-Funktionen nicht als "static inline" ausgelegt 
sind - sie sind dann je nach Anwendungsfall u. U. schlicht zu langsam.

Beispiel:
void GPIO_SetValue(uint8_t portNum, uint32_t bitValue)

{

  LPC_GPIO_TypeDef *pGPIO = GPIO_GetPointer(portNum);



  if (pGPIO != NULL)

  {

    pGPIO->SET = bitValue;

  }

}

Der Funktionsaufruf frisst Zeit, "Pointer holen" kommt dazu, dann kommt 
die Indirektion.

D. h. folgendes hat das gleiche Resultat:
GPIO_SetValue(0, 1);

LPC_GPIOA->SET = 1;

aber die zweite Variante ist der Turbo.

Die Entscheidung "Peripherals library" oder "Register direkt" würde ich 
mir drei Mal überlegen.

Bei den stm32 setze ich die "standard peripherals library" ein, und es 
gibt m. E. drei große Probleme: Die semantische Lücke zwischen 
Datenblatt und der Library, die fehlende Abstraktion (die Funktionen 
sind oft nicht genug "high level") und schließlich ist das Zeugs nicht 
portabel zwischen stm32f1 und stm32f4. Muss nicht zwangsläufig für LPC 
gelten.

Es ist natürlich verlockend, z. B. im Falle von CAN/UART auf bestehende 
Funktionen aufsetzen zu können, die die Baud rate settings korrekt 
machen.

Die Kehrseite ist dann, dass z. B. im Falle des LPC177x_8xCMSIS_110506 
z. B. uint64_t Operationen für UART-Einstellungen eingebunden werden 
(muss für den CM0 nicht gelten). Generellt gilt, dass Code-Größe und 
RAM-Bedarf ansteigen.

Autor: W.S. (Gast)
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht lesenswert
Roland H. schrieb:
> Die Entscheidung "Peripherals library" oder "Register direkt" würde ich
> mir drei Mal überlegen.

JA, das sollte man dreimal ganz dick unterstreichen!
Und nochwas, so ein Grundgerüst gefällt mir überhaupt nicht:

int main(void)
{ // Die Std. Peripherie nun Clocks, PLLs usw. einrichten
  SystemInit();
  //GPIOInit();
  while(1)
  {
  }
  return 0 ;
}

weil man eben nicht genau weiß, was da alles in SystemInit angelassen 
wird.
Ich rate eher dazu, all diese tollen für ein bestimmtes Board 
geschriebenen XYZ_Init Routinen wegzulassen und sich sein System selbst 
aufzusetzen. Dazu kann auch gehören, daß man sich seine eigene 
CPU-Headerdatei zusammenstellt, um unnötigen Ballast erst gar nicht in 
das Projekt kommen zu lassen.

W.S.

Autor: H. G. (ledi)
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht lesenswert
Ok, das leuchtet ein.

Aber wo finde ich die Funktionen und deren Parameter?

Nach

GPIO_SetValue();

habe ich z.B. in der Headerdatei, im Datenblatt und im user manual 
vergebens gesucht.

Also ich bräuchte eine Art Start-up-Lektüre (am Besten mit Beispielen) 
damit ich einmal die Funktionen kennenlerne und weiß, was ich wo 
einbinden muss.
Hast du da für mich eine Empfehlung?

Autor: Jürgen Liegner (jliegner)
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht lesenswert
Genau das ist der Punkt bei diesen Libs. Es scheint nirgends einen Bezug 
zum Usermanual des mc's zu geben. Eine vernünftige Doku zu den Libs gibt 
es aber nicht. Und wenn man die Funktionen der Lib aus den Headern und 
dem Code rausklaubt, hat man den mc immer noch nicht verstanden. Also 
lies das Manual des mc und setze die Register. Sowas wie:
LPC_GPIO0->DIR  |=  (1<<PinNummer);
LPC_GPIO0->DATA |=  (1<<PinNummer);
LPC_GPIO0->DATA &= ~(1<<PinNummer);

ist auch nicht schwieriger als ein GPIOSetDir und GPIOSetValue.

Besonders schön ist für den LPC11xx auch die Funktion:
void GPIOSetInterrupt( uint32_t portNum, uint32_t bitPosi, uint32_t sense,
      uint32_t single, uint32_t event )
{
  switch ( portNum )
  {
  case PORT0:
    if ( sense == 0 )
    {
    LPC_GPIO0->IS &= ~(0x1<<bitPosi);
    /* single or double only applies when sense is 0(edge trigger). */
    if ( single == 0 )
      LPC_GPIO0->IBE &= ~(0x1<<bitPosi);
    else
      LPC_GPIO0->IBE |= (0x1<<bitPosi);
    }
    else
      LPC_GPIO0->IS |= (0x1<<bitPosi);
    if ( event == 0 )
    LPC_GPIO0->IEV &= ~(0x1<<bitPosi);
    else
    LPC_GPIO0->IEV |= (0x1<<bitPosi);
  break;
   case PORT1:
    if ( sense == 0 )
    {
    LPC_GPIO1->IS &= ~(0x1<<bitPosi);
    /* single or double only applies when sense is 0(edge trigger). */
    if ( single == 0 )
      LPC_GPIO1->IBE &= ~(0x1<<bitPosi);
    else
      LPC_GPIO1->IBE |= (0x1<<bitPosi);
    }
    else
      LPC_GPIO1->IS |= (0x1<<bitPosi);
    if ( event == 0 )
    LPC_GPIO1->IEV &= ~(0x1<<bitPosi);
    else
    LPC_GPIO1->IEV |= (0x1<<bitPosi);  
  break;
  case PORT2:
    if ( sense == 0 )
    {
    LPC_GPIO2->IS &= ~(0x1<<bitPosi);
    /* single or double only applies when sense is 0(edge trigger). */
    if ( single == 0 )
      LPC_GPIO2->IBE &= ~(0x1<<bitPosi);
    else
      LPC_GPIO2->IBE |= (0x1<<bitPosi);
    }
    else
      LPC_GPIO2->IS |= (0x1<<bitPosi);
    if ( event == 0 )
    LPC_GPIO2->IEV &= ~(0x1<<bitPosi);
    else
    LPC_GPIO2->IEV |= (0x1<<bitPosi);  
  break;
  case PORT3:
    if ( sense == 0 )
    {
    LPC_GPIO3->IS &= ~(0x1<<bitPosi);
    /* single or double only applies when sense is 0(edge trigger). */
    if ( single == 0 )
      LPC_GPIO3->IBE &= ~(0x1<<bitPosi);
    else
      LPC_GPIO3->IBE |= (0x1<<bitPosi);
    }
    else
      LPC_GPIO3->IS |= (0x1<<bitPosi);
    if ( event == 0 )
    LPC_GPIO3->IEV &= ~(0x1<<bitPosi);
    else
    LPC_GPIO3->IEV |= (0x1<<bitPosi);    
  break;
  default:
    break;
  }
  return;
}

Der ganze Code muss dazugelinkt werden nur um eine einzelne Zeile 
Register setzen durch eine Funktion zu ersetzen. Was sense, single und 
event bedeuten, kann man auch nicht erahnen ohne das Usermanual gelesen 
zu haben.
Soviel kann man gar nicht brechen.

Mir kommt aber ein ganz anderer Verdacht auf, eventuell sind auch die 
Hersteller der tollen IDEs nicht unbeteiligt. So kriegt man schnell den 
Flash voll und grenzt die (codegrößenbeschränkten) Freeware-Versionen 
aus.
Das trifft hier zwar für CodeRed und die LPC11xx nicht zu da die nur 32k 
haben, aber große Programme brauchen auch länger um in den Flash geladen 
zu werden. Und Warten nervt.

Einen Vorteil haben die Libs aber. Es gibt sie. Und damit genügend 
Beispielcode wenn man mal Verständnisprobleme mit dem Usermanual hat.


@ Roland H.

Das gibt es bei LPC11xx nicht:
LPC_GPIOA->SET = 1

Die LPC11xx haben die Besonderheit mit dem MASKED_ACCESS 
Speicherbereich, den ich sonst noch nicht gesehen haben.

Setzen eines Pins z.B.
//  Pin als Ausgang konfigurieren
LPC_GPIO0->DIR  |=  (1<<PinNummer);

// Pin auf 1 setzen 
LPC_GPIO0->MASKED_ACCESS[1<<PinNummer]=1;

// Pin auf 0 setzen 
LPC_GPIO0->MASKED_ACCESS[1<<PinNummer]=0;

Autor: H. G. (ledi)
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht lesenswert
Ok, hab das mal mit einem Beispiel versucht und mittels Debugger 
durchgesteppt.

Die LED (am Port0 Pin7) blinkt aber nicht! Was habe ich vergessen oder 
übersehen?
#ifdef __USE_CMSIS
#include "LPC11xx.h"
#endif

#include <cr_section_macros.h>
#include <NXP/crp.h>

__CRP const unsigned int CRP_WORD = CRP_NO_CRP ;

#define PinNummer 7

int main(void)
{
  SystemInit();

  //  Pin als Ausgang konfigurieren
  LPC_GPIO0->DIR  |=  (1<<PinNummer);

  while(1)
  {
    // Pin auf 1 setzen
    LPC_GPIO0->MASKED_ACCESS[1<<PinNummer]=1;

    // Pin auf 0 setzen
    LPC_GPIO0->MASKED_ACCESS[1<<PinNummer]=0;
  }
  return 0 ;
}

Autor: Children (Gast)
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht lesenswert
So schnell ist dein Auge nicht, das du etwas blinken sehen würdest.

Mach mal soetwas wie delay zwischen die Toggelei.

Autor: H. G. (ledi)
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht lesenswert
Children schrieb:
> So schnell ist dein Auge nicht, das du etwas blinken sehen würdest.
>
> Mach mal soetwas wie delay zwischen die Toggelei.

Nein, ich habe den Debugger händisch bedient!
Also Zeile für Zeile (mit F5) ausführen lassen.

Autor: Ralf (Gast)
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht lesenswert
> Die LED (am Port0 Pin7)...
Wie zählst du den Pin? Heisst der tatsächlich Pin7?
Wie ist die LED angeschlossen -> High- oder Low-aktiv?

Ralf

Autor: H. G. (ledi)
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht lesenswert
@ Ralf

Pin von 0,1,2,3,4,5,6,7 = PIO0_7
LED ist active high

Autor: Albert ... (albert-k)
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht lesenswert
Du hast vergessen den Clock für die GPIO's zu aktivieren. Weiss das 
genaue Register dazu nicht aus dem kopf, schau am besten im Manual nach.

Autor: Jürgen Liegner (jliegner)
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht lesenswert
das entsprechende Bit steht nach dem Reset immer auf 1 laut Manual.
Trotzdem zur Sicherheit:
LPC_SYSCON->SYSAHBCLKCTRL |= (1<<6);

hier war noch ein Fehler:
// Set
LPC_GPIO0->MASKED_ACCESS[(1<<PinNummer)] = (1<<PinNummer);


/ Clr
LPC_GPIO0->MASKED_ACCESS[(1<<PinNummer)] = (0<<PinNummer);

War und ist auch ungetestet aus dem Kopf....

Autor: H. G. (ledi)
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht lesenswert
Albert ... schrieb:
> Du hast vergessen den Clock für die GPIO's zu aktivieren. Weiss das
> genaue Register dazu nicht aus dem kopf, schau am besten im Manual nach.

Hab ich nun versucht mit:
LPC_SYSCON.SYSAHBCLKCTRL |= 0x8000;

Da erhalte ich aber die Fehlermeldung:
../src/main.c:26:12: error: request for member 'SYSAHBCLKCTRL' in 
something not a structure or union

Hat jemand ein konkretes Beispiel, wie man den Clock für die GPIO´s 
setzt?

Autor: H. G. (ledi)
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht lesenswert
Ah, ja Pointer auf Struktur!
Danke!

Autor: H. G. (ledi)
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht lesenswert
Es funktioniert!!!

Hier der Code:
#ifdef __USE_CMSIS
#include "LPC11xx.h"
#endif

#include <cr_section_macros.h>
#include <NXP/crp.h>

__CRP const unsigned int CRP_WORD = CRP_NO_CRP ;

#define PinNummer 7

int main(void)
{
  SystemInit();

  LPC_SYSCON->SYSAHBCLKCTRL |= (1<<6);

  //  Pin als Ausgang konfigurieren
  LPC_GPIO0->DIR  |=  (1<<PinNummer);

  int i,j;
  while(1)
  {
    // Pin auf 1 setzen
    LPC_GPIO0->MASKED_ACCESS[1<<PinNummer]= (1 << 7);
    for (i=0; i<=1000; i++)
    {
      for (j=0; j<=1000; j++)
      {
      }
    }
    // Pin auf 0 setzen
    LPC_GPIO0->MASKED_ACCESS[1<<PinNummer]= (0 << 7);
    for (i=0; i<=1000; i++)
    {
      for (j=0; j<=1000; j++)
      {
      }
    }
  }
  return 0 ;
}

Autor: H. G. (ledi)
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht lesenswert
Jürgen Liegner schrieb:
> das entsprechende Bit steht nach dem Reset immer auf 1 laut Manual.
> Trotzdem zur Sicherheit:
>
>
> LPC_SYSCON->SYSAHBCLKCTRL |= (1<<6);
> 

Warum muss ich eigentlich das Register SYSAHBCLKCTRL über eine Struktur 
ansprechen?

Kann ich die Bits nicht irgendwie auch direkt setzen

z.B. SYSAHBCLKCTRL |= (1<<6);

Autor: Lutz (Gast)
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht lesenswert
H. G. schrieb:
> Warum muss ich eigentlich das Register SYSAHBCLKCTRL über eine Struktur
> ansprechen?

Weil's im Header in Zeile 147 so definiert ist?

Wenn du dem compiler bzw. linker die Adresse des Registers anders 
"beibringst", kannst du das natürlich auch auf deine gewünschte Art 
schreiben. Ist in der LPC11xx.h aber nun mal so definiert.

Warum hast du eigentlich so eine verschachtelte Schleife für das delay 
gewählt? Der LPC11xx hat 32 bit; die kannst du ruhig voll ausnutzen. Ist 
ja einer der Vorteile.

Autor: Jürgen Liegner (jliegner)
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht lesenswert
falls du man sowas wie das bekannt Delayus suchst:
// Microsecond delay loop-
void DelayuS(uint32_t uS)
{
  uint32_t CyclestoLoops;

  CyclestoLoops = SystemCoreClock;
  if (CyclestoLoops >= 2000000) 
    {
    CyclestoLoops /= 1000000;
    CyclestoLoops *= uS;
    } 
  else
    {
    CyclestoLoops *= uS;
    CyclestoLoops /= 1000000;
    }

  if  (CyclestoLoops <= 100)
    return;
  
  CyclestoLoops -= 100; // cycle count for entry/exit 100? should be measured
  CyclestoLoops /= 4; // cycle count per iteration- should be 4 on Cortex M0/M3

  if (!CyclestoLoops)
    return;

  // Delay loop for Cortex M3 thumb2
  asm volatile 
    (
    // Load loop count to register
    " mov r3, %[loops]\n"
    // loop start- subtract 1 from r3
    "loop: sub r3, #1\n"
   // " nop \n"
    // test for zero, loop if not
    " bne loop\n\n"

    : // No output registers
    : [loops] "r" (CyclestoLoops) // Input registers
    : "r3" // clobbered registers
    );
}

Das geht bei meinem lpc11c24 ziemlich genau. Natürlich nur wenn keine 
langen Interrupts dazwischen kommen. Und die SystemCoreClock Variable 
muss auch richtig stehen. Die wird aber von der cr_startup_lpc11.c vor 
der main() schon richtig gesetzt und steht bei mir auf 48000000. Durch 
die assembler-Befehle kann auch die Compileroptimierung nicht dazwischen 
funken. Ich möchte noch betonen, dass diese Funktion nicht von mir 
stammt, sondern mal aus einem der vielen Codeschnipsel im Web. Leider 
weiss ich aber nicht mehr woher das kam.
In realen Anwendeungen sollte sowas sowieso nur sehr begrenzt vorkommen, 
da wartet man besser mit dem SysTick oder einen anderen Timer anstelle 
die Rechenzeit zu verbraten.

Autor: Bär_Tram (Gast)
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht lesenswert
Jürgen Liegner schrieb:
> Sowas wie:
> LPC_GPIO0->DIR  |=  (1<<PinNummer);
> LPC_GPIO0->DATA |=  (1<<PinNummer);
> LPC_GPIO0->DATA &= ~(1<<PinNummer);
>
> ist auch nicht schwieriger als ein GPIOSetDir und GPIOSetValue.

Roland H. schrieb:
> Beispiel:
> void GPIO_SetValue(uint8_t portNum, uint32_t bitValue)
>
> {
>
>   LPC_GPIO_TypeDef *pGPIO = GPIO_GetPointer(portNum);
>
>
>
>   if (pGPIO != NULL)
>
>   {
>
>     pGPIO->SET = bitValue;
>
>   }
>
> }
>
> Der Funktionsaufruf frisst Zeit, "Pointer holen" kommt dazu, dann kommt
> die Indirektion.
>
> D. h. folgendes hat das gleiche Resultat:
> GPIO_SetValue(0, 1);
>
> LPC_GPIOA->SET = 1;
>
> aber die zweite Variante ist der Turbo.
>
> Die Entscheidung "Peripherals library" oder "Register direkt" würde ich
> mir drei Mal überlegen.

Man muß dabei aber auch erwähnen, daß es mit den Libs viel 
universeller und auch gerade für Einsteiger einfacher ist. Mit der Lib 
hat man immer nur eine Funktion, in der man die Parameter setzen muß.
Wie würdest du es denn machen, wenn du z.B. einen DS18B20 angeschlossen 
hast? Zum Ansprechen von DQ müßtest du an jeder Stelle des 
Sensor-Codes sowas wie
LPC_GPIOx->FIODIR |= (1<<y);
schreiben, wobei x und y in jedem Projekt anders sind. Das gleiche für 
das Setzen und Löschen. Man könnte auch defines in der zugehörigen 
headerdatei machen wie
#define DQ_SET_DIR LPC_GPIO2->FIODIR|=(1<<7)
und diese im c.file einfach einsetzen.Es ist halt ein Kompromiss. 
Ansonsten stimmt alles genannte. Aber man kann auch bedenken, daß bei 
den 32-bittern üblicherweise Speicher- und Laufzeitreserven da sind, die 
das dann egalisieren.

Autor: Roland H. (batchman)
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht lesenswert
Bär_Tram schrieb:
> Man muß dabei aber auch erwähnen, daß es mit den Libs viel
> universeller und auch gerade für Einsteiger einfacher ist.

In welchem Sinne "universell"? Portabel auf einen anderen ARM des 
gleichen Herstellers? Mit viel Glück passt die Library noch für die 
Nachfolgegeneration (die nächste CPU-Linie).

Bei STM32 geht das übrigens nicht - die Library zwischen stm32f1 und 
stm32f4 ist anders.

Ich bezweifle, dass es einfacher ist. Da gehen die Meinungen allerdings 
auseinander. Deshalb hatte ich geschrieben, dass man es sich überlegen 
sollte.

Bär_Tram schrieb:
> Mit der Lib
> hat man immer nur eine Funktion, in der man die Parameter setzen muß.

Mag sein, dass ich STM32 library geschädigt bin. In jedem Fall bekommst 
Du dort mit einer Library-Funktion z. B. keine PWM hin. Da hilft die 
Library gar nicht. Auf allen anderen Plattformen habe ich es dann von 
Anfang an gar nicht mehr gemacht.

> Wie würdest du es denn machen, wenn du z.B. einen DS18B20 angeschlossen
> hast? Zum Ansprechen von DQ müßtest du an jeder Stelle des
> Sensor-Codes sowas wie
> LPC_GPIOx->FIODIR |= (1<<y);
> schreiben, wobei x und y in jedem Projekt anders sind. Das gleiche für
> das Setzen und Löschen. Man könnte auch defines in der zugehörigen
> headerdatei machen wie
> #define DQ_SET_DIR LPC_GPIO2->FIODIR|=(1<<7)
> und diese im c.file einfach einsetzen.

Ja, so ähnlich. Um den Begriff "universell" aufzugreifen ;-)

Zunächst definiere ich den GPIO-Pin in einer config.hpp mittels #defines 
(port + pin - bei Dir das x und das y). Dann habe ich GPIO-Makros, 
welche in der Logik-Schicht verwendet werden, und je für AVR/diverse 
ARMs/MSP430/Renesas RX/PIC32 den optimalen GPIO-Aufruf einsetzen. Das 
ist portabel, schont den Flash/Stack und ist am schnellsten. 
Diesbezüglich keine Kompromisse - der liegt darin, diesen Umweg 
vorgesehen zu haben. Ausserdem giesst der Präprozessor die Konfiguration 
so fest in den Code, dass der Pin zur Laufzeit nicht geändert werden 
kann.

Z. B. beim lpc1769 ungefähr so (alles etwas vereinfacht - hier wird das 
bit-banding ignoriert):
#define GPIO_MODE_OUT(port, pin) \
  CONCAT2(LPC_GPIO, port)->FIODIR |= (1 << pin)

und beispielsweise beim atxmega256a3
#define GPIO_MODE_OUT(port, pin) \
  CONCAT2(PORT, port.DIRSET) = (1 << pin)

In diesem Fall also ohne "read-modify-write".

Immer wenn eine neue CPU auf dem Tisch landet, dann wird die GPIO-API 
einmalig und zentral ergänzt. Die eigentlichen Programme bleiben 
unberührt.

Selbst wenn es die erste und auf längere Sicht die einzige Plattform 
ist, würde ich immer einen Mini-HAL-Layer einbauen, und sei es nur um 
dort die Möglichkeit zu haben, Ergänzungen/Verbesserungen/zusätzliche 
Einstellungen zentral vornehmen zu können.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel




Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder GIF-Format hochladen.
Siehe Bildformate
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken erkennst du die Nutzungsbedingungen an.

webmaster@mikrocontroller.netImpressumNutzungsbedingungenWerbung auf Mikrocontroller.net