Forum: Mikrocontroller und Digitale Elektronik Inputpins an AT91SAM9G20 (war: "Embedded PC")


von t0mM3k (Gast)


Lesenswert?

Hallo zusammen,
ich stehe vor einem Problem bei dem ich nicht weiterkomme (hab mich vllt 
ein bisschen übernommen) und frage nun daher euch um Hilfe.

Ich arbeite derzeit in meinem Projekt mit einem Embedded PC.
Zu diesem gab es auch ein paar Beispielprogramme auf CD dazu.

Eines dieser Programme habe ich etwas angepasst, sodass ich jetzt einen 
beliebigen Pin (einer nach außen geführten seriellen Schnittstelle) auf 
1 oder 0 setzen kann. So weit so gut.
Allerdings würde ich jetzt gerne auch auf Inputs reagieren können.
Also angenommen ich lege an Pin 2 ein HIGH an, sollte ein Interrupt 
ausgelöst werden und mir der PC auf der Konsole ausgeben: PIN2 = HIGH

Habe bisher nur ganz kleine C-Programme für ATmega8 etc. geschrieben 
(z.B. Servosteuerungen).
Darum bin ich jetzt hiermit anscheinend ein bisschen überfordert.

Hier einfach mal der Code zum steuern der Outputpins:
1
#include <stdio.h>   
2
#include <string.h>  
3
#include <unistd.h>  
4
#include <fcntl.h>   
5
#include <errno.h>   
6
#include <termios.h>
7
#include <sys/types.h>
8
#include <sys/select.h>
9
#include <sys/mman.h>
10
11
#define MAP_SIZE 4096UL
12
#define MAP_MASK (MAP_SIZE -1)
13
#define PIOB_BASE 0xfffff600UL
14
15
//Output-Pins
16
#define PIO_B22 ((unsigned long) 1 << 22)  
17
#define PIO_B25  ((unsigned long) 1 << 25) 
18
#define PIO_B05 ((unsigned long) 1 << 5)   
19
#define PIO_B04  ((unsigned long) 1 << 4)   
20
#define PIO_B24 ((unsigned long) 1 << 24)  
21
#define PIO_B26  ((unsigned long) 1 << 26)  
22
#define PIO_B27 ((unsigned long) 1 << 27)  
23
#define PIO_B23  ((unsigned long) 1 << 23)  
24
25
//configure Register
26
#define PIOB_PER PIOB_BASE + 0x00  
27
#define PIOB_PDR PIOB_BASE + 0x04  
28
#define PIOB_OER PIOB_BASE + 0x10  
29
#define PIOB_ODR PIOB_BASE + 0x14  
30
#define PIOB_OSR PIOB_BASE + 0x18  
31
#define PIOB_SODR PIOB_BASE + 0x30 
32
#define PIOB_CODR PIOB_BASE + 0x34 
33
#define PIOB_ODSR PIOB_BASE + 0x38 
34
#define PIOB_PDSR PIOB_BASE + 0x3C 
35
#define PIOB_IFER PIOB_BASE + 0x20 
36
#define PIOB_IFDR PIOB_BASE + 0x24 
37
//Configure macros
38
#define PIOB_Enable_Register(addr, pio) *((unsigned long *) (addr + (PIOB_PER & MAP_MASK))) = pio
39
#define PIOB_Disable_Register(addr, pio) *((unsigned long *) (addr + (PIOB_PDR & MAP_MASK))) = pio
40
#define PIOB_Enable_Output(addr, pio) *((unsigned long *) (addr + (PIOB_OER & MAP_MASK))) = pio
41
#define PIOB_Disable_Output(addr, pio) *((unsigned long *) (addr + (PIOB_ODR & MAP_MASK))) = pio
42
#define PIOB_Enable_Inputfilter(addr, pio) *((unsigned long *) (addr + (PIOB_IFER & MAP_MASK))) = pio
43
#define PIOB_Enable_Input(addr, pio) \
44
             (*((unsigned long *) (addr + (PIOB_ODR & MAP_MASK))) = pio) && \
45
             (*((unsigned long *) (addr + (PIOB_IFER & MAP_MASK))) = pio) && \
46
             (*((unsigned long *) (addr + (PIOB_CODR & MAP_MASK))) = pio)
