Linux/PRU-SWPKG: PRU PWM issue

Part Number: PRU-SWPKG

Tool/software: Linux

I am trying to send a pulse of width 100 clock cycles using PRU on my BeagleBone Black through P8_11. In my main.c file I have added a callback for pin P8_10 for a rising edge.

If I disable the outer loop and send the pulse only once, I am not registering anything in my callback function. If the outerloop is enabled, the program freezes.

Is there anything wrong in my approach? Are there any working examples trying to do the same?

Thanks.

/* PRU PWM CODE

Send pulse of width 100 clock cycles every 1000 clock cycles.
*/
// Start of program
.origin 0

// Delay in between high and low
mov r1, 10
// Number of pulses to send
mov r2, 1000

// Loop here
outloop:
    // Set high
    set r30, r30, 15

    // wait for sometime here
    delay:
	sub r1, r1, 1
	qbne delay, r1, 0

    // Set low
    clr r30, r30, 15
    sub r2, r2, 1
    qbne outloop, r2, 0

// We are done, send interrupt
mov r31.b0, 19 + 16

// Halt, otherwise PWM runs continuously
halt

  • The PRU experts have been notified. They will respond here.
    Best Regards
    Biser

    Note:  If this answer solves your question please click the "Verify Answer"  button.

  • In reply to Biser Gatchev-XID:

    Do you have a logic analyzer to see what is happening externally on P8-11?

    I don't see anywhere in your assembly code where you are reloading the value of r1 with 10. So, either r1 will remain 0 and your inner loop will get bypassed very quickly, or r1 will roll to 0xffffffff and it will take ~21.5 seconds before r1 decrements down to 0 again on each of your loops (I think this is what will happen).

    Also, I'm not sure if it is the copy and pasting, but your 'delay:' label should not be indented or it will not be recognized as a label.

    Jason Reeder

  • In reply to Jason Reeder:

    Thanks Jason.

    I was doing a few other things wrong as well. Fixed them and now I am getting a neat 1000 pulses out.

    I have a followup question:

    I have connected a servo encoder on P8_10, and I want to receive and count the encoder ticks there.

    If I setup a normal callback using add_edge_detect (not through the PRU but the normal C program) I don't get any ticks as the frequency is too high. Is there any way that I can get the value using PRU#1? Also, will I be able to run both PRUs in parallel?

    P.S: Posting the new code for reference:

    // Start of program
    .ORIGIN 0
    
    MOV R2, 1000
    TOP:
    
    // Set high P9_27
    SET R30.t5 
    
    // wait for sometime here
    MOV R1, 1163
    HIDELAY: 
    SUB R1, R1, 1 
    QBNE HIDELAY, R1, 0
    
    // Set low
    CLR R30.t5
    SUB R2, R2, 1
    
    // wait for low here
    MOV R1, 1163
    LOWDELAY:
    SUB R1, R1, 1
    QBNE LOWDELAY, R1, 0
    
    // Repeat from top
    QBNE TOP, R2, 0
    
    // We are done, send interrupt
    MOV R31.B0, 19 + 16
    
    // Halt, otherwise PWM runs continuously
    HALT
  • In reply to Puneeth Bandikatla:

    Glad to hear you got the bit-banged PWM portion working!

    While the PRU can bit-bang these specialized functions, there are dedicated peripherals on the AM335x devices that are built to do the types of things that you are trying to implement. A simple PWM signal can be made by using the PWM mode of the eCAP peripheral that is inside the PRU subsystem. Also, you can have the PRU control the eQEP (enhanced quadrature encoder pulse) module in order to count your encoder ticks.

    Please see this TI Design that actually does both of those things (generating a PWM and reading a quadrature encoder using the PRUs): http://www.ti.com/tool/TIDEP0073

    The design guide will explain the demo: http://www.ti.com/lit/pdf/tidubj6

    The source code is also provide on that page and here: http://www.ti.com/lit/zip/tidcc20

    Yes, both PRUs can run completely in parallel and that is shown in the TI Design I mentioned.

    Jason Reeder

  • In reply to Jason Reeder:

    Thanks Jason,
    Got most things setup using the SDK. But when I start the pru_pid_server, all it says is "Invalid RPMsg file. Exiting", meaning the /dev/rpmsg_pru%s file is not being created.
    I have connected the BBB to my Linux host using a USB cable and have established an ethernet connection using the same.
  • In reply to Puneeth Bandikatla:

    The server started working once I reinstalled the kernel with RPMsg Support (processors.wiki.ti.com/.../RPMsg_Quick_Start_Guide). The server now prints some data on stdout and using my web browser I can view the graph and set the values for set point, Kp, Ki, Kd etc. Yet the motor is not moving, nor is the graph updating..
    Am I missing something? Is there some way to test if the PRU is working?
  • In reply to Puneeth Bandikatla:

    You can see the /dev/rpmsg_pruX devices now correct? Are you able to see the PWM signal on the pin connected to the motor (using your logic analyzer)?

    You used the Processor SDK version listed in the design guide right?

    Jason Reeder

  • In reply to Jason Reeder:

    I think I used the latest SDK Version (03.03.00.04) but except for the change in environment variables everything compiled smoothly.
    I'll briefly outline my process. Let me know if I am going wrong somewhere:
    1. Ran make using default config and compiled zImage and device tree overlay
    2. Ran create-sdcard.sh and used precompiled image.
    3. Copied zImage and the dtb file to /boot/
    4. Compiled prupid_fw_0.c and prupid_fw_1.c and copied them to /lib/firmware/pru folder. Copied the server files to /usr/share/matrix_gui~/
    5. Updated symbolic links to point to to the copied files.
    6. Popped the memory card in the BBB and started it up. ( eMMC is disabled and BBB is definitely running from the SDCard.)
    7. Not getting any signals on the pin.

    Also, is there any way to check if the .out file placed in /lib/firmware/pru folder is running on start up?
  • In reply to Puneeth Bandikatla:

    Something weird is happening with RPUMsg. The first time I start beaglebone after compiling the kernel with RPUMsg support. both /dev/rpmsg_pruX are visible. But if I restart the BBB, they go away and only after I recompile everything and load it on the SD card am I able to view them.
    Is this possibly a bug?
    I have also tried running the first, basic example from the hands-on labs and even that doesn't seem to work.
  • In reply to Puneeth Bandikatla:

    Puneeth,

    The code provided in that TI Design was validated against the 2.0.2.11 version of the Linux Processor SDK (as specified in the design guide). It is not guaranteed to work (without modification) with any other version of the SDK.

    Between the 2.0.2.11 release and the current 3.3.0.4 release, there have been changes to the default device tree as well as the way that rpmsg works between the PRU and the ARM core.

    If you want to run the 3.3.0.4 SDK then you will need to (1) make sure that there are no pin conflicts after the device has booted and also (2) port the RPMsg code that is running on pru1 to build against the updated rpmsg_lib 

    (1) type 'dmesg | grep pinctrl' at the command prompt after booting and make sure there are no conflicts reported

    (2) start with the pru1 code provided in the TI design and replace the resource_table with the one from 'ti-processor-sdk-linux-am335x-evm-03.03.00.04/example-applications/pru-icss-5.1.0/examples/am335x/PRU_RPMsg_Echo_Interrupt1/resource_table_1.h'. You'll also need to change the makefile to build against the newer rpmsg library (export PRU_CGT=${HOME}/ti-processor-sdk-linux-am335x-evm-03.03.00.04/linux-devkit/sysroots/x86_64-arago-linux/usr/share/ti/cgt-pru). Then you'll need to update the RPMsg pieces in the PRU_IO_1.c file to match the RPMsg pieces in the 'ti-processor-sdk-linux-am335x-evm-03.03.00.04/example-applications/pru-icss-5.1.0/examples/am335x/PRU_RPMsg_Echo_Interrupt1/main.c' file

    Jason Reeder