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?
QTouch sollte mit allen Mikrocontrollern funktionieren, die Tristate- Ausgänge haben. Das dürften fast alle bis auf einige 8051-Derivate sein.
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:
1 | int main(void){ |
2 | uint32_t count = 0; |
3 | RCC->APB2ENR |= RCC_APB2ENR_IOPCEN; //GPIOC clock enable |
4 | |
5 | for(;;){ |
6 | count = 0; |
7 | |
8 | //PC9 & PC13 als Ausgang (Push-Pull)
|
9 | GPIOC->CRH = GPIOC->CRH & ~(0x00F000F0) | (0x00300030); |
10 | |
11 | //und low ziehen
|
12 | GPIOC->BSRR = GPIO_BSRR_BR9; //reset pin PC9 |
13 | GPIOC->BSRR = GPIO_BSRR_BR13; //reset pin PC13 |
14 | |
15 | delay_ms(1); //1ms warten (Kondensator entladen) |
16 | |
17 | |
18 | do{ |
19 | //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).
> if((GPIOC->IDR & 0x00002000) == 1){
Wie soll das jemals 1 werden?
if((GPIOC->IDR & 0x00002000)){
Und im do...while fehlen noch Verzögerungen um der Ladung Zeit zu geben, sich zu verschieben. ;-)
und der versprochene Screenshot fehlt auch :-P
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:
1 | int main(void){ |
2 | uint32_t count = 0; |
3 | RCC->APB2ENR |= RCC_APB2ENR_IOPCEN; //GPIOC clock enable |
4 | |
5 | for(;;){ |
6 | count = 0; |
7 | |
8 | //PC9 & PC13 als Ausgang (Push-Pull)
|
9 | GPIOC->CRH = GPIOC->CRH & ~(0x00F000F0) | (0x00300030); |
10 | |
11 | //und low ziehen
|
12 | GPIOC->BSRR = GPIO_BSRR_BR9; //reset pin PC9 |
13 | GPIOC->BSRR = GPIO_BSRR_BR13; //reset pin PC13 |
14 | |
15 | delay_ms(1); //1ms warten |
16 | |
17 | |
18 | do{ |
19 | //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:
1 | #define COUNT_VAL 1000
|
2 | |
3 | int main(void){ |
4 | uint32_t count = 0; |
5 | RCC->APB2ENR |= RCC_APB2ENR_IOPCEN; //GPIOC clock enable |
6 | |
7 | for(;;){ |
8 | count = COUNT_VAL + 1; |
9 | |
10 | //PC9 & PC13 als Ausgang (Push-Pull)
|
11 | GPIOC->CRH = GPIOC->CRH & ~(0x00F000F0) | (0x00300030); |
12 | |
13 | //und low ziehen
|
14 | GPIOC->BSRR = GPIO_BSRR_BR9; //reset pin PC9 |
15 | GPIOC->BSRR = GPIO_BSRR_BR13; //reset pin PC13 |
16 | |
17 | delay_ms(1); //1ms warten |
18 | |
19 | |
20 | do{ |
21 | //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!
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.