element14 Community
element14 Community
    Register Log In
  • Site
  • Search
  • Log In Register
  • About Us
  • Community Hub
    Community Hub
    • What's New on element14
    • Feedback and Support
    • Benefits of Membership
    • Personal Blogs
    • Members Area
    • Achievement Levels
  • Learn
    Learn
    • Ask an Expert
    • eBooks
    • element14 presents
    • Learning Center
    • Tech Spotlight
    • STEM Academy
    • Webinars, Training and Events
    • Learning Groups
  • Technologies
    Technologies
    • 3D Printing
    • FPGA
    • Industrial Automation
    • Internet of Things
    • Power & Energy
    • Sensors
    • Technology Groups
  • Challenges & Projects
    Challenges & Projects
    • Design Challenges
    • element14 presents Projects
    • Project14
    • Arduino Projects
    • Raspberry Pi Projects
    • Project Groups
  • Products
    Products
    • Arduino
    • Avnet Boards Community
    • Dev Tools
    • Manufacturers
    • Multicomp Pro
    • Product Groups
    • Raspberry Pi
    • RoadTests & Reviews
  • Store
    Store
    • Visit Your Store
    • Choose another store...
      • Europe
      •  Austria (German)
      •  Belgium (Dutch, French)
      •  Bulgaria (Bulgarian)
      •  Czech Republic (Czech)
      •  Denmark (Danish)
      •  Estonia (Estonian)
      •  Finland (Finnish)
      •  France (French)
      •  Germany (German)
      •  Hungary (Hungarian)
      •  Ireland
      •  Israel
      •  Italy (Italian)
      •  Latvia (Latvian)
      •  
      •  Lithuania (Lithuanian)
      •  Netherlands (Dutch)
      •  Norway (Norwegian)
      •  Poland (Polish)
      •  Portugal (Portuguese)
      •  Romania (Romanian)
      •  Russia (Russian)
      •  Slovakia (Slovak)
      •  Slovenia (Slovenian)
      •  Spain (Spanish)
      •  Sweden (Swedish)
      •  Switzerland(German, French)
      •  Turkey (Turkish)
      •  United Kingdom
      • Asia Pacific
      •  Australia
      •  China
      •  Hong Kong
      •  India
      •  Korea (Korean)
      •  Malaysia
      •  New Zealand
      •  Philippines
      •  Singapore
      •  Taiwan
      •  Thailand (Thai)
      • Americas
      •  Brazil (Portuguese)
      •  Canada
      •  Mexico (Spanish)
      •  United States
      Can't find the country/region you're looking for? Visit our export site or find a local distributor.
  • Translate
  • Profile
  • Settings
Raspberry Pi
  • Products
  • More
Raspberry Pi
Raspberry Pi Forum Want to create a capacitance proximity/touch sensor with a RP2040 Pico board using PIO
  • Blog
  • Forum
  • Documents
  • Quiz
  • Events
  • Polls
  • Files
  • Members
  • Mentions
  • Sub-Groups
  • Tags
  • More
  • Cancel
  • New
Join Raspberry Pi to participate - click to join for free!
Featured Articles
Announcing Pi
Technical Specifications
Raspberry Pi FAQs
Win a Pi
Raspberry Pi Wishlist
Actions
  • Share
  • More
  • Cancel
Forum Thread Details
  • State Not Answered
  • Replies 36 replies
  • Subscribers 662 subscribers
  • Views 12274 views
  • Users 0 members are here
  • proximity_sensors
  • rp2040
  • PIO
  • capacitive
Related

Want to create a capacitance proximity/touch sensor with a RP2040 Pico board using PIO

BigG
BigG over 3 years ago

There is nothing quite like solving a problem to help develop new skills. In this case I have found a library solution to what I want to achieve but it is not RP2040 compatible and of course it does not use PIO, which is the skill I am trying to acquire.

Having seen other members deliver some great PIO related projects, I thought this would be a great opportunity to build a solution together while helping me, and hopefully others, grasp how to develop PIO code from scratch.

Basically I want to create a capacitance touch or proximity sensor using a Raspberry Pi Pico (RP2040) board.

There is an Arduino library that can do this: https://github.com/PaulStoffregen/CapacitiveSensor

But it is not RP2040 compatible: https://github.com/PaulStoffregen/CapacitiveSensor/issues/42

Having reviewed this library, it appears on face value to be well suited to use PIO. Only, I don't know how to start.

As far as I can make out, there is only one function to apply PIO... but maybe others see things differently. I'm keen to learn more.

// Private Methods /////////////////////////////////////////////////////////////
// Functions only available to other functions in this library