47
48
#define PIOB_Set_Low(addr, pio) *((unsigned long *) (addr + (PIOB_CODR & MAP_MASK))) = pio
49
#define PIOB_Set_High(addr, pio) *((unsigned long *) (addr + (PIOB_SODR & MAP_MASK))) = pio
50
51
short lvl;
52
unsigned long pin;
53
54
void printError(){
55
   printf("\n\n!!!Error!!!\nSyntax is: setPin <Pin> 1|0 \nExample:\n################\n# setPin RTS 1 #\n################\nPossible Pins are:\nDSR\nRI\nRXD\nTXD\nDTR\nRTS\nCTS\nDCD\n\n\n");
56
   exit(1);
57
}
58
59
int main (int count, char *argv[]){
60
       if(count!=3){
61
     printError();
62
       }else{
63
    if(*argv[2]=='1'){
64
       lvl=1;
65
    }else if(*argv[2]=='0'){
66
       lvl=0;
67
    }else{
68
       printError();
69
    }
70
       }
71
     int fd;
72
     void *map_base;
73
     if ((fd = open("/dev/mem", O_RDWR | O_SYNC)) == -1)
74
     {
75
    printf("Fehler beim Zugriff auf /dev/mem");
76
          exit(1); //Fehler beim Zugriff auf dev-mem
77
     }
78
     map_base = mmap(0, MAP_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, PIOB_BASE & ~MAP_MASK);
79
     if (map_base == (void *) -1)
80
     {
81
    printf("Fehler beim Zugriff auf mmap");
82
          exit(1); //Zugriffsfehler
83
     }
84
     PIOB_Enable_Register(map_base, PIO_B22 | PIO_B25 | PIO_B05 | PIO_B04 | PIO_B24 | PIO_B26 | PIO_B27 | PIO_B23);
85
     PIOB_Enable_Output(map_base, PIO_B22 | PIO_B25 | PIO_B05 | PIO_B04 | PIO_B24 | PIO_B26 | PIO_B27 | PIO_B23);
86
     
87
     char *name=argv[1];
88
     if(strcmp(name,"DSR")==0){
89
  pin=PIO_B22;
90
     }else if(strcmp(name,"RI")==0){
91
  pin=PIO_B25;
92
     }else if(strcmp(name,"RXD")==0){
93
  pin=PIO_B05;
94
     }else if(strcmp(name,"TXD")==0){
95
  pin=PIO_B04;
96
     }else if(strcmp(name,"DTR")==0){
97
  pin=PIO_B24;
98
     }else if(strcmp(name,"RTS")==0){
99
  pin=PIO_B26;
100
     }else if(strcmp(name,"CTS")==0){
101
  pin=PIO_B27;
102
     }else if(strcmp(name,"DCD")==0){
103
  pin=PIO_B23;
104
     }
105
106
     switch(lvl){
107
        case 0: PIOB_Set_Low(map_base, pin); printf("Pin %s wurde in IF0 auf 0 gesetzt.\n",name); break;
108
  case 1: PIOB_Set_High(map_base, pin);printf("Pin %s wurde in IF0 auf 1 gesetzt.\n",name); break;
109
     }
110
111
     if (munmap(map_base, MAP_SIZE) == -1) exit(1);
112
     close(fd);
113
}

Stehe grade total auf dem Schlauch, wie ich jetzt die Pins auch auslesen 
kann und mit einem Interrupt überwachen kann.

Danke schonmal für jeden hilfreichen Hinweis.

mfg t0mM3k


[Edit]
Titel geändert, da es sich nicht um einen "embedded PC" handelt.
-rufus
von Oliver (Gast)


Lesenswert?

t0mM3k schrieb:
> Stehe grade total auf dem Schlauch, wie ich jetzt die Pins auch auslesen

RTFM

Wer soll denn hier wissen, welches System du nutzt, und wie das 
programmiert wird?

Oliver
von Dennis H. (c-logic) Benutzerseite


Lesenswert?

AT91 scheinbar von Atmel.

Für Input z.b. über Interrupt bietet sich ja der PinInterrupt an.

Notwendige Register sind  PIO_IER PIO_IDR PIO_IMR und PIO_ISR für die 
Maske

Der Interrupt-Controller (AIC) muß noch passend dazu programmiert 
werden.
Speziel welches Gerät auslöst und welche Adresse angesprungen werden 
soll.

Der Interrupt sollte dann bei jedem Pinchange ausgelöst werden, je 
nachdem welche PIN's mit PIO_IER maskiert werden.
Über PIO_ISR kann man dann in der Interrupt-Service-Routine selbst 
rausfinden, welcher Pin es war.

Sehr hilfreich ist ja aber definitiv welcher AT91 das nun ist.
von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Dennis Heynlein schrieb:
> AT91 scheinbar von Atmel.

Das korreliert nicht mit

> Ich arbeite derzeit in meinem Projekt mit einem Embedded PC.

(Hervorhebung von mir)
von t0mM3k (Gast)


Lesenswert?

danke erstmal für die schnellen antworten.
Also genau genommen ist es ein Singleboard-Computer von der Firma 
taskit:
http://www.taskit.de/produkte/portuxg20/index.htm

Warum trifft dann die Aussage nicht zu dass es ein EmbeddedPC ist?!
War die Aussage falsch?! (Wenn ja, dann Entschuldige ich mich hiermit 
dafür)

Also ja, es handelt sich um einen AT91SAM9G20 von Atmel
von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

t0mM3k schrieb:
> Warum trifft dann die Aussage nicht zu dass es ein EmbeddedPC ist?!

Das ist kein "Embedded PC". Ein "Embedded PC" enthält nicht nur im Namen 
einen "PC" -- und ist also ein x86-System.

Damit hat sich der Aufenthalt dieses Threads in "PC-Programmierung" 
erledigt.
von t0mM3k (Gast)


Lesenswert?

Rufus Τ. Firefly schrieb:
> Damit hat sich der Aufenthalt dieses Threads in "PC-Programmierung"
> erledigt.

