Hallo,
hat jemand von Euch schon Erfahrungen mit den GPIOs eines Atmel SAMD21
sammeln können?
Ich habe ein seltsames Problem. Ich lese, wenn ich die für
Datenleitungen (D7..D0) vorgesehenen Port Pins am EXT2-Header auf
PULL_UP konfiguriere, den Wert 0xFF ein, konfiguriere ich auf PULL_DOWN
lese ich entsprechen 0x00.
Ich kann auch den oberen Nibble auf PULL_UP, den unteren Nibble auf
PULL_DOWN konfigurieren, so dass ich 0xF0 lese - wenn ich dann aber D7
mit GND verbinde oder D0 mit VCC (dass läßt sich einfach mittels Jumper
machen), lese ich nicht etwa 0x70 oder 0xF1, sondern nach wie vor
0xF0!!!
Hat jemand eine Idee, was ich da falsch mache?
So, hab' mir jetzt mal so ein SAMD21 XplainedPro an Land gezogen,
wollte demnächst sowieso mal was mit einem SAMD20 selbst machen.
Das ganze ASF-Geraffel ist mir suspekt. Eine Funktion, die ein Bit
in einem Steuerregister setzt oder löscht, brauch ich nicht, ich kann
mit dem |= und &=-Operator ganz gut umgehen. ;-)
Ich habe daher mal eine Minimal-App gezimmert, die je nachdem, ob man
einen Jumper bei PA16 oder PA19 reinsteckt, die LED0 an- oder
ausschaltet. Funktioniert.
1
#include"sam.h"
2
3
void_init(void)
4
{
5
}
6
7
int
8
main(void)
9
{
10
// unusable, since PORT is a macro
11
// PM->APBBMASK.bit.PORT = 1;
12
PM->APBBMASK.reg=8;
13
14
/* PA19: input with pulldown */
15
PORT->Group[0].PINCFG[19].bit.INEN=1;
16
PORT->Group[0].PINCFG[19].bit.PULLEN=1;
17
PORT->Group[0].OUTCLR.bit.OUTCLR=(1<<19);
18
19
/* PA16: input with pullup */
20
PORT->Group[0].PINCFG[16].bit.INEN=1;
21
PORT->Group[0].PINCFG[16].bit.PULLEN=1;
22
PORT->Group[0].OUTSET.bit.OUTSET=(1<<16);
23
24
/* LED0 on XPlainedPro: PB30, active low */
25
PORT->Group[1].DIRSET.bit.DIRSET=(1<<30);
26
PORT->Group[1].OUTSET.bit.OUTSET=(1<<30);
27
28
for(;;)
29
{
30
if((PORT->Group[0].IN.bit.IN&(1<<19))!=0)
31
{
32
/* PA19 pulled high */
33
/* turn on LED */
34
PORT->Group[1].OUTCLR.bit.OUTCLR=(1<<30);
35
/* wait for button release */
36
while((PORT->Group[0].IN.bit.IN&(1<<19))!=0)
37
{
38
}
39
}
40
41
if((PORT->Group[0].IN.bit.IN&(1<<16))==0)
42
{
43
/* PA16 pulled low */
44
/* turn off LED */
45
PORT->Group[1].OUTSET.bit.OUTSET=(1<<30);
46
/* wait for button release */
47
while((PORT->Group[0].IN.bit.IN&(1<<16))==0)
48
{
49
}
50
}
51
}
52
53
return0;
54
}
(Die leere _init() wollte er bei mir unbedingt haben, sonst gibt's
einen Linkerfehler. Eventuell brauchst du die ja nicht.)
Jörg Wunsch schrieb:> Jumper bei PA16 oder PA19 reinsteckt,
Das sind übrigens, im Gegensatz zu deinem Bild, die Pins links an
der Steckerleiste. Nur dort gibt's sowohl Vcc als auch GND, auf
der rechten Seite ist statt Vcc die Leitung zur Identifikation des
angesteckten Moduls.
Jörg Wunsch schrieb:> Nur dort gibt's sowohl Vcc als auch GND, auf> der rechten Seite ist statt Vcc die Leitung zur Identifikation des> angesteckten Moduls.
Das stimmt so, wenn ich in links/rechts unterscheide - unterscheide ich
es in oben/unten gibt es VCC und GND nur unten :-).
Jörg Wunsch schrieb:> Das ganze ASF-Geraffel ist mir suspekt.
Sicher bringt so eine Lib 'ne Menge Overhead mit, wenn sie aber gut
gemacht ist, läßt sich eine nicht zeitkritische Applikation auch mal
lösen, ohne das Datenblatt studieren zu müssen. Ich benutze bei meiner
Applikation den virtuellen ComPort (mit Callbackfunktionen), 'nen
Timerinterrupt und ettliche GPIOs des EXT2-Steckers. Dazu habe ich die
"getting-started" Applikation etwas abgeändert und das Programm um
insgesamt drei Module/Klassen erweitert. Mittlerweile funktioniert das
Programm auch, hab' mir wieder eine ordentlichen "Schnitzer" erlaubt.
Ich hatte zunächst die Ausgänge mittels port_pin_set_output_level(pin,
val) getestet und dabei auch die Wiederholrate des Timer-Interrupts
justiert.
Für das Lesen eines GPIO-Pins habe ich dann eine
port_pin_set_output_level(pin, val)-Zeile kopiert, den zweiten Parameter
rausgeschmissen und das set in get geändert - und übersehen, dass ich
auch output in input hätte ändern müässen! :-)
Mit port_pin_get_input_level(pin) funktioniert das Programm wie
gewünscht.
U.G. L. schrieb:>> Das ganze ASF-Geraffel ist mir suspekt.>> Sicher bringt so eine Lib 'ne Menge Overhead mit, wenn sie aber gut> gemacht ist, läßt sich eine nicht zeitkritische Applikation auch mal> lösen, ohne das Datenblatt studieren zu müssen.
Ist nicht so mein Ding; ich möchte gern selbst in der Hand haben, was
auf meinen Controllern passiert und was nicht.
Und „gut gemacht“, hmm, naja, hüstel, „gut gemeint“ ist meist das
Gegenteil davon … ;-)
Wenn man sowas konsequent durchzieht, ist man bei Konzepten à la
Arduino oder Bascom, aber die sind dann wenigstens in sich stimmig.
ASF ist meiner Meinung nach an vielen Stellen einfach nur Overhead
ohne Konzept dahinter.
Jörg Wunsch schrieb:> Und „gut gemacht“, hmm, naja, hüstel, „gut gemeint“ ist meist das> Gegenteil davon … ;-)
Das bezog sich jetzt nicht speziell auf die ASF - da ich die jetzt nur
für dieses eine Projekt eingesetzt habe, will ich mir da kein Urteil
anmaßen - da sie für lau zu haben ist, würd' ich ein "gut gemacht" aber
schon vergeben, wenn sie einen nicht mit Fehlern ärgert. Ich meine klar
- ich hätte schon jetzt, wie auf der PC-Seite, gerne etwas wie
usart_read_buffer_job_until(...) gehabt, dem ich einen Delimiter
Character mitgeben kann - gab's nicht und ich musste die Zeichen einzeln
reinlutschen, aber es hat auch so auf Anhieb funktioniert.
Und bei etwas zeitkritischem würd' ich von vorn herein nicht auf eine
Lib bauen - die unterschiedlichen Anforderungen, die Libraries
typischerweise erfüllen müssen, sind eben mit einem gewissen Overhead
verbunden.