Hallo,
mich würde interessieren, ob das Charge-Transfer-Prinzip (vgl. Qtouch)
auch auf einem STM32 anwendbar ist. Soweit ich das den Qtouch
Spezifikationen und diesem
Beitrag "qtouch - sekt oder selters" Thread entnehmen konnte,
wird hierfür nur ein Mikrocontroller benötigt der abschaltbare Pullups
besitzt. Also sollte das Prinzip auch auf andere Mikrocontroller (in
meinem Fall einen STM32) portierbar sein, oder irre ich da?
Ich hab bereits gestern ein paar Tests gemacht, jedoch waren diese nicht
von Erfolg gekrönt. Bevor ich jetzt Zeit in die Fehlersuche investiere
(bin mir im Moment überhaupt nicht sicher, ob der Fehler software - oder
hardwareseitig begraben liegt), wollte ich mal kurz rückfragen ob das
Charge-Transfer-Prinzip prinzipiell mit dem STM32 zu realisieren ist?
Genau, sollte eigentlich mit jedem vernünftigen Mikrocontroller gehen
auf dem man Ports per Firmware, während der Laufzeit auf Aus- oder
Eingang konfigurieren kann.
Funktionieren tuts dann natürlich noch besser, wenn die Ports möglichst
geringe Leckströme aufweisen, aber das ist dann eher ein Detail.
Einigermassen funktionieren sollte es auf jeden Fall.
Als ich den Code für den MSP430 angepasst hatte, musste ich ein paar
kleine Anpassungen beim Timing vornehmen. Eventuell musst Du das auch
tun, denn je nach Taktfrequenz Deines Mikrocontrollers verändert sich so
einiges... Eventuell musst Du bei der Schleife einen grösseren
Datentypen nehmen, falls die Zählvariable grösser als 255 werden kann
und mit dem Abbruchkriterium ein wenig experimentieren bzw. mit dem
Debugger schauen wo die Werte in etwa liegen.
Hi,
na das hört sich ja mal nicht so schlecht an, dann sollte das ja
theoretisch auch mit dem STM32 funktionieren.
Ich hab mich da heute nochmals hingesetzt, doch irgendwie will das nicht
so wirklich funktionieren.
Mein Hardwareaufbau sieht so aus:
PC9-----------+---- 1K ---- Touchpad
|
---
--- 47n
|
PC13----------+
Mein Sourcecode sieht so aus:
//beide als floating input schalten, damit keine Ladung abfliessen kann
20
GPIOC->CRH=GPIOC->CRH&~(0x00F000F0)|(0x00400040);
21
22
//PC13 Out und high schalten, um C aufzuladen
23
GPIOC->CRH=GPIOC->CRH&~(0x00F00000)|(0x00300000);
24
25
GPIOC->BSRR=GPIO_BSRR_BS13;//PC13 high schalten
26
27
28
//und PC13 wieder als floating input
29
GPIOC->CRH=GPIOC->CRH&~(0x00F00000)|(0x00400000);
30
31
//Die Ladung aus C jetzt nach PC9 auf GND abfuehren
32
GPIOC->CRH=GPIOC->CRH&~(0x000000F0)|(0x00000030);
33
34
GPIOC->BSRR=GPIO_BSRR_BR9;//PC9 nach GND schalten
35
36
//messen, ob Ladung schon fuer eine 1 an PC13 reicht, sonst von vorn
37
if((GPIOC->IDR&0x00002000)==1){
38
printf("Count = %d",count);
39
}
40
41
count++;
42
}while(count<1000);
43
}
44
}
Bei der Count-Variable hab ich, wie Johnny B. vorgeschlagen hat, einen
größeren Datentyp (zum Testen mal 32bit) genommen.
Mein Problem ist nun, dass die Bedingung dieser Schleife nie wahr ist:
1
if((GPIOC->IDR&0x00002000)==1){
2
printf("Count = %d",count);
3
}
Im Moment steh ich grad ein bisschen auf'm Schlauch und kann mir das
nicht ganz erklären...
Wenn ich mit dem Oszi zwischen dem Touchpad und GND messe, dann ergibt
sich der folgende Spannungsverlauf (siehe Screenshot).
holger schrieb:> Wie soll das jemals 1 werden?
Du hast natürlich vollkommen Recht, danke. Ich hab irgendwie die ganze
Zeit den Fehler bei der Portinitialisierung gesucht.
Immerhin bekomm ich jetzt ne Ausgabe, aber nur dann wenn ich mit dem
Finger das Pad (in meinem Fall ein Lötpunkt aus 3x3 Lochrasterpunkten)
auf der Unterseite der Platine berühre. Irgendwas passt da noch nicht
ganz. Ich werd mal zur Sicherheit alle Lötstellen nachlöten, um
schlechten Kontakt auszuschließen.
Johnny B. schrieb:> Und im do...while fehlen noch Verzögerungen um der Ladung Zeit zu geben,> sich zu verschieben. ;-)
Die hab' ich weggelassen, auf Grund des Postings von Peter Dannegger: (
Beitrag "Re: qtouch - sekt oder selters" )
"Es reichen die Delays durch die Ausführungszeit der Meßloop vollkommen
aus, um die wenigen pF umzuladen.
Nur für die Entladung des 33nF bis zur nächsten Messung sollte man etwas
Zeit lassen."
Die CPU wird übrigens mit 8MHz getaktet. Aber ich kann mal probieren ein
delay einzubauen, vielleicht ändert das ja etwas. Wie lange sollte man
da in etwa warten? 5us?
Julian O. schrieb:> und der versprochene Screenshot fehlt auch :-P
Du hast Recht, den hab' ich glatt vergessen. Jetzt ist er im Anhang.
Bernhard B. schrieb:> //PC13 Out und high schalten, um C aufzuladen> GPIOC->CRH = GPIOC->CRH & ~(0x00F00000) | (0x00300000);>> GPIOC->BSRR = GPIO_BSRR_BS13; //PC13 high schalten
Du must zuerst den gewünschten Pegel vorbereiten und danach auf Ausgang
schalten. Sonst entlädst Du ja wieder.
Peter
Peter Dannegger schrieb:> Bernhard B. schrieb:>> //PC13 Out und high schalten, um C aufzuladen>> GPIOC->CRH = GPIOC->CRH & ~(0x00F00000) | (0x00300000);>>>> GPIOC->BSRR = GPIO_BSRR_BS13; //PC13 high schalten>> Du must zuerst den gewünschten Pegel vorbereiten und danach auf Ausgang> schalten. Sonst entlädst Du ja wieder.>>> Peter
Wie meinst du das genau?
Ich soll PC13 zuerst auf High schalten und dann als Ausgang
konfigurieren?
Ich dachte man kann einen IO-Port nur dann auf ein Potential ziehen,
wenn der IO-Port als Ausgang konfiguriert wurde?
Wenn Dein Port aber "0" ist, Du ihn dann als Ausgang definierst und
anschließend erst "1" schaltest, ist schon etwas Zeit vergangen, in der
der Port "0" ausgegeben und somit den C schon wieder (etwas) entladen
hat.
Ich hab wie gesagt gedacht, dass ich nen IO-Port nur dann auf ein
Potential ziehen kann (in meinem Fall "1") wenn der entsprechende Port
als Ausgang konfiguriert wurde.
Ich hab das aber mal umgebaut:
//beide als floating input schalten, damit keine Ladung abfliessen kann
20
GPIOC->CRH=GPIOC->CRH&~(0x00F000F0)|(0x00400040);
21
22
GPIOC->BSRR=GPIO_BSRR_BS13;//PC13 high schalten
23
24
//PC13 Out und high schalten, um C aufzuladen
25
GPIOC->CRH=GPIOC->CRH&~(0x00F00000)|(0x00300000);
26
27
28
//und PC13 wieder als floating input
29
GPIOC->CRH=GPIOC->CRH&~(0x00F00000)|(0x00400000);
30
31
//Die Ladung aus C jetzt nach PC9 auf GND abfuehren
32
GPIOC->CRH=GPIOC->CRH&~(0x000000F0)|(0x00000030);
33
34
GPIOC->BSRR=GPIO_BSRR_BR9;//PC9 nach GND schalten
35
36
//messen, ob Ladung schon fuer eine 1 an PC13 reicht, sonst von vorn
37
if((GPIOC->IDR&0x00002000)){
38
printf("Count = %d",count);
39
}
40
41
count++;
42
}while(count<1000);
Jedoch bleibt das Problem, es wird nur etwas ausgegeben wenn ich mit dem
Finger direkt auf den Lötpunkt greife...
Die Lötverbindungen hab ich jetzt nochmal nachgelötet, das sollte
passen.
Jemand ne Idee was da falsch laufen könnte?
Bernhard B. schrieb:> //Die Ladung aus C jetzt nach PC9 auf GND abfuehren> GPIOC->CRH = GPIOC->CRH & ~(0x000000F0) | (0x00000030);>> GPIOC->BSRR = GPIO_BSRR_BR9; //PC9 nach GND schalten>> //messen, ob Ladung schon fuer eine 1 an PC13 reicht, sonst von vorn> if((GPIOC->IDR & 0x00002000)){
Wieder das gleiche, erst den Pegel einschalten und danach auf Ausgang!
Ich nehme mal an, BSR ist das Ausgangsregister und CRH das
Richtungsregister.
Beim AVR gibt es die Besonderheit, daß er auch nen Pullup einschalten
kann.
Daher muß ich für Tristate das Ausgangsregister auf Low setzen.
Wenn das beim STM32 nicht so ist, dann setze die Pins einfach einmalig
vor der Schleife und in der Schleife nur die Richtung.
Und daß ich zuerst die Zählschleife prüfe und danach den Pin, hat schon
seinen Grund.
Beim AVR werden Eingänge gelatcht, d.h. es muß mindestens ein CPU-Zyklus
zwischen Setzen des Ausgangs und Rücklesen des Eingangs vergehen.
Peter
Danke für deinen Input. Ich hab mich von deinem Programm im "Qtouch -
Sekt oder Selters" Thread inspirieren lassen und meines dementsprechend
umgebaut.
Nun sieht es so aus:
//beide als floating input schalten, damit keine Ladung abfliessen kann
22
GPIOC->CRH=GPIOC->CRH&~(0x00F000F0)|(0x00400040);
23
24
GPIOC->BSRR=GPIO_BSRR_BS13;//PC13 high schalten
25
26
//PC13 Out und high schalten, um C aufzuladen
27
GPIOC->CRH=GPIOC->CRH&~(0x00F00000)|(0x00300000);
28
29
30
//und PC13 wieder als floating input
31
GPIOC->CRH=GPIOC->CRH&~(0x00F00000)|(0x00400000);
32
33
GPIOC->BSRR=GPIO_BSRR_BR9;//PC9 nach GND schalten
34
35
//Die Ladung aus C jetzt nach PC9 auf GND abfuehren
36
GPIOC->CRH=GPIOC->CRH&~(0x000000F0)|(0x00000030);
37
38
39
if(--count==0){
40
break;
41
}
42
43
}while(!(GPIOC->IDR&0x00002000));
44
printf("Count = %d",COUNT_VAL-count);//hier wird dann Timeout oder "Key pressed" ausgegeben
45
}
46
}
Wenn ich den Debugger anwerfe, dann sehe ich, dass alle IO-Ports richtig
konfiguriert werden (Floating Input bzw. Push-Pull) und diese auch
korrekt auf Low bzw High gezogen werden.
Ich bekommen jedoch immer nen Timeout - egal ob ich den 3x3 Lötpunkt,
welcher bei mir als Touchpad fungiert, durch die Platine hindurch
berühre oder nicht.
Was mir gerade noch einfällt: Mein Touchpad befindet sich auf einer
kleinen Lochrasterplatine, wo auch der 1K Widerstand und der 47nF
Kondensator sitzen (hab versucht die beiden Komponenten so nah ans Pad
zu löten als möglich). Um die Touchpad-Platine mit der
Mikrocontroller-Platine zu verbinden, verwende ich zwei ca. 15cm lange
Drähte. Könnte das vielleicht der Übeltäter sein?
So, ich hab die zwei Anschlussdrähte mal auf 3cm gekappt - leider keine
Besserung. Ich hab mir schon überlegt, den 1K Widerstand zwischen dem
Touchpad gegen einen 10K auszutauschen. Aber ich glaub kaum das das was
bringt, da der Spannungsverlauf am Touchpad genauso aussieht wie das in
der Spezifikation von Atmel beschrieben wurde (siehe Anhang)
Keine Ahnung was da nicht passt...
Bernhard B. schrieb:> Ich hab mir schon überlegt, den 1K Widerstand zwischen dem> Touchpad gegen einen 10K auszutauschen.
Warum?
Die Empfindlichkeit sollte man erst dann senken, wenn man überhaupt
erstmal eine Empfindlichkeit hat.
Ich würde auch den 2.Widerstand zum Begrenzen des Umladestromes
vorsehen.
Den Innenwiderstand der Ausgangstreiber zu nehmen, ist kein sauberes
Design.
Hast Du meinen Rat mit der Wartezeit vor dem Einlesen beachtet?
Ansonsten, ob Deine kryptischen Hexwerte überhaupt das tun, was sie
sollen, kannst nur Du feststellen.
Ich kenne den STM32 nicht. Wie schaltet der die internen Pullups ein?
Am besten Du schreibst Dir erstmal Macros (z.B. PIN_LOW, PIN_HIGH,
PIN_INPUT, PIN_OUTPUT, PIN_TEST) und benutzt diese.
Und benutze nicht irgendwelche kryptischen Hexwerte, sondern definier
Dir die beiden Pins, z.B. SENSKEY_A0, SENSKEY_B0.
Peter
Peter Dannegger schrieb:> Ich würde auch den 2.Widerstand zum Begrenzen des Umladestromes> vorsehen.
Ok, werd ich ergänzen.
Peter Dannegger schrieb:> Hast Du meinen Rat mit der Wartezeit vor dem Einlesen beachtet?
Was meinst du genau? Im Moment warte ich eine Millisekunde um
sicherzustellen, dass der Kondensator vollkommen entladen ist.
Sonstige Verzögerungen hab' ich im Moment nicht eingebaut.
Peter Dannegger schrieb:> Ansonsten, ob Deine kryptischen Hexwerte überhaupt das tun, was sie> sollen, kannst nur Du feststellen.
Laut Debugger sollte das passen.
Peter Dannegger schrieb:> Ich kenne den STM32 nicht. Wie schaltet der die internen Pullups ein?
Ich dachte die müssen ausgeschalten sein? Zumindest hab ich das diesem
Beitrag "Re: qtouch - sekt oder selters" Posting entnommen.
Wieder ein kleines Update:
Ich hab' jetzt mal nen 1ct Münze auf die Unterseite der
Lochrasterplatine gelötet, um mein Pad zu vergrößern. Ebenso hab ich den
zweiten Widerstand (2K2) zum Begrenzen des Umladestroms eingelötet.
Wenn ich jetzt mit dem Finger direkt auf die Kupfermünze greife, dann
bekomme ich folgende Werte:
Count = 322
Count = 398
Count = 316
Count = 334
Count = 393
Count = 307
Count = 348
Count = 387
Count = 302
Count = 360
Count = 375
Count = 300
Count = 372
Count = 361
Count = 397
Wenn ich mit dem Finger jedoch auf die Oberseite der Lochrasterplatine
greife dann tut sich überhaupt nichts...
Bernhard B. schrieb:> Was meinst du genau?
Die Zeit zwischen Pin_A auf low-Ausgang bis zum Einlesen von Pin_B.
Dürfte auch beim STM um ein oder mehrere IO-Takte verzögert sein.
Und deshalb mache ich das "if( --i == 0 ) break;" dazwischen zum
Zeitschinden.
> Ich dachte die müssen ausgeschalten sein?
Ja.
Aber beim AVR muß man etwas tricksen, da die Pullups mit PORTxy:DDRxy =
1:0 aktiv werden.
Gibts beim STM dafür ein extra Register, kann man sich die Trickserei
sparen, d.h. Pin_B = 1 aus der Schleife rausziehen.
Peter
Peter Dannegger schrieb:> Die Zeit zwischen Pin_A auf low-Ausgang bis zum Einlesen von Pin_B.> Dürfte auch beim STM um ein oder mehrere IO-Takte verzögert sein.>> Und deshalb mache ich das "if( --i == 0 ) break;" dazwischen zum> Zeitschinden.
Alles klar, das meinst du. Ja, das hab ich bereits oben eingebaut.
Peter Dannegger schrieb:> Gibts beim STM dafür ein extra Register, kann man sich die Trickserei> sparen, d.h. Pin_B = 1 aus der Schleife rausziehen.
Hab' ich mal geändert, bringt aber leider auch nicht den gewünschten
Erfolg.
PS: Hat das eigentlich nen tiefergehenden Sinn, dass viele Qtouch -
Softwarelösungen im Thread "Qtouch - Sekt oder Selters" zwei
unterschiedliche Ports nutzen?
Ich glaub ich habs jetzt hinbekommen.
Ich musste COUNT_VAL erhöhen, da bei mir der Wert ungedrückt bereits
1300 ist.
1
#define COUNT_VAL 1500
Wenn ich nun auf die Oberseite der Lochrasterplatine greife, dann ändert
sich der Wert auf 1100.
Ich werd morgen noch nen ausführlichen Test machen, aber ich glaub es
passt.
Danke an alle!