This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

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.
  • 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

  • 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
  • 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

  • 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.
  • 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?
  • 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

  • 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?
  • 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.
  • 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

  • I switched to the older version of the SDK and things seem to work fine . I shall try to port it to the newer version and check as well.

    I have a slightly broader question about the PRU's capabilities. I want to drive 3 servo motors using Cortex A8 (or perhaps even A9). I am wondering if I can drive all these motors and receive the encoder feedback to all of them in parallel(or at least switch between them with minimal latency) using only the two PRUs. I believe that there are a few limitations such as the number of eQEP pins available to the PRU etc.

    If this is not possible, what is the best strategy to the same? What is the maximum number of motors that I can run with feedback loops on PRU?

    Thanks,
    Puneeth
  • Puneeth,

    The eQEP pins belong to the eQEP module that is outside of the PRU Subsystem. The PRU code that is controlling the eQEP peripheral in the example (in prupid_fw_1/PRU_IO_1.c) is actually just reading from and writing to the eQEP registers using the PRUs ability to access the full memory space of the SOC.

    The AM335x SOC has 3 eQEP modules (one inside of each PWM subsystems (PWMSS)) in total so you should be able to use one for each of your motors. If you are using the BeagleBone Black however, it appears like only eQEP1 is brought out to the header pins (which is the one that the example uses). The newer BeagleBone Blue though, brings out the pins for all 3 eQEP modules as well as enough PWM signals for 4 motor drivers (motor drivers are also on the board): https://beagleboard.org/blog/2017-03-13-meet-beaglebone-blue/. Schematic is here: https://github.com/beagleboard/beaglebone-blue. Support for the BeagleBone Blue will come from the BeagleBoard community: http://beagleboard.org/discuss

    The maximum number of motors/encoder feedback possible will depend largely on the code that you write for you application. However, with 2 cores running at 200MHz each it seems like driving 3 motors should be well within the capabilities of the PRUs.

    Jason Reeder

  • Hi Jason,
    As you said, the BBB brings out only one eQEP pin, limiting me to just one encoder feedback.
    So, instead, I plan to send a fixed number of pulses using the PWMs available to each of the motors.
    Can I run 4 PWMs at different frequencies in parallel and make each of them stop at different intervals(or after a certain amount of pulses sent) by, say, polling for interrupts? Or is there a better way to control 4 independent motors?

    Thanks,
    Puneeth
  • Puneeth,

    Yes, the PRU can do this by bit-banging its general purpose output pins (which is what you were doing in the beginning of this post right?). However, you will have to write the software to do it.

    The PRU has a cyclecounter register that you can enable that increments each cycle (5ns). You can use this in your code along with some logic to determine if you should toggle each of your 4 general purpose outputs (bit-banged PWMs in your case) by using the R30 register.

    Jason Reeder