Darum hatte ich den Thread auch ursprünglich im Subforum GCC gestartet, 
da ich ja immerhin Probleme bei der Programmierung habe.

Dennoch möchte ich mich für den irreführenden Titel entschuldigen.
von t0mM3k (Gast)


Lesenswert?

Dennis Heynlein schrieb:
> Notwendige Register sind  PIO_IER PIO_IDR PIO_IMR und PIO_ISR für die
> Maske

Die benötigten Register habe ich bereits dem Datenblatt entnommen (Danke 
für die Bestätigung dass ich da richtig lag :) )


Dennis Heynlein schrieb:
> Der Interrupt-Controller (AIC) muß noch passend dazu programmiert
> werden.
> Speziel welches Gerät auslöst und welche Adresse angesprungen werden
> soll.

Und genau DA liegt der Hase im Pfeffer.
Ich habe mehrere nach außen geführte Pins vom PIO Controller die ich 
überwachen möchte. Die Absicht war erstmal eine simple Interruptroutine 
zu schreiben, die einem nur auf Console ausgibt: "Pin 1 wurde auf HIGH 
gesetzt".
Ich habe aber leider keinen Schimmer, wie ich a) den AIC passend dazu 
programmiere und b) die Pins des IO Controllers als Source für die 
Interrupts angeben muss.
von t0mM3k (Gast)


Lesenswert?

kann mir denn keiner helfen?

Habe jetzt herausgefunden, dass der Chip so behandelt werden kann wie 
sein Vorgänger AT91SAM9260.
Für diesen habe ich eine Headerdatei gefunden:
http://www.keil.com/dd/docs/arm/atmel/sam9260/at91sam9260.h

Darin sind ja alle Register die ich brauche definiert.
Allerdings bekomm ichs einfach nicht raus, wie ich den AIC programmieren 
muss, um als Source den entsprechenden Pin anzugeben, und dann auf eine 
entsprechende ISR zu "mappen".
von Μαtthias W. (matthias) Benutzerseite


Lesenswert?

Hi

wenn ich mir das kleine Beispielprogramm so anschaue würde ich darauf 
tippen (mmap & Co.) das du den Chip nicht "nackt" betreibst sondern ein 
OS (sehr wahrscheinlich Linux) darauf laufen hast. Dann ist das was du 
in deinem Beispiel oben machst nicht der Weg den du gehen solltest. Du 
greifst am Kernel vorbei direkt auf die Register zu. Du solltest das 
aber eher mit den vom Kernel (bzw. den Treiber darin) zur Verfügung 
gestellten Methoden machen. Siehe dazu die Dokumentation zum GPIO 
Framework des Linux Kernels

http://git.kernel.org/?p=linux/kernel/git/stable/linux-stable.git;a=blob_plain;f=Documentation/gpio.txt;hb=c3b92c8787367a8bb53d57d9789b558f1295cc96

Matthias
von t0mM3k (Gast)


Lesenswert?

hm, okay
danke erstmal für deinen hinweis.
ja es läuft linux drauf, aber die Firma von der das Gerät gebaut worden 
ist, hat auch ein paar beispielprogramme mitgeliefert.
Das eine zum ansteuern von LEDs ist genauso gelöst, und darüber die 
Outputpins zu steuern hat wunderbar funktioniert.

Nun wollte ich das mit den Inputs dementsprechend genauso (nur 
andersrum) lösen.
Ist ja prinzipiell auch ganz einfach: die entsprechenden Interrupts am 
PIOB Controller über das IER aktivieren, und alle anderen über das IDR 
disablen.
Somit habe ich meine Maske.
Aber angenommen ich möchte jetzt eine Interrupt Service Routine 
schreiben, in der der Code abgearbeitet werden soll, wenn (z.B.) Pin1 
auf HIGH gesetzt wurde. Wie verknüpfe ich dann die Routine mit dem 
Ereignis Pin1 wurde gerade auf HIGH gesetzt?

Ich hab keine Lust das mit Busy Waiting zu machen indem ich in ner 
endlosschleife immer  ISR auslese und dann mit ner if-then-else Schleife 
zur entsprechenden Methode springe.
von Μαtthias W. (matthias) Benutzerseite


Lesenswert?

Hi

Das Beispielprogramm funktioniert so. Für das setzen und lesen von 
GPIOs. Für Interrupthandling brauchst du zwingend die Mithilfe des 
Kernels da du dessen Interruptbehandlung nicht einfach umgehen kannst. 
Ließ einfach mal das Dokument das ich verlinkt habe. Du wirst um die 
Verwendung der vom Kernel bereitgestellten Dienst nicht vorbeikommen. 
Das hier 
https://www.ridgerun.com/developer/wiki/index.php/How_to_use_GPIO_signals 
könnte auch noch weiterhelfen.

Matthias
von t0mM3k (Gast)


Lesenswert?

okay,
dann hab ich also dank dir den abzweig vom holzweg gefunden.
Neue Stichwörter zu googlen, und neue Tutorials zu lesen.
Naja, vllt schaff ichs ja :)

Vielen Dank
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.