Debouncing PRU Input on AM5728

On the AM5728 (Beagle X-15) I have performed pin muxing to change pin vin1a_d6 to pr1_pru0_gpi3 (attaches to external push button), and gpio4_8 to pr1_pru1_gpo4 (attaches to external LED). Using a combination of code from the TI trainings I have set up a scenario that will turn the LED on and off when the button is pushed. RPMsg is also enabled and sends a message to the device driver saying whether the button is pushed or released.

Currently I debounce with using a large delay [__delay_cycles(100000000)]. The problem with this is that the response time is too slow for my desired functionality however, reducing the delay time causes the remoteproc to either completely freeze and require a restart or loses all functionality and doesn’t register the button push at all.

I am new to embedded systems and PRU, and am unsure if this is a PRU/RPMsg problem or a debouncing issue. I have tried different types of debouncing methods and it doesn’t improve the situation. Is there a specific method to debounce PRU inputs or is there any advice to improving the speed of my input/output response.

Attached the code (2 files that work across remoteproc4 and 5)

#include <stdint.h>

#include <pru_cfg.h>

/*TODO: Include intc.h */

#include <pru_intc.h>

// PRU Core 1

#define PRU1

volatile register uint32_t __R30;

volatile register uint32_t __R31;

/* Defines */

#define PRU0

/* PRU0-to-PRU1 interrupt */

#define PRU0_PRU1_EVT (16)

#define PRU0_PRU1_TRIGGER (__R31 = (PRU0_PRU1_EVT - 16) | (1 << 5))

/* SW1 offset */

/*TODO: Define GPI offset for SW1 */

#define SW1 (1 << 3)

/* INTC configuration

  • We are going to map User event 16 to Host 1

  • PRU1 will then wait for r31 bit 31 (designates Host 1) to go high

  • */

void configIntc(void)

{

/* Clear any pending PRU-generated events */

__R31 = 0x00000000;



/* Map event 16 to channel 1 */

CT_INTC.CMR4_bit.CH_MAP_16 = 1; /*TODO: Select correct bit field and enter proper value */;



/* Map channel 1 to host 1 */

CT_INTC.HMR0_bit.HINT_MAP_1 = 1; /*TODO: Select correct bit field and enter proper value */;



/* Ensure event 16 is cleared */

CT_INTC.SICR = 16; /*TODO: Clear proper event */;



/* Enable event 16 */

CT_INTC.EISR = 16; /*TODO: Enable proper event */;



/* Enable Host interrupt 1 */

CT_INTC.HIEISR |= (1 << 0); /*TODO: Enable proper event */;



// Globally enable host interrupts

CT_INTC.GER = 1; /*TODO: Enable global events */;

}

void main(void)

{

/* Configure GPI and GPO as Mode 0 (Direct Connect) */

CT_CFG.GPCFG0 = 0x00000;



/* Clear GPO pins */

__R30 &= 0xFFFF00000;



/* Configure INTC */

configIntc();



while (1) {

    if ((__R31 & SW1) != SW1) {

        __delay_cycles(100000000);

        PRU0_PRU1_TRIGGER;

    }

}

}

#include <stdint.h>

#include <stdio.h>

#include <pru_cfg.h>

#include <pru_intc.h>

#include <rsc_types.h>

#include <pru_rpmsg.h>

#include “resource_table.h”

#include “intc_map_1.h”

#include <stdbool.h>

#include <string.h>

volatile register uint32_t __R30;

volatile register uint32_t __R31;

#define HOST1_MASK (0x80000000)

#define LED_ON (__R30 |= (1 <<4))

#define LED_OFF (__R30 &= ~(1 << 4))

//RPMsg variables

#define TO_ARM_HOST 18

#define FROM_ARM_HOST 19

#define CHAN_NAME “rpmsg-pru”

#define CHAN_PORT 31

#define CHAN_DESC “Channel 31”

#define VIRTIO_CONFIG_S_DRIVER_OK 4

bool RPMessage=true;

//Debounce variables

int pressed = 0;

int pressed_conf_lvl = 0;

int released_conf_lvl = 0;

//Push button debouncing

volatile bool buttonPressed;

void main(void)

{

struct pru_rpmsg_transport transport;

uint16_t src=1024, dst=31;

volatile uint8_t *status;



/* Initialise RPMsg messages depending on switch state*/

char switch_press[20];

uint16_t closed_len = 9;

memcpy(switch_press, "LED on \n", closed_len);



char switch_release[20];

uint16_t open_len = 10;

memcpy(switch_release, "LED off \n", open_len);





/* Allow OCP master port access by the PRU so the PRU can read external memories */

CT_CFG.SYSCFG_bit.STANDBY_INIT = 0;



/* Clear the status of the PRU-ICSS system event that the ARM will use to 'kick' us */

CT_INTC.SICR_bit.STATUS_CLR_INDEX = FROM_ARM_HOST;



/* Make sure the Linux drivers are ready for RPMsg communication */

status = &resourceTable.rpmsg_vdev.status;



while (!(*status & VIRTIO_CONFIG_S_DRIVER_OK));



/* Initialize the RPMsg transport structure */

pru_rpmsg_init(&transport, &resourceTable.rpmsg_vring0, &resourceTable.rpmsg_vring1, TO_ARM_HOST, FROM_ARM_HOST);



/* Create the RPMsg channel between the PRU and ARM user space using the transport structure. */

while (pru_rpmsg_channel(RPMSG_NS_CREATE, &transport, CHAN_NAME, CHAN_DESC, CHAN_PORT) != PRU_RPMSG_SUCCESS);





while (1) 

{

    

    //Check if interrupt set to HOST 1 from switch

    if (__R31 & HOST1_MASK) 

    {

        //if interrupt detected increment press confidence

        pressed_conf_lvl ++;



        //reset release as a press is detected

        released_conf_lvl = 0;

        //threshold for debounced press

        if (pressed_conf_lvl >= 10)

        {

            if (pressed == 0)

            {

                //Send RPMsg that LED is off and turn LED off

                pru_rpmsg_send(&transport, dst, src, switch_press, closed_len); 

                LED_ON;

                pressed = 1;

                //flag that a message has been sent

                RPMessage = true;

            }

        }

    }

    else

    {

        released_conf_lvl ++;



        if (released_conf_lvl >= 10)

        {   

            //Send message that switch is closed, LED will turn on

            if(!RPMessage)

            {

                //Send message that LED on and turn LED on

                pru_rpmsg_send(&transport, dst, src, switch_release, open_len);

                LED_OFF;



                //Flag that message has been sent

                RPMessage=true;

            }

            else

            {

                RPMessage=false;

            }



            pressed = 0;

            released_conf_lvl = 0;

            pressed_conf_lvl = 0;

        }

    }

//Clear interrupts from switch and RPMsg

CT_INTC.SICR = 16; 

CT_INTC.SICR_bit.STATUS_CLR_INDEX = FROM_ARM_HOST;  



//Delay loop otherwise reading device file crashes PRU

__delay_cycles(1000000000); 

}

}

Much easier to use external resistor/capacitor for debounce, however as a quick and dirty debounce assuming < 10ms resolution is not needed I normally just poll the switch inputs at a slow rate, that is longer than the debounce period.

A good switch will have debounce of less than 5ms, so polling at around 10ms is usually fine. Then you just look for 2 consecutive readings that are the same and that is the current state of the switch. This means the switch needs to be closed for at least 30ms to be seen, which for a push button is fine.

If you want to force slower button presses you can just increase the consecutive reading count.

1 Like