diff --git a/src/drivers/rp-pio-touch_sense.adb b/src/drivers/rp-pio-touch_sense.adb index 2e62c1d..eb6d4ec 100644 --- a/src/drivers/rp-pio-touch_sense.adb +++ b/src/drivers/rp-pio-touch_sense.adb @@ -3,7 +3,8 @@ -- -- SPDX-License-Identifier: BSD-3-Clause -- -with RP.PIO.Touch_Sense_PIO; +with RP.PIO.Touch_Sense_Discharge_PIO; use RP.PIO.Touch_Sense_Discharge_PIO; +with RP.PIO.Touch_Sense_Charge_PIO; use RP.PIO.Touch_Sense_Charge_PIO; package body RP.PIO.Touch_Sense is @@ -12,24 +13,40 @@ package body RP.PIO.Touch_Sense is procedure Initialize (This : in out Touch_Sensor; ASM_Offset : PIO_Address := 0; - Max_Count : HAL.UInt32 := 10_000) + Max_Count : HAL.UInt32 := 10_000; + Mode : Touch_Mode := Discharge) is Config : PIO_SM_Config := Default_SM_Config; begin This.Max_Count := Max_Count; - This.PIO.Load - (Prog => Touch_Sense_PIO.Touch_Sense_Program_Instructions, - Offset => ASM_Offset); + case Mode is + when Discharge => + This.PIO.Load + (Prog => Touch_Sense_Discharge_Program_Instructions, + Offset => ASM_Offset); + when Charge => + This.PIO.Load + (Prog => Touch_Sense_Charge_Program_Instructions, + Offset => ASM_Offset); + end case; This.Pin.Configure (Output, Floating, This.PIO.GPIO_Function); Set_Jmp_Pin (Config, This.Pin.Pin); Set_Set_Pins (Config, This.Pin.Pin, 1); - Set_Wrap (Config, - ASM_Offset + Touch_Sense_PIO.Touch_Sense_Wrap_Target, - ASM_Offset + Touch_Sense_PIO.Touch_Sense_Wrap); + case Mode is + when Discharge => + Set_Wrap (Config, + ASM_Offset + Touch_Sense_Discharge_Wrap_Target, + ASM_Offset + Touch_Sense_Discharge_Wrap); + + when Charge => + Set_Wrap (Config, + ASM_Offset + Touch_Sense_Charge_Wrap_Target, + ASM_Offset + Touch_Sense_Charge_Wrap); + end case; Set_Clock_Frequency (Config, 125_000_000); This.PIO.SM_Initialize (This.SM, ASM_Offset, Config); diff --git a/src/drivers/rp-pio-touch_sense.ads b/src/drivers/rp-pio-touch_sense.ads index 91e3051..1bc6280 100644 --- a/src/drivers/rp-pio-touch_sense.ads +++ b/src/drivers/rp-pio-touch_sense.ads @@ -12,16 +12,29 @@ is -- introduced by the contact or proximity of the user finger(s) with a -- pin. -- - -- Using PIO, any RP2040 pin connected to ground through a large resistor - -- (e.g. 1Mohm) can be a capacitive touch sensor. + -- Using PIO, any RP2040 pin connected to ground (or 3.3v) through a large + -- resistor (e.g. 1Mohm) can be a capacitive touch sensor. -- - -- The PIO program will charge the internal pin capacitor by configuring - -- the pin as an output and set it high for a few microseconds. And then + -- Two measure modes are available: Charge or Discharge + -- + -- In Discharge mode (Default): Connect the pin to ground through a + -- large resistor. The PIO program will charge the internal pin capacitor + -- by configuring the pin as an output and set it high for a few + -- microseconds. And then set the pin as an input and count how many + -- cycles it takes for the capacitor to discharge through the resistor. + -- + -- In Charge mode: Connect the pin to 3.3v through a large resistor. The + -- PIO program will discharge the internal pin capacitor by configuring + -- the pin as an output and set it low for a few microseconds. And then -- set the pin as an input and count how many cycles it takes for the - -- capacitor to discharge through the resistor. + -- capacitor to charge through the resistor. -- -- If users touch the pin, the capacitance will increase and therefore the - -- number of cycles it takes to discharge will increase as well. + -- number of cycles it takes to discharge/charge will increase as well. + + type Touch_Mode is (Discharge, Charge); + -- Measure either capacitive discharge time (Pin pulled down) or + -- capacitive charge time (pin pulled up). type Touch_Sensor (Pin : not null access RP.GPIO.GPIO_Point; @@ -41,12 +54,15 @@ is -- Max_Count is the maximum number of loops in the PIO program for a -- single measure. Lowering this number will shorten the measure time -- in worst case (high capacitance). + -- + -- Mode select either a discharge or charge count (see above). procedure Initialize (This : in out Touch_Sensor; ASM_Offset : PIO_Address := 0; - Max_Count : HAL.UInt32 := 10_000); + Max_Count : HAL.UInt32 := 10_000; + Mode : Touch_Mode := Discharge); -- Trigger a measurement and return the number of cycles it took for the - -- capacitor to discharge. + -- capacitor to discharge/charge. -- -- User touching the pin will increase capacitance, higher capacitance -- means higher Raw_Value. diff --git a/src/drivers/rp-pio-touch_sense_charge_pio.ads b/src/drivers/rp-pio-touch_sense_charge_pio.ads new file mode 100644 index 0000000..62cb506 --- /dev/null +++ b/src/drivers/rp-pio-touch_sense_charge_pio.ads @@ -0,0 +1,35 @@ +-------------------------------------------------------- +-- This file is autogenerated by pioasm; do not edit! -- +-------------------------------------------------------- + +pragma Style_Checks (Off); + +package RP.PIO.Touch_Sense_Charge_PIO + with Preelaborate +is + + ------------------------ + -- Touch_Sense_Charge -- + ------------------------ + + Touch_Sense_Charge_Wrap_Target : constant := 0; + Touch_Sense_Charge_Wrap : constant := 12; + + Touch_Sense_Charge_Program_Instructions : RP.PIO.Program := ( + -- .wrap_target + 16#80a0#, -- 0: pull block + 16#e081#, -- 1: set pindirs, 1 + 16#e000#, -- 2: set pins, 0 + 16#e03e#, -- 3: set x, 30 + 16#1f44#, -- 4: jmp x--, 4 [31] + 16#a027#, -- 5: mov x, osr + 16#e080#, -- 6: set pindirs, 0 + 16#0049#, -- 7: jmp x--, 9 + 16#000b#, -- 8: jmp 11 + 16#00cb#, -- 9: jmp pin, 11 + 16#0007#, -- 10: jmp 7 + 16#a0c1#, -- 11: mov isr, x + 16#8020#); -- 12: push block + -- .wrap + +end RP.PIO.Touch_Sense_Charge_PIO; diff --git a/src/drivers/rp-pio-touch_sense_pio.ads b/src/drivers/rp-pio-touch_sense_discharge_pio.ads similarity index 70% rename from src/drivers/rp-pio-touch_sense_pio.ads rename to src/drivers/rp-pio-touch_sense_discharge_pio.ads index 9f0ee27..c8f12de 100644 --- a/src/drivers/rp-pio-touch_sense_pio.ads +++ b/src/drivers/rp-pio-touch_sense_discharge_pio.ads @@ -4,18 +4,18 @@ pragma Style_Checks (Off); -package RP.PIO.Touch_Sense_PIO +package RP.PIO.Touch_Sense_Discharge_PIO with Preelaborate is - ----------------- - -- Touch_Sense -- - ----------------- + --------------------------- + -- Touch_Sense_Discharge -- + --------------------------- - Touch_Sense_Wrap_Target : constant := 0; - Touch_Sense_Wrap : constant := 11; + Touch_Sense_Discharge_Wrap_Target : constant := 0; + Touch_Sense_Discharge_Wrap : constant := 11; - Touch_Sense_Program_Instructions : RP.PIO.Program := ( + Touch_Sense_Discharge_Program_Instructions : RP.PIO.Program := ( -- .wrap_target 16#80a0#, -- 0: pull block 16#e081#, -- 1: set pindirs, 1 @@ -31,4 +31,4 @@ is 16#8020#); -- 11: push block -- .wrap -end RP.PIO.Touch_Sense_PIO; +end RP.PIO.Touch_Sense_Discharge_PIO; diff --git a/src/drivers/touch_sense_charge.pio b/src/drivers/touch_sense_charge.pio new file mode 100644 index 0000000..bd96b5d --- /dev/null +++ b/src/drivers/touch_sense_charge.pio @@ -0,0 +1,31 @@ +; SPDX-FileCopyrightText: 2017 Scott Shawcroft, written for Adafruit Industries +; SPDX-FileCopyrightText: Copyright (c) 2023 Tod Kurt +; +; SPDX-License-Identifier: MIT + + +; See rp-pio-touch_sense.ads for more high level explanation of the touch +; sensing process. + +.program touch_sense_charge + +.wrap_target + pull block ; trigger a reading, get maxcount value from fifo, OSR contains maxcount + set pindirs, 1 ; set GPIO as output + set pins, 0 ; drive pin LOW to discharge capacitance +; set x,24 ; wait time for pin discharge + set x,30 ; wait time for pin discharge +discharge: ; wait (24+1)*31 = 1085 cycles = 8.6us + jmp x--, discharge [31] + mov x, osr ; load maxcount value (10_000 usually) + set pindirs, 0 ; set GPIO as input +timing: + jmp x--, test ; decrement x until timeout + jmp done ; we've timed out, so leave +test: + jmp pin, done ; exit when pin is becomes high + jmp timing ; loop otherwise +done: + mov isr, x ; load ISR with count value in x + push ; push ISR into RX fifo +.wrap diff --git a/src/drivers/touch_sense.pio b/src/drivers/touch_sense_discharge.pio similarity index 97% rename from src/drivers/touch_sense.pio rename to src/drivers/touch_sense_discharge.pio index af768b7..91af7f7 100644 --- a/src/drivers/touch_sense.pio +++ b/src/drivers/touch_sense_discharge.pio @@ -7,7 +7,7 @@ ; See rp-pio-touch_sense.ads for more high level explanation of the touch ; sensing process. -.program touch_sense +.program touch_sense_discharge .wrap_target pull block ; trigger a reading, get maxcount value from fifo, OSR contains maxcount