int CapacitiveSensor::SenseOneCycle(void)
{
    noInterrupts();
	DIRECT_WRITE_LOW(sReg, sBit);	// sendPin Register low
	DIRECT_MODE_INPUT(rReg, rBit);	// receivePin to input (pullups are off)
	DIRECT_MODE_OUTPUT(rReg, rBit); // receivePin to OUTPUT
	DIRECT_WRITE_LOW(rReg, rBit);	// pin is now LOW AND OUTPUT
	delayMicroseconds(10);
	DIRECT_MODE_INPUT(rReg, rBit);	// receivePin to input (pullups are off)
	DIRECT_WRITE_HIGH(sReg, sBit);	// sendPin High
    interrupts();

	while ( !DIRECT_READ(rReg, rBit) && (total < CS_Timeout_Millis) ) {  // while receive pin is LOW AND total is positive value
		total++;
	}
	//Serial.print("SenseOneCycle(1): ");
	//Serial.println(total);

	if (total > CS_Timeout_Millis) {
		return -2;         //  total variable over timeout
	}

	// set receive pin HIGH briefly to charge up fully - because the while loop above will exit when pin is ~ 2.5V
    noInterrupts();
	DIRECT_WRITE_HIGH(rReg, rBit);
	DIRECT_MODE_OUTPUT(rReg, rBit);  // receivePin to OUTPUT - pin is now HIGH AND OUTPUT
	DIRECT_WRITE_HIGH(rReg, rBit);
	DIRECT_MODE_INPUT(rReg, rBit);	// receivePin to INPUT (pullup is off)
	DIRECT_WRITE_LOW(sReg, sBit);	// sendPin LOW
    interrupts();

#ifdef FIVE_VOLT_TOLERANCE_WORKAROUND
	DIRECT_MODE_OUTPUT(rReg, rBit);
	DIRECT_WRITE_LOW(rReg, rBit);
	delayMicroseconds(10);
	DIRECT_MODE_INPUT(rReg, rBit);	// receivePin to INPUT (pullup is off)
#else
	while ( DIRECT_READ(rReg, rBit) && (total < CS_Timeout_Millis) ) {  // while receive pin is HIGH  AND total is less than timeout
		total++;
	}
#endif
	//Serial.print("SenseOneCycle(2): ");
	//Serial.println(total);

	if (total >= CS_Timeout_Millis) {
		return -2;     // total variable over timeout
	} else {
		return 1;
	}
}

  • Sign in to reply
  • Cancel
  • BigG
    0 BigG over 3 years ago in reply to scottiebabe

    Hard to say. I would've thought it latched until explicitly told otherwise. I'm also using the (opt) directive so that I don't need it for every line.

    Looking at the SDK documentation, it states the following.

    .side_set <count> (opt) (pindirs) directive:

    "If this directive is present, <count> indicates the number of side set bits to be used. Additionally opt may be specified to indicate that a side <value> is optional for instructions (note this requires stealing an extra bit — in addition to the <count> bits — from those available for the instruction delay). Finally, pindirs may be specified to indicate that the side set values should be applied to the PINDIRs and not the PINs. This directive is only valid within a program before the first instruction."

    <instruction> (side <side_set_value>) ([<delay_value>])

    "<side_set_value> is a value to apply to the side_set pins at the start of the instruction. Note that the rules for a side set value via side <side_set_value> are dependent on the .side_set directive for the program. If no .side_set is specified then the side <side_set_value> is invalid, if an optional number of sideset pins is specified then side <side_set_value> may be present, and if a non-optional number of sideset pins is specified, then side <side_set_value> is required. The <side_set_value> must fit within the number of side set bits specified in the .side_set directive."

    Anyway, I've literally just tested the code a few minutes ago and while it behaves differently in that I get much higher count values and when I keep touching the values look different. But it still gives the same results with my sampling algorithm hack in that it correctly confirms that the touch pad was touched etc.

    I'll post a video demo.

    • Cancel
    • Vote Up +1 Vote Down
    • Sign in to reply
    • Verify Answer
    • Cancel
  • scottiebabe
    0 scottiebabe over 3 years ago in reply to BigG

    Thanks again for sharing your experiences on the PIO, I am learning along side you! Interesting perhaps it does, latch... we would see it in the instruction memory. Is it possible to upload the uf2 image and I can probe the pins on my scope. And great work btw! 

    • Cancel
    • Vote Up +1 Vote Down
    • Sign in to reply
    • Verify Answer
    • Cancel
  • BigG
    0 BigG over 3 years ago in reply to scottiebabe

    Thanks. You're welcome. This is great teamwork as you're helping me too.

    I did spot an error though in my original 2 state machine version:

    begin2:
        pull                    ; used as a manual trigger
        nop             side 0  ; Trig Pin write low

    That last "nop side 0" should not have been included. As such it did not provide a full count. Maybe that's why my count values are higher this time round.

    Should be:

    begin2:
        pull                    ; used as a manual trigger
        set pins, 1             ; set Read Pin high as input
        set pindirs, 1          ; set Read Pin as output
        set pins, 1             ; set Read Pin high as input
        set pindirs, 0          ; set Read Pin as input
        nop             side 0  ; Trig Pin write low
        jmp begin2
    

    • Cancel
    • Vote Up +1 Vote Down
    • Sign in to reply
    • Verify Answer
    • Cancel
  • BigG
    0 BigG over 3 years ago in reply to BigG

    Here's the video demo - it's now doing the right things. Just what I was hoping for Relaxed:

    You don't have permission to edit metadata of this video.
    Edit media
    x
    image
    Upload Preview
    image

    • Cancel
    • Vote Up +2 Vote Down
    • Sign in to reply
    • Verify Answer
    • Cancel
  • BigG
    0 BigG over 3 years ago in reply to BigG

    I just created my very first open source public Arduino library on my GitHub account... feel free to give it a try and let me know how it goes.

    github.com/.../PicoCapSense

    • Cancel
    • Vote Up +4 Vote Down
    • Sign in to reply
    • Verify Answer
    • Cancel
  • scottiebabe
    0 scottiebabe over 3 years ago in reply to BigG

    A thousand congratulations to you for creating your first Arduino Library! I think its super cool that it employs a PIO statemachine Slight smile I was able to successfully compile your library and sample ino under platformio using:

    image

    It runs!

    image

    Again super cool! I still need to add some resistors to the pico ... lol

    • Cancel
    • Vote Up +2 Vote Down
    • Sign in to reply
    • Verify Answer
    • Cancel
  • scottiebabe
    0 scottiebabe over 3 years ago in reply to BigG

    That's really neat, I have only used the PIO under uPython and never with the official pio assembler. I have never seen a reference to this functionally in the uPython docs. But you are totally correct!

    image

    So in your example we can see 2 bits being used in the side-set bit field

    image

    The pio instructions are:

    image

    We can see:

    side 0 = 0b10

    side 1 = 0b11

    I need to see what uPython is doing...

    • Cancel
    • Vote Up +3 Vote Down
    • Sign in to reply
    • Verify Answer
    • Cancel
  • BigG
    0 BigG over 3 years ago in reply to scottiebabe

    Thanks for testing on PlatformIO. Very cool to see. This is very much appreciated.

    • Cancel
    • Vote Up +2 Vote Down
    • Sign in to reply
    • Verify Answer
    • Cancel
  • BigG
    0 BigG over 3 years ago in reply to BigG

    Some universal rules are created for a reason... as they never change... and the biggest of all these is... never Assume... if you do it always get in the way.

    So I finally got round to making a few more capacitive sensing touchpads as I had to scrounge around to find suitable resistors to make up the required circa 1Mohms (did not have any) for the transmit side of the sensor. They might not look the prettiest but they work...

    image

    Unfortunately, I could not say the same for my new PicoCapSense library. It currently only works with one capacitive sensor.

    The reason for this (after a fair bit of testing and research) is that the pio_add_program(_pio, &capsense_program); function, which provides the program offset, only works once. The second time that function is called (happens when creating the 2nd or 3rd instance), it creates a panic scenario internally (as per documentation).

    Thankfully I've figured out a work around and it now works. I still need to do some more testing and then I'll update my repository.

    You don't have permission to edit metadata of this video.
    Edit media
    x
    image
    Upload Preview
    image

    • Cancel
    • Vote Up +3 Vote Down
    • Sign in to reply
    • Verify Answer
    • Cancel
  • BigG
    0 BigG over 3 years ago in reply to BigG

    I've updated my GitHub repository with the latest version that will now allow for multiple capsensing.

    github.com/.../PicoCapSense

    • Cancel
    • Vote Up +4 Vote Down
    • Sign in to reply
    • Verify Answer
    • Cancel
<>
element14 Community

element14 is the first online community specifically for engineers. Connect with your peers and get expert answers to your questions.

  • Members
  • Learn
  • Technologies
  • Challenges & Projects
  • Products
  • Store
  • About Us
  • Feedback & Support
  • FAQs
  • Terms of Use
  • Privacy Policy
  • Legal and Copyright Notices
  • Sitemap
  • Cookies

An Avnet Company © 2025 Premier Farnell Limited. All Rights Reserved.

Premier Farnell Ltd, registered in England and Wales (no 00876412), registered office: Farnell House, Forge Lane, Leeds LS12 2NE.

ICP 备案号 10220084.

Follow element14

  • X
  • Facebook
  • linkedin
  • YouTube