Help with the PRU to measure the duration of a pulse

336 views
Skip to first unread message

danji...@gmail.com

unread,
Oct 9, 2013, 10:32:58 AM10/9/13
to beagl...@googlegroups.com
Hello, I would like to know how to use the PRU to measure the duration of a pulse sent by an ultrasonic sensor, I must do
this since Linux is not able to use real hard interrupts, so it won't be able to get acurate data off them.

I would like to know if this is possible using the on board PRU , and where i could find some documentation on them (how to program them, 
how they send data to the beaglebone). I am asking for help since most newbie tutorials are just focused on GPIO and PWM.

Thanks in advance!

rar76

unread,
Jun 27, 2014, 3:14:47 PM6/27/14
to beagl...@googlegroups.com, danji...@gmail.com
hi,

I'll place this info here just for reference.  The code is "rough" and based off the examples.  I was a newbie to this stuff to, and I still am, but I made some progress.

I used the PRU to quickly scan p8_16 for input coming from an IR Sensor (IRM-3438).  The PRU will read the p8_16 at close to 10ns.  After comparing the input to a PWM output, I would say either the PWM has precision issues or the GPIO/PRU can't read at 10ns, but it's still significantly less than 1microsecond, iirc. 

IR wiring:
BBB                             IR Sensor
3.3V_sys -> 100 ohm -> vcc
gnd -> gnd
p8_16 -> 4.7 kOhm -> ir output

Typical output for IRM-3438 with a yk-001 remote:
+      58984      53340
-      59031      53364
+      59066      53316
-      59013      53283
+      59132      53353
-      59005      51042
+      61333      53336
-      59060     165465
+      59151     163160
-      61480     163057
+      61537     165442
-      59152     163270
+      61293     165502
-      59129     165392
+      59225     163179
-      61368     163249
+      61318      53408


Values close to 60000+-10000 are 0's, where values close to 160000+-10000 are 1's.  Start value is 909000 +-10000 is a code start value.  Code size is 64, however all codes for the yk-001 can be used by just looking at the "on" times: 60000 for 0, 160000 for 1, 10000 tolerance. 

Regards,
Rene Robichaud

BB-BONE-PRU-00A0.dts:
/*
* pru dts file BB-BONE-PRU-00A0.dts
*/

/dts-v1/;
/plugin/;

/ {
  compatible
= "ti,beaglebone", "ti,beaglebone-black";

 
/* identification */
  part
-number = "BB-BONE-PRU";
  version
= "00A0";

  exclusive
-use =
   
"pru0",
   
"P8.16";
 
  fragment@0
{
    target
= <&am33xx_pinmux>;
    __overlay__
{
      mygpio
: pinmux_mygpio{
        pinctrl
-single,pins =
       
<
           
0x038 0x2e /* p8_16 input gpio1_14 mode, no pullup/down  */
       
>;
     
};
   
};
 
};

  fragment@1
{
    target
= <&ocp>;
    __overlay__
{
      test_helper
: helper {
        compatible
= "bone-pinmux-helper";
        pinctrl
-names = "default";
        pinctrl
-0 = <&mygpio>;
        status
= "okay";
     
};
   
};
 
};

  fragment@2
{
  target
= <&pruss>;
    __overlay__
{
      status
= "okay";
   
};
 
};
};

pru_p8_16.p:

.origin 0
.entrypoint start

#define GPIO1 0x4804c000
#define GPIO2 0x481ac000
#define GPIO_OE 0x134
#define GPIO_DATAIN 0x138

// Refer to this mapping in the file - \prussdrv\include\pruss_intc_mapping.h
#define PRU0_PRU1_INTERRUPT     17
#define PRU1_PRU0_INTERRUPT     18
#define PRU0_ARM_INTERRUPT      19
#define PRU1_ARM_INTERRUPT      20
#define ARM_PRU0_INTERRUPT      21
#define ARM_PRU1_INTERRUPT      22

#define CONST_PRUCFG         C4
#define CONST_PRUDRAM        C24
#define CONST_PRUSHAREDRAM   C28
#define CONST_DDR            C31

