diff --git a/src/drivers/rp-pio-touch_sense.adb b/src/drivers/rp-pio-touch_sense.adb new file mode 100644 index 0000000..2e62c1d --- /dev/null +++ b/src/drivers/rp-pio-touch_sense.adb @@ -0,0 +1,69 @@ +-- +-- Copyright (C) 2022 Fabien Chouteau +-- +-- SPDX-License-Identifier: BSD-3-Clause +-- +with RP.PIO.Touch_Sense_PIO; + +package body RP.PIO.Touch_Sense is + + function Initialized (This : Touch_Sensor) return Boolean + is (This.Enabled); + + procedure Initialize (This : in out Touch_Sensor; + ASM_Offset : PIO_Address := 0; + Max_Count : HAL.UInt32 := 10_000) + 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); + + 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); + + Set_Clock_Frequency (Config, 125_000_000); + This.PIO.SM_Initialize (This.SM, ASM_Offset, Config); + This.PIO.Set_Enabled (This.SM, True); + + This.Enabled := True; + + -- Do a first read to set a default threshold + This.Threshold := This.Raw_Value + 200; + end Initialize; + + function Raw_Value (This : Touch_Sensor) return HAL.UInt32 is + Data : HAL.UInt32; + begin + if not This.Enabled then + return 0; + else + This.PIO.Put (This.SM, This.Max_Count); + This.PIO.Get (This.SM, Data); + return This.Max_Count - Data; + end if; + end Raw_Value; + + function Touch (This : Touch_Sensor) return Boolean + is (This.Raw_Value > This.Threshold); + + function Threshold (This : Touch_Sensor) return HAL.UInt32 + is (This.Threshold); + + procedure Set_Threshold (This : in out Touch_Sensor; + Threshold : HAL.UInt32) + is + begin + This.Threshold := Threshold; + end Set_Threshold; + +end RP.PIO.Touch_Sense; diff --git a/src/drivers/rp-pio-touch_sense.ads b/src/drivers/rp-pio-touch_sense.ads new file mode 100644 index 0000000..91e3051 --- /dev/null +++ b/src/drivers/rp-pio-touch_sense.ads @@ -0,0 +1,77 @@ +-- +-- Copyright (C) 2024 Fabien Chouteau +-- +-- SPDX-License-Identifier: BSD-3-Clause +-- +with RP.GPIO; + +package RP.PIO.Touch_Sense + with Preelaborate +is + -- Capacitive touch sensing is based on change in capacitance typically + -- 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. + -- + -- 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. + -- + -- If users touch the pin, the capacitance will increase and therefore the + -- number of cycles it takes to discharge will increase as well. + + type Touch_Sensor + (Pin : not null access RP.GPIO.GPIO_Point; + PIO : not null access PIO_Device; + SM : PIO_SM) + is tagged private; + + -- Return True if the touch sensor is configured and ready to use + function Initialized (This : Touch_Sensor) return Boolean; + + -- Configure the Pin, PIO and state machine for capacitive touch sensing. + -- And set a default detection threshold based on a first measurement. + -- + -- ASM_Offset is the location in PIO memory where the PIO assembly code + -- will be installed. + -- + -- 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). + procedure Initialize (This : in out Touch_Sensor; + ASM_Offset : PIO_Address := 0; + Max_Count : HAL.UInt32 := 10_000); + + -- Trigger a measurement and return the number of cycles it took for the + -- capacitor to discharge. + -- + -- User touching the pin will increase capacitance, higher capacitance + -- means higher Raw_Value. + function Raw_Value (This : Touch_Sensor) return HAL.UInt32; + + -- Return True if Raw_Value is above the detection threshold + function Touch (This : Touch_Sensor) return Boolean; + + -- Return the threshold for touch detection + function Threshold (This : Touch_Sensor) return HAL.UInt32; + + -- Set threshold for touch detection + procedure Set_Threshold (This : in out Touch_Sensor; + Threshold : HAL.UInt32); + +private + + type Touch_Sensor + (Pin : not null access RP.GPIO.GPIO_Point; + PIO : not null access PIO_Device; + SM : PIO_SM) + is tagged record + Enabled : Boolean := False; + Max_Count : HAL.UInt32; + Threshold : HAL.UInt32 := HAL.UInt32'Last; + end record; + +end RP.PIO.Touch_Sense; diff --git a/src/drivers/rp-pio-touch_sense_pio.ads b/src/drivers/rp-pio-touch_sense_pio.ads new file mode 100644 index 0000000..9f0ee27 --- /dev/null +++ b/src/drivers/rp-pio-touch_sense_pio.ads @@ -0,0 +1,34 @@ +-------------------------------------------------------- +-- This file is autogenerated by pioasm; do not edit! -- +-------------------------------------------------------- + +pragma Style_Checks (Off); + +package RP.PIO.Touch_Sense_PIO + with Preelaborate +is + + ----------------- + -- Touch_Sense -- + ----------------- + + Touch_Sense_Wrap_Target : constant := 0; + Touch_Sense_Wrap : constant := 11; + + Touch_Sense_Program_Instructions : RP.PIO.Program := ( + -- .wrap_target + 16#80a0#, -- 0: pull block + 16#e081#, -- 1: set pindirs, 1 + 16#e001#, -- 2: set pins, 1 + 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#000a#, -- 8: jmp 10 + 16#00c7#, -- 9: jmp pin, 7 + 16#a0c1#, -- 10: mov isr, x + 16#8020#); -- 11: push block + -- .wrap + +end RP.PIO.Touch_Sense_PIO; diff --git a/src/drivers/touch_sense.pio b/src/drivers/touch_sense.pio new file mode 100644 index 0000000..af768b7 --- /dev/null +++ b/src/drivers/touch_sense.pio @@ -0,0 +1,30 @@ +; 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 + +.wrap_target + pull block ; trigger a reading, get maxcount value from fifo, OSR contains maxcount + set pindirs, 1 ; set GPIO as output + set pins, 1 ; drive pin HIGH to charge capacitance +; set x,24 ; wait time for pin charge + set x,30 ; wait time for pin charge +charge: ; wait (24+1)*31 = 1085 cycles = 8.6us + jmp x--, charge [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, timing ; loop while pin is still high +done: + mov isr, x ; load ISR with count value in x + push ; push ISR into RX fifo +.wrap