// Address for the Constant table Block Index Register (CTBIR)
#define CTBIR          0x22020

// Address for the Constant table Programmable Pointer Register 0(CTPPR_0)    
#define CTPPR_0         0x22028

// Address for the Constant table Programmable Pointer Register 1(CTPPR_1)    
#define CTPPR_1         0x2202C    



///////////////////////////////////////////////////////////////////////////////
// start
///////////////////////////////////////////////////////////////////////////////

start
:

   
// Enable OCP master port
    lbco    r0
, CONST_PRUCFG, 4, 4
    clr     r0
, r0, 4         // Clear SYSCFG[STANDBY_INIT] to enable OCP master port
    sbco    r0
, CONST_PRUCFG, 4, 4

   
// Configure the programmable pointer register for PRU0 by setting c28_pointer[15:0]
   
// field to 0x0120.  This will make C28 point to 0x00012000 (PRU shared RAM).
    mov     r0
, 0x00000120
    mov     r1
, CTPPR_0
    sbbo    r0
, r1, 0, 4
   
   
// Configure the programmable pointer register for PRU0 by setting c31_pointer[15:0]
   
// field to 0x0010.  This will make C31 point to 0x80001000 (DDR memory).
    mov     r0
, 0x00100000
    mov     r1
, CTPPR_1
    sbbo    r0
, r1, 0, 4
   
   
//Load values from external DDR Memory into Registers R0/R1/R2
   
//lbco      r0, CONST_DDR, 0, 16

   
reset
:
    mov        r1
, 0 // off counter
    mov        r2
, 0 // on counter
    mov        r3
, 0 // period counter
   
// off loop
loop_off
:
    add        r1
, r1, 1 // increment off counter
    qbbc    loop_off
, r31, 14 // while ( r31.t14 == 0 )
   
   
// check to see if arm processor signals exit
    qbbs    
exit, r31, 30 // r31.t30

// on loop    
loop_on
:
    add        r2
, r2, 1 // inc on counter
    qbbs    loop_on
, r31, 14 // while ( r31.t14 == 1 )

send_data
:
   
// store values of registers r0, r1, r2 and r3 into PRU shared RAM
    sbco    r0
, CONST_PRUSHAREDRAM, 0, 32
   
   
// notify program
    mov        r31
.b0, PRU0_ARM_INTERRUPT+16
    jmp        reset
   
exit:
   
// notify program
    mov        r31
.b0, PRU0_ARM_INTERRUPT+16
   
    halt
   

pru_p8_16.c
// modified pru example to read p8_16 at close to 10ns
// Rene Robichaud

#include <stdio.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <string.h>


// Driver header file
#include <prussdrv.h>
#include <pruss_intc_mapping.h>    

#define PRU_NUM      0


#define DDR_BASEADDR         0x80000000
#define OFFSET_DDR             0x00001000
   
#define OFFSET_SHAREDRAM     2048 // 0x00002000
#define ADDEND1          0x98765400u
#define ADDEND2         0x12345678u
#define ADDEND3         0x00000001u
#define ADDEND4         0x87654321u

#define PRUSS0_SHARED_DATARAM    4

static int mem_fd;
static void *ddrMem, *sharedMem;
static unsigned int *sharedMem_uint;
int    g_interrupted = 0;




//=============================================================================

static int user_pru_init( unsigned short pru_num )
{
   
void *DDR_regaddr1, *DDR_regaddr2, *DDR_regaddr3, *DDR_regaddr4;    

   
/* open the device */
    mem_fd
= open( "/dev/mem", O_RDWR );
   
if (mem_fd < 0)
   
{
        printf
( "Failed to open /dev/mem (%s)\n", strerror( errno ) );
       
return -1;
   
}    

   
/* map the DDR memory */
    ddrMem
= mmap( 0, 0x0FFFFFFF, PROT_WRITE | PROT_READ, MAP_SHARED, mem_fd, DDR_BASEADDR );
   
if ( ddrMem == NULL )
   
{
        printf
("Failed to map the device (%s)\n", strerror(errno));
        close
(mem_fd);
       
return -1;
   
}
   
   
/* Store Addends in DDR memory location */
    DDR_regaddr1
= ddrMem + OFFSET_DDR;
    DDR_regaddr2
= ddrMem + OFFSET_DDR + 0x00000004;
    DDR_regaddr3
= ddrMem + OFFSET_DDR + 0x00000008;
    DDR_regaddr4
= ddrMem + OFFSET_DDR + 0x0000000c;

   
*(unsigned int*) DDR_regaddr1 = ADDEND1;
   
*(unsigned int*) DDR_regaddr2 = ADDEND2;
   
*(unsigned int*) DDR_regaddr3 = ADDEND3;
   
*(unsigned int*) DDR_regaddr4 = ADDEND4;

   
return(0);
}

//=============================================================================

static unsigned short user_pru_recv_data( unsigned short pru_num )
{
   
/* Allocate Shared PRU memory. */
    prussdrv_map_prumem
( PRUSS0_SHARED_DATARAM, &sharedMem );
    sharedMem_uint
= (unsigned int*) sharedMem;
   
   
return 1;

}

//=============================================================================

int main( int argc, char* argv[] )
{
   
unsigned int ret;
    tpruss_intc_initdata pruss_intc_initdata
= PRUSS_INTC_INITDATA;
   
int i;
   
int update = 0;
       
    printf
("\nINFO: Starting %s example.\r\n", "PRU_p8_12");
   
/* Initialize the PRU */
    prussdrv_init
();        
   
   
/* Open PRU Interrupt */
    ret
= prussdrv_open( PRU_EVTOUT_0 );
   
if (ret)
   
{
        printf
("prussdrv_open open failed\n");
       
return (ret);
   
}
   
   
/* Get the interrupt initialized */
    prussdrv_pruintc_init
(&pruss_intc_initdata);

   
/* Initialize example */
    printf
("\tINFO: Initializing example.\r\n");
    user_pru_init
( PRU_NUM );
   
   
/* Execute example on PRU */
    printf
("\tINFO: Executing example.\r\n");
   
   
// EXECUTE
    prussdrv_exec_program
(PRU_NUM, "./pru_p8_16.bin");
   
   
     
/* Wait until PRU0 has finished execution */
    printf
("\tINFO: Waiting for HALT command.\r\n");
   
   
   
while ( !g_interrupted )
   
{
       
// wait for interrupt
        prussdrv_pru_wait_event
( PRU_EVTOUT_0 );
        prussdrv_pru_clear_event
( PRU_EVTOUT_0, PRU0_ARM_INTERRUPT );
       
       
// process pru shared memory
        user_pru_recv_data
( PRU_NUM );
       
        update
= !update;
        printf
( "%c ", update ? '+' : '-' );
       
for ( i = 1; i < 3; i++ )
       
{
           
           
            printf
( "%10u ", sharedMem_uint[ OFFSET_SHAREDRAM + i ] );
           
       
}
       
        printf
( "\n" );
   
}
   
   
    prussdrv_pru_wait_event
( PRU_EVTOUT_0 );
    prussdrv_pru_clear_event
( PRU_EVTOUT_0, PRU0_ARM_INTERRUPT );
   
   
   
   
/* Disable PRU and close memory mapping*/
    prussdrv_pru_disable
( PRU_NUM );
    prussdrv_exit
();
    munmap
( ddrMem, 0x0FFFFFFF );
    close
( mem_fd );

   
return 0;
}






 

TJF

unread,
Jun 28, 2014, 11:23:06 AM6/28/14
to beagl...@googlegroups.com, danji...@gmail.com
Find infos on how to use the PRUSS in the PRU FAQ.

I'd try the inbuild eCAP device. It's connected to header P9_42, mode 3 (pr1_ecap0_ecap_cap_in_apwm_o).
Reply all
Reply to author
Forward
0 new messages