uio_pruss.c question

1,149 views
Skip to first unread message

Christopher Piggott

unread,
Feb 15, 2012, 6:29:16 PM2/15/12
to Beagle Board

Can somebody explain to me what this code snippet does? It's from the
uio_pruss.c driver. It looks like, for each event channel, it
establishes two separate memory regions for each event channel,
(which I think is a uio_mem) ... but that every event channel gets the
SAME two. What's the point of mapping once per event channel?



for (cnt = 0, p = gdev->info; cnt < MAX_PRUSS_EVT; cnt++, p++)
{
p->mem[0].addr = regs_prussio->start;
p->mem[0].size = resource_size(regs_prussio);
p->mem[0].memtype = UIO_MEM_PHYS;
p->mem[1].size = sram_pool_sz;
p->mem[1].memtype = UIO_MEM_PHYS;

p->mem[2].addr = gdev->ddr_paddr;
p->mem[2].size = extram_pool_sz;
p->mem[2].memtype = UIO_MEM_PHYS;

p->name = kasprintf(GFP_KERNEL, "pruss_evt%d", cnt);
p->version = DRV_VERSION;

/* Register PRUSS IRQ lines */
p->irq = gdev->hostirq_start + cnt;
p->handler = pruss_handler;
p->priv = gdev;

ret = uio_register_device(&dev->dev, p);
if (ret < 0)
goto out_free;
}

Bas Laarhoven

unread,
Feb 15, 2012, 6:56:28 PM2/15/12
to beagl...@googlegroups.com, Christopher Piggott

Hi Christopher,

I've been wondering myself about this implementation too. If you look at
this code (and at an older version) you'll see that the second (mem[1])
region used to point to on-chip SRAM, for which there is no
implementation for the 335x (yet?). It looks like someone just removed
the line with the p->mem[1].addr assignment and a leading blank line. So
I'm not sure about the state of this driver...

FYI: If you tweak the right registers the PRUSS can be used and the old
pasm produces working code. I've been able to modulate ('glow') one of
the user leds, depending on the system load. So communcation from user
space to a PRU and from that PRU to GPIO can be done. But beware, the
PRU - like a DMA controller - has access to almost the entire memory
map, and it's very easy to overwrite kernel code or other data by mistake.

--- Bas

Christopher Piggott

unread,
Feb 15, 2012, 8:05:13 PM2/15/12
to Beagle Board
Oh, wow, I didn't even notice that there were THREE memory sections
defined in there.

It would help me if I could figure out what these two things return:

p->mem[0].addr = regs_prussio->start;
p->mem[0].size = resource_size(regs_prussio);

I guess I assume that regs_prussio is the global address in L3. I'm
wondering if resource_size(regs_prussion) returns enough that I can
see all the control registers, IRAM0, IRAM1, DMEM0, DMEM1, and the
SHARED 12K of data memory.

By tweaking registers, do you have to tweak registers in order to get
the old pasm to work? Reports are that a pasm_2 is going to be
released to developers in March some time, but I would like to get
started now if at all possible.

I'm really happy to know somebody besides me is thinking about these
things.

Christopher Piggott

unread,
Feb 15, 2012, 8:12:50 PM2/15/12
to Beagle Board
Another question. The IRQ handler does this:

/* Disable interrupt */
iowrite32(intr_bit, intrdis_reg);
return IRQ_HANDLED;

What does this mean - does the userspace side have to turn the
interrupt back on if it wishes?

Bas Laarhoven

unread,
Feb 16, 2012, 4:15:51 AM2/16/12
to beagl...@googlegroups.com, Christopher Piggott
On 16-2-2012 2:05, Christopher Piggott wrote:
> Oh, wow, I didn't even notice that there were THREE memory sections
> defined in there.
>
> It would help me if I could figure out what these two things return:
>
> p->mem[0].addr = regs_prussio->start;
> p->mem[0].size = resource_size(regs_prussio);
This looks like the io map for the PRUSS submodule. It spans all PRUSS
registers and memories. See 4.3.2 in the TRM.
The other maps aren't needed to get the PRUSS working. But if some of
the global settings are wrong (depends on the kernel you're using)
you'll need access to some other parts of the chip to get the PRUSS
running...

>
> I guess I assume that regs_prussio is the global address in L3. I'm
> wondering if resource_size(regs_prussion) returns enough that I can
> see all the control registers, IRAM0, IRAM1, DMEM0, DMEM1, and the
> SHARED 12K of data memory.
IIRC the region size is (correctly) set to 16K / $4000.

>
> By tweaking registers, do you have to tweak registers in order to get
> the old pasm to work? Reports are that a pasm_2 is going to be
> released to developers in March some time, but I would like to get
> started now if at all possible.

No, the old pasm just works. You'll need to tweak some settings to
enable the PRUSS submodule, give it a clock, clock the outgoing bus, set
some power management options. It's a steep learning curve but it can be
done ;-)

>
> I'm really happy to know somebody besides me is thinking about these
> things.
>

There are more. I can't image all the others have given up already, so
ask your questions and you might get an answer.

--- Bas

Christopher Piggott

unread,
Feb 16, 2012, 7:14:07 AM2/16/12
to Beagle Board
>There are more. I can't image all the others have given up already, so
>ask your questions and you might get an answer.

OK. What if you want to use the two PRUs to do two totally different
things, with two separate userspace drivers? Does this driver allow
that?

Bas Laarhoven

unread,
Feb 16, 2012, 7:46:35 AM2/16/12
to beagl...@googlegroups.com, Christopher Piggott

First of all, it's (uio_pruss.c) not really a driver. The only thing it
does is to make the PRUSS I/O space available for a userspace driver.
The latter has to be written by you and takes complete control over the
PRUSS (i.e. both PRUs). You should also be able to get events from the
PRUSS to userspace, but I haven't tried that yet.

So yes, you should be able to run two independent userspace drivers, but
you might run into problems accessing the parts that are shared by both
PRUs (locking, atomic access, synchronization etc.).

--- Bas

Christopher Piggott

unread,
Feb 16, 2012, 8:14:55 AM2/16/12
to Beagle Board
Ah, yes. That makes sense.

I am going to think about the idea that UIO isn't what I want here,
and do a more traditional kernel device driver. What I have to do is
integrate four high speed A/D converters for structural vibration
analysis. I like the UIO concepts of handling interrupts (events) and
mmap() but what I'm thinking is maybe it needs to be something smart
enough to enforce mutual exclusion of shared register access, as you
alluded to.

I'll have to give this some more thought.

>You'll need to tweak some settings to enable the PRUSS submodule, give it a clock, clock the outgoing bus, set some power management options.

If I may clarify that, in uio_pruss.c, should this take care of
powering it on and configuring the clock?

/* Power on PRU in case its not done as part of boot-loader */
gdev->pruss_clk = clk_get(&dev->dev, "pruss");
if (IS_ERR(gdev->pruss_clk)) {
dev_err(&dev->dev, "Failed to get clock\n");
kfree(gdev->info);
kfree(gdev);
ret = PTR_ERR(gdev->pruss_clk);
return ret;
} else {
clk_enable(gdev->pruss_clk);
}

On the PRU wiki exists a kernel patch that touches these files (just
the source files)

* arch/arm/mach-davinci/da850.c b/arch/arm/mach-davinci/da850.c
* arch/arm/mach-davinci/devices-da8xx.c
* arch/arm/mach-davinci/include/mach/da8xx.h
* drivers/uio/uio_pru.c

However, those are all for different devices - I'm working on AM3359
whose arch is I believe mach-omap2. What I'm not sure of is whether
or not that machine type somehow inherits from davinci.

Looking at that patch in detail a lot of what it does is add platform
resources. I don't see that in my kernel, and I'm going to have to
figure that out.

$ grep -R platform_device_register arch/arm/* | grep -i pru

returns nothing, making me think the support isn't there, and I may
have to make my own patch that does what the davinci one does.

Does this sound like the right track?

Bas thank you so much for your help and advice.

--C











Christopher Piggott

unread,
Feb 16, 2012, 8:23:30 AM2/16/12
to Beagle Board
I think I found it.

arch/arm/mach-omap2/clock3xxx_data.c

defines a bunch of clocks ... but it looks like none for the PRU
subsystem. I'm working off of a kernel named

linux-3.0+3.1-rc8-psp04.06.00.02.sdk-psp04.06.00.02.sdk

from the T.I. SDK, I think my next step better be to check newer
kernels from angstrom and see if any of this has been changed/
augmented.

Bas Laarhoven

unread,
Feb 16, 2012, 8:37:23 AM2/16/12
to beagl...@googlegroups.com, Christopher Piggott
On 16-2-2012 14:14, Christopher Piggott wrote:
> Ah, yes. That makes sense.
>
> I am going to think about the idea that UIO isn't what I want here,
> and do a more traditional kernel device driver. What I have to do is
> integrate four high speed A/D converters for structural vibration
> analysis. I like the UIO concepts of handling interrupts (events) and
> mmap() but what I'm thinking is maybe it needs to be something smart
> enough to enforce mutual exclusion of shared register access, as you
> alluded to.
>
> I'll have to give this some more thought.
>
>> You'll need to tweak some settings to enable the PRUSS submodule, give it a clock, clock the outgoing bus, set some power management options.
> If I may clarify that, in uio_pruss.c, should this take care of
> powering it on and configuring the clock?
>
> /* Power on PRU in case its not done as part of boot-loader */
> gdev->pruss_clk = clk_get(&dev->dev, "pruss");
> if (IS_ERR(gdev->pruss_clk)) {
> dev_err(&dev->dev, "Failed to get clock\n");
> kfree(gdev->info);
> kfree(gdev);
> ret = PTR_ERR(gdev->pruss_clk);
> return ret;
> } else {
> clk_enable(gdev->pruss_clk);
> }

There are several bits that need to be set correctly. This may solve the
clock issue, but I just tried with a recent the 3.2.0+ kernel and the
PRUSS is left with the reset asserted, so you'll only get bus errors
accessing the PRUSS I/O map. Also, if you want to access peripherals
that are not connected to the PRU, you'll have to enable the clock for
the outgoing bus first.

>
> On the PRU wiki exists a kernel patch that touches these files (just
> the source files)
>
> * arch/arm/mach-davinci/da850.c b/arch/arm/mach-davinci/da850.c
> * arch/arm/mach-davinci/devices-da8xx.c
> * arch/arm/mach-davinci/include/mach/da8xx.h
> * drivers/uio/uio_pru.c
>
> However, those are all for different devices - I'm working on AM3359
> whose arch is I believe mach-omap2. What I'm not sure of is whether
> or not that machine type somehow inherits from davinci.
>
> Looking at that patch in detail a lot of what it does is add platform
> resources. I don't see that in my kernel, and I'm going to have to
> figure that out.
>
> $ grep -R platform_device_register arch/arm/* | grep -i pru
>
> returns nothing, making me think the support isn't there, and I may
> have to make my own patch that does what the davinci one does.
>
> Does this sound like the right track?

There's a lot of work in progress wrt the arm port. But little
documentation and it's a moving target.
If you have a schedule to meet I suggest you skip all the nice clock
setting schemes that are being implemented and do direct access to the
corresponding registers from a kernel driver.

--- Bas

Bas Laarhoven

unread,
Feb 16, 2012, 8:43:39 AM2/16/12
to beagl...@googlegroups.com
Good starting point. I started with the TI kit too and moved to the
angstrom kernel only recently. I found development in the oe tree a
challenge and didn't notice any progress on the PRUSS code. So I might
switch back to the TI kernel again.

--- Bas

Christopher Piggott

unread,
Feb 16, 2012, 11:57:23 AM2/16/12
to Beagle Board
I hope this isn't a really dumb question but ...

Why do I really need the userspace loader to load the PRU's IMEM? Why
can't I have an appropriately privileged program open /dev/mem and
mmap() to the global address of the PRUSS in L3, then just write the
PRU program directly to IMEM that way?

Daniel Chisholm

unread,
Feb 16, 2012, 12:16:14 PM2/16/12
to Beagle Board


On Feb 15, 9:05 pm, Christopher Piggott <cpigg...@gmail.com> wrote:
>
> I'm really happy to know somebody besides me is thinking about these
> things.

Sorry that I don't have anything to contribute at the moment but I
thought I should speak up and let you know that you have at least one
very, very interested lurker.

Evaluating the PRU's capabilities is my #1 priority for my Beaglebone
work and I am quite excited that it might be able to do some really
great things for me. So threads like this, which will help me find
tools and modules, are just pure gold as far as I am concerned.

(I might as well mention what I have in mind, just in case anybody has
some clever suggestions for me. I would like to program one PRU core
to poll a small number of input bits (5-20) at maximum possible rate.
Whenever there is a change in any one of these bits I would want to
record the bits plus a timestamp from the TCRR register (perhaps the
other PRU will pick these up, or perhaps the AM3359 will). These
input bits won't change very often (only a few times a second each),
but I would like to be able to get sub-microsecond timestamping of
when the changes happen.)

Jerrill

unread,
Apr 14, 2012, 12:07:42 AM4/14/12
to beagl...@googlegroups.com, Christopher Piggott
Bas and Christopher,

I'm just getting started with the BeagleBone PRUSS. I'm running kernel version 3.2.14 and have installed the uio_pruss kernel module. 

I use the following to enable the PRUSS:

devmem2 0x44E00C00 w 0

And I can kind of run the GPIO toggling demo code provided on the TI web site. (i.e. I'm no longer getting a segfault, just a hang!) I made a PRUSS binary with only a single instruction (HALT) in it for debugging because the application kept hanging "waiting for HALT". After some debugging I found that the following read statement is blocking in prussdrv.c waiting for values to read from /dev/uio0.

int prussdrv_pru_wait_event(unsigned int pru_evtout_num)
{
    int event_count;
    unsigned int *pruintc_io = (unsigned int *) prussdrv.intc_base;
    read(prussdrv.fd[pru_evtout_num], &event_count, sizeof(int));
    pruintc_io[PRU_INTC_HIEISR_REG >> 2] = pru_evtout_num+2;
    return 0;
}

I'm still in the process of figuring out what I need to learn to resolve the issue, but obviously when the HALT instruction is executed (if it is even being executed) there is nothing being returned on /dev/uio0 and the read blocks.

So many questions...

1) Am I even on the right track? 

2) Or is there a better way to approach this thing? 

3) Is this code even compatible with the uio_pruss kernel module that is available via opkg?

# opkg list | grep pru  
kernel-module-uio-pruss - 3.2-r9a+gitr09e9651bcf2ee8d86685f2a8075bc6557b1d3b91 - linux-ti33x-psp version 3.2-r9a+gitr09e9651bcf2ee8d86685f2a8075bc6557b1d3b91
 uio-pruss kernel module

Thanks for your input.
Jerrill

Kyle Manna

unread,
Apr 14, 2012, 8:38:53 AM4/14/12
to beagl...@googlegroups.com
Hi Jerrill,

I had set the uio_pruss stuff before I switched to working with my code completely in the kernel, so I haven't worked with the uio_pruss driver in a while.

The place where you are most certainly stuck has to do with the IRQs not being setup correctly.  If I remember correctly, TI's demo firmware has a number of demos that does some stuff, sends an IRQ to the Cortex-A8 and then halts.  Your code is waiting for the IRQ, which it sounds like you aren't setting up as you just are sending the halt instruction.

The code you shared above is doing a blocking read on the uio driver waiting for an IRQ ("PRU event") which doesn't happen.

So, it sounds like you need to do one of two things:
1) Configure the INTC (it looks more complicated then it really is at first glance) and update your PRU firmware to trigger an IRQ.
2) Look at the run status of the PRU core you are running on and see if it has changed from run to stop state from your HALT instruction.  You can view this RUNSTATE in the CONTROL register which is a part of the PRUSS_PRU)CTRL registers (section 4.5.4.1 in the TRM).

- Kyle

-- To join: http://beagleboard.org/discuss
To unsubscribe from this group, send email to:
beagleboard...@googlegroups.com
Frequently asked questions: http://beagleboard.org/faq

Christopher Piggott

unread,
Apr 14, 2012, 9:01:11 AM4/14/12
to beagl...@googlegroups.com, Christopher Piggott




On Saturday, April 14, 2012 12:07:42 AM UTC-4, Jerrill wrote:

1) Am I even on the right track? 
 
I think so.  My advice though is to ignore the events/interrupts for now and start with something much simpler - a PRU program that runs by itself, with no external requirements, that you can load, start, stop, and then inspect what it has done.  Maybe you are already past this point, in which case you should ignore me.  However, if you're not, just try something like this:

start:
        MOV32 r1, 0
l1:
        // Increment r1
        ADD r1, r1, 1
        JMP     l1

then use devmem2 to just see that r1 is counting up (at a very high rate).  If you haven't already done that, I'd start there first.
 
3) Is this code even compatible with the uio_pruss kernel module that is available via opkg?

I believe so.  The main issue I had was taking the PRUSS completely out of reset when the driver is loaded.  There were three ways to fix this: work around it with something like devemem2; use the patch jason w. and I made; or do it the way Vaibhav did it - which means a fix to the machine definition in the kernel, that causes everything to turn on and get into the right state as soon as uio_pruss.ko tries to grab the clock.

Where I can't help you with is whether or not that change has made it into an OE, TI, or some other kernel.

It shouldn't stop your development, though - you can work around it with devmem2 or something similar for now (you could even have your userspace program do it if you're willing to mmap the right place in physical memory - not a good long term solution but if it gets you going during development...)

I hope that helps.  If not, write back.


Bas Laarhoven

unread,
Apr 14, 2012, 9:19:14 AM4/14/12
to beagl...@googlegroups.com
Make sure whether you really need an interrupt. There are other ways to signal a process in user space. I'm using fifo's and shared memory right and have no need for interrupts up to now.

-- Bas


2) Or is there a better way to approach this thing? 

3) Is this code even compatible with the uio_pruss kernel module that is available via opkg?

# opkg list | grep pru  
kernel-module-uio-pruss - 3.2-r9a+gitr09e9651bcf2ee8d86685f2a8075bc6557b1d3b91 - linux-ti33x-psp version 3.2-r9a+gitr09e9651bcf2ee8d86685f2a8075bc6557b1d3b91
 uio-pruss kernel module

Thanks for your input.
Jerrill

Christopher Piggott

unread,
Apr 14, 2012, 10:40:40 AM4/14/12
to beagl...@googlegroups.com
One thing I want to add to what Bas said: holding it in reset was one
problem I had, but there was another. It also was leaving the L3
interconnect i some kind of "smart" state that made it so that if your
PRU program tried to access global resources over L3 (or L3 to L4) it
would just hang the PRU indefinitely. This is something else to watch
out for, but it won't be an issue if your PRU software doesn't use
these kinds of resources (for example main memory).

--C

Kyle Manna

unread,
Apr 14, 2012, 10:48:32 AM4/14/12
to beagl...@googlegroups.com
Baas: the PRU core needs to notify the Cortex-A8 and Linux that something has happened.  There is no other way to do this other then to poll the PRU RAM or some other memory space.  The UIO driver allows a block reading that blocks until a interrupt occurs, you'd have to poll here instead.  Communicating with userspace isn't really the issue.

Chris: The STANSBY_INIT (as well as STANDBY_MODE) bit will disable access to L3 connected peripherals.  I had this problem too when accessing GPIO and SPI peripherals as well as accessing the DDR2 memory.

Jerrill

unread,
Apr 14, 2012, 5:02:52 PM4/14/12
to beagl...@googlegroups.com, Christopher Piggott
Christopher,

Well, I think I have the counting program working but I'm stuck on the devmem2 step.

Which address do I use for R1 via devmem2? How can I figure that out for myself from the documentation?

I've been trying to figure this out from the TRM and haven't had much luck, though admittedly I haven't set down and read the 250-page PRUSS section cover-to-cover yet, much less the other 4250 pages. :-) I see that the PRUSS is 0x4A300000 and that the registers may be in the CFG space at offset +0x00026000 but not much beyond that.

I was able to find the PRUSS reset bit documentation working backward from address 0x44E00C00.

What's the best way to figure these addresses out?

Thanks,
Jerrill


 

Bas Laarhoven

unread,
Apr 14, 2012, 6:00:22 PM4/14/12
to beagl...@googlegroups.com
On 14-4-2012 16:48, Kyle Manna wrote:
Baas: the PRU core needs to notify the Cortex-A8 and Linux that something has happened.  There is no other way to do this other then to poll the PRU RAM or some other memory space.  The UIO driver allows a block reading that blocks until a interrupt occurs, you'd have to poll here instead.  Communicating with userspace isn't really the issue.
Someone starting with PRU coding can postpone the trouble of getting the interrupt system working. That's why I suggested using another approach, e.g. polling first. If needed, the polling (of shared memory) can be done in a separate thread, just as the blocking wait probably would. Depending on you application, the interrupt passing may be necessary or not at all.

-- Bas

Christopher Piggott

unread,
Apr 15, 2012, 9:25:24 AM4/15/12
to beagl...@googlegroups.com
>I was able to find the PRUSS reset bit documentation working backward from address 0x44E00C00.
>What's the best way to figure these addresses out?

The AM335x Technical Resource Manual. Be prepared to do some math, though:

PRUSS1's base address is 0x4A300000. You know this from the L4 map in
chapter 2 (see table 2-4 and look for PRUSS1).

Chapter 4 section 2 has a table "Global Memory Map" that tells you
that the PRU0 DEBUG is offset 0x00022400 (for PRU1 it would be
0x00024400).

Next go to chapter 4 section 5 and look for the table "PRUSS_PRU_DEBUG
Registers" -- I'm looking at Rev C and it's table 4.5.5. That tells
you that GPREG1 (which is the debug register that shows you what's in
R1) is offset 4.

Putting those all together, PRU1's r1 register can be read at 0x4a322404.

At one point in time I had written a shell script that sets up aliases
for these registers as commands, so you can just type "r0" at a prompt
and it will show you. I will try to find that.

Jerrill

unread,
Apr 15, 2012, 9:52:38 PM4/15/12
to beagl...@googlegroups.com
Christopher,

Thank you for the information about how to read the manual! :-) And if you find that shell script it sounds very useful!

Here's how far I've gotten this evening...

sandbox.p
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.origin 0
.entrypoint main

main:
        LDI R1, #0
loop1:
        ADD R1, R1, #1
        JMP loop1
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

sandbox.c
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#include <stdio.h>
#include <prussdrv.h>

#define PRU_NUM   0

int main (void)
{
    unsigned int ret;

    printf("\nINFO: Starting %s example.\r\n", "sandbox");
    prussdrv_init ();
    ret = prussdrv_open(PRU_EVTOUT_0);
    if (ret)
    {
        printf("prussdrv_open open failed\n");
        return (ret);
    }

    printf("\tINFO: Executing example.\r\n");
    prussdrv_exec_program (PRU_NUM, "./sandbox.bin");

    printf("\tINFO: Program complete.\r\n");
    prussdrv_exit ();
    return(0);
}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

I didn't forget to release the device from reset:
devmem2 0x44E00C00 w 0

But the register isn't incrementing yet...

# devmem2 0x4a322404 w
/dev/mem opened.
Memory mapped at address 0x400c7000.
Read at address  0x4A322404 (0x400c7404): 0x00000000

# devmem2 0x4a322404 w
/dev/mem opened.
Memory mapped at address 0x4031d000.
Read at address  0x4A322404 (0x4031d404): 0x00000000

I'll keep looking. If anyone sees the problem, let me know! Thank you in advance.
Jerrill
 

Jerrill

unread,
Apr 16, 2012, 7:22:41 AM4/16/12
to beagl...@googlegroups.com
I'm forwarding this email to the list as requested by the sender. Lots of useful information! Thanks, Rob!

--------------

Hi Jerril, 


Unfortunately they're taking a while to approve my request to join the group. 

I've got similar goals as you with the PRU.... bit bashing 16 lines at 10Mhz. 

Following from your post 7 hours ago,  i've compiled a similar simple "hello world" binary and am having similar problems.  

I've been playing with devmem2 trying to figure it out

Did you try querying the control registers?  Note that if the PRU is running, then (according to TRM 4.5.5.2) the debug register GPREG1 cant be read. 

After loading my binary (almost the same as your sandbox): 
root@omap:~/bin# ./test 
INFO: Starting test example.
        INFO: Executing example.
File ./test.bin open passed
        INFO: Program complete.

Checking the control registers:
root@omap:~/bin# devmem2 0x4a322000 w  | tail -1
Value at address 0x4A322000 (0x4023b000): 0x1

This suggests the PRU is accessible but not enabled (ie. halted).  There's no halt instruction in your code??

If i force it to restart using the same control register:
root@omap:~/bin# devmem2 0x4a322000 w 2 | tail -1
Written 0x2; readback 0x2

And then check the control register again: 
root@omap:~/bin# devmem2 0x4a322000 w  | tail -1
Value at address 0x4A322000 (0x4019b000): 0x8003

Which according to the TRM means the PRU is now running (hurray!)

I think this queries the Program Counter:
root@omap:~/bin# devmem2 0x4a322004 w  | tail -1
Value at address 0x4A322004 (0x400d2004): 0xFE9B

However 0xFE9B doesn't make any sense?   

If i check where I think the binary should have been loaded to there's no code there: 
root@omap:~/bin# devmem2 0x4a334000 w  | tail -1
Value at address 0x4A334000 (0x4024d000): 0x0

Ahh, but thats because the PRU is running...  
Turning the enable bit off:
root@omap:~/bin# devmem2 0x4a322000 w 1 | tail -1
Written 0x1; readback 0x1

Checking:
root@omap:~/bin# devmem2 0x4a322000 w  | tail -1
Value at address 0x4A322000 (0x40273000): 0x8001
Nope, the PRU is still running...? 

Odd, lets reset it instead: 
root@omap:~/bin# devmem2 0x4a322000 w 0 | tail -1
Written 0x0; readback 0x0

Checking we're halted: 
root@omap:~/bin# devmem2 0x4a322000 w | tail -1
Value at address 0x4A322000 (0x402bb000): 0x1
Yep, its reset and in halt. 

Now checking the program memory location: 
root@omap:~/bin# devmem2 0x4a334000 w  | tail -1
Value at address 0x4A334000 (0x402db000): 0x5A9814FD

We've got some data, however it's got nothing like the PRU binary code (hex dump):
root@omap:~/bin# xxd test.bin 
0000000: e100 0024 e1e1 0101 0001 0021            ...$.......!

This suggests the PRU code isn't being loaded?  In fact if i load any of the other TI examples the PC stays the same and none of the program memory seems to change.

Feel free to forward to the list.  Please let me know if you're getting similar results from the devmem2 commands!

Thanks, Rob. 
 

Christopher Piggott

unread,
Apr 16, 2012, 4:55:04 PM4/16/12
to beagl...@googlegroups.com
If your code appears like it might be running or it might not, someone else's suggestion that the code is really loaded (when the pru is not in reset) is the right place to start.  If the code appears to be loaded, my next troubleshooting tip is this:

The PRU has a "single step" mode in it, and it can be helpful.  You access it through the CONTROL register, see section 4.5.4 under "Control Register."  In order to run your program you must have taken it out of reset by setting the ENABLE bit to 1.  If instead you write both enable AND the SINGLE_STEP bits at the same time then the PRU should advance one instruction.    You can look at the next register up (STATUS) and watch that PCOUNTER has moved.

I mentioned earlier that I wrote a script I found helpful for this sort of thing.  It's simple and obvious, but maybe I can save you the time of figuring it out by pasting it below.  Save it as a file, and then use the shell import:

    . pruAliases.sh

and it will make a bunch of aliases.  I use bash; if you use something else, YMMV.  There are aliases for looking at imem as well, at least the first few instructions.

For interested kibitzers, the base address here is for the AM335x ... if you use something else this will likely be wrong.

Someone suggested playing some games with grep, etc. to clean up the devmem2 output.  Good idea.

Guys I'm sorry I haven't made much progress on my PRU debugger.  I'll try to spend some time on it this week to get it at least functional for displaying registers.

################### AM335x ###################
alias control0="devmem2 0x4a322000 w"

alias status0="devmem2 0x4a322004 w"
alias wakeup_en0="devmem2 0x4a322008 w"
alias cycle0="devmem2 0x4a32200C w"
alias stall0="devmem2 0x4a322010 w"
alias r0-0="devmem2 0x4a322400 w"
alias r1-0="devmem2 0x4a322404 w"
alias r2-0="devmem2 0x4a322408 w"
alias r3-0="devmem2 0x4a32240C w"
alias r4-0="devmem2 0x4a322410 w"
alias r30-0="devmem2 0x4a322478 w"
alias r31-0="devmem2 0x4a32247C w"


alias control1="devmem2 0x4a324000 w"

alias status1="devmem2 0x4a324004 w"
alias wakeup_en1="devmem2 0x4a324008 w"
alias cycle1="devmem2 0x4a32400C w"
alias stall1="devmem2 0x4a324010 w"
alias r0-1="devmem2 0x4a324400 w"
alias r1-1="devmem2 0x4a324404 w"
alias r2-1="devmem2 0x4a324408 w"
alias r3-1="devmem2 0x4a32440C w"
alias r4-1="devmem2 0x4a324410 w"
alias r30-1="devmem2 0x4a324478 w"
alias r31-1="devmem2 0x4a32447C w"

 

alias imem0="
devmem2 0x4a334000
devmem2 0x4a334004
devmem2 0x4a334008
devmem2 0x4a33400C
devmem2 0x4a334010
devmem2 0x4a334014
devmem2 0x4a334018
devmem2 0x4a33401C
"
alias dmem0="
devmem2 0x4a300000
devmem2 0x4a300004
devmem2 0x4a300008
devmem2 0x4a30000C
"
alias imem1="
devmem2 0x4a338000
devmem2 0x4a338004
devmem2 0x4a338008
devmem2 0x4a33800C
devmem2 0x4a338010
devmem2 0x4a338014
devmem2 0x4a338018
devmem2 0x4a33801C
"
alias dmem1="
devmem2 0x4a302000
devmem2 0x4a302004
devmem2 0x4a302008
devmem2 0x4a30200C
"

###################


Rob

unread,
Apr 17, 2012, 5:25:28 AM4/17/12
to beagl...@googlegroups.com
Hi guys, have been following these PRU threads closely. 

Thanks to Jerril for forwarding my post... and thanks Christopher for confirming i'm checking the PRU's instruction memory contents correctly. 

Using my own "test" code very similar to Jerril's, and also the TI demos (eg. PRU_memCopy etc) I dont seem to be able to load code into the PRU's instruction memory. In all cases using TI's app_loader/interface/prussdrv.c library.

I did some more investigations that might help others. 

Using the uio_pruss kernel module from Anstrom kernel uImage-3.2-r9a+gitr09e9651bcf2ee8d86685f2a8075bc6557b1d3b91-beaglebone-20120415071250.bin

Firstly a bash definition to clean up devmem2's output: 
dm(){ devmem2 $1 w $2 | sed -n 3p | awk '{ print $6 }' ;}
I've added that to ~/.bashrc
The first parameter is the global address, the second optional one is the value to set it to. 

Remove the PRU from reset:
dm 0x44E00C00 0

To simplify things, i created test.p very similar to Jerrils, compiled with PASM. 
+++++++++++++++++
.origin 0
.entrypoint main
main:
        LDI R1, #0
loop1:
        ADD R1, R1, #1
        JMP loop1
+++++++++++++++++

Which compiles into 3 machine instructions:
root@omap:~/bin# xxd test.bin
0000000: e1000024 e1e10101 00010021            ...$.......!

Note the ARM is little-endian, so to manually load it into the PRU's imem you need to flip the bits:

root@omap:~/bin# dm 0x4a334000 0x240000E1    #load the first instruction
root@omap:~/bin# dm 0x4a334004 0x101E1E1     #second
root@omap:~/bin# dm 0x4a334008 0x21000100    #third

Can check the machine code is loaded: 
root@omap:~/bin# dm 0x4a334000
0x240000E1
root@omap:~/bin# dm 0x4a334004
0x101E1E1
root@omap:~/bin# dm 0x4a334008
0x21000100

#now start and reset the PRU. This includes single-stepping and enables the counter:
root@omap:~/bin# dm 0x4a322000 0x10a  #send a reset to the PRU
0x109

root@omap:~/bin# dm 0x4a322004   #check the program counter, it has run the first instruction 
0x1
root@omap:~/bin# dm 0x4a322404   #check the R1 value has been reset
0x0
root@omap:~/bin# dm 0x4a322000 0x10b   #single step the PRU
0x109
root@omap:~/bin# dm 0x4a322004    #check the program counter has incremented, yep
0x2
root@omap:~/bin# dm 0x4a322000 0x10b  #step
0x109
root@omap:~/bin# dm 0x4a322004    #check the PC has jumped back to 0x1
0x1
root@omap:~/bin# dm 0x4a322404    #check the R1 value has incremented
0x1
root@omap:~/bin# dm 0x4a322000 0x10b    #step again
0x109
root@omap:~/bin# dm 0x4a322004    #and the program counter has stepped forward again
0x2


Another debugging session. Output is CONTROL, STATUS, R1:
root@omap:~/bin# dm 0x4a322000 0x10a  #reset the PRU and put in single step mode
0x109
root@omap:~/bin# dm 0x4a322000 0x10b && dm 0x4a322004 && dm 0x4a322404
0x109
0x2
0x1
root@omap:~/bin# dm 0x4a322000 0x10b && dm 0x4a322004 && dm 0x4a322404
0x109
0x1
0x1
root@omap:~/bin# dm 0x4a322000 0x10b && dm 0x4a322004 && dm 0x4a322404
0x109
0x2
0x2
root@omap:~/bin# dm 0x4a322000 0x10b && dm 0x4a322004 && dm 0x4a322404
0x109
0x1
0x2
root@omap:~/bin# dm 0x4a322000 0x10b && dm 0x4a322004 && dm 0x4a322404
0x109
0x2
0x3
root@omap:~/bin# dm 0x4a322000 0x10b && dm 0x4a322004 && dm 0x4a322404
0x109
0x1
0x3
root@omap:~/bin# dm 0x4a322000 0x10b && dm 0x4a322004 && dm 0x4a322404
0x109
0x2
0x4
root@omap:~/bin# dm 0x4a322000 0x10b && dm 0x4a322004 && dm 0x4a322404
0x109
0x1
0x4
root@omap:~/bin# dm 0x4a322000 0x10b && dm 0x4a322004 && dm 0x4a322404
0x109
0x2
0x5

In my case this confirmed the PRU is working fine and that the problem is in the app_loader/interface/prussdrv.c library.

Cheers, Rob.

Norbyte

unread,
Apr 17, 2012, 5:46:48 AM4/17/12
to beagl...@googlegroups.com
On a somewhat unrelated note, an updated TRM was published a few days ago.
I checked if there were some important changes, and there are!
They renamed the PRUSS section of the manual to "Programmable Real-Time Unit and Industrial Communication Subsystem (PRU-ICSS)" and removed *EVERYTHING* in there! (It's just a dummy section now, similar to the SGX section).

The changelog isn't particularly talkative about this change either, it says
"Changed PRUSS to Programmable Real-Time Unit and Industiral Communication Subsystem (PRU-ICSS)."

Christopher Piggott

unread,
Apr 17, 2012, 9:20:47 AM4/17/12
to beagl...@googlegroups.com
Woah!!!

I will ask about this on E2E.

--Chris

Jerrill

unread,
Apr 17, 2012, 12:16:55 PM4/17/12
to beagl...@googlegroups.com

> beagleboard+unsubscribe@googlegroups.com


> Frequently asked questions: http://beagleboard.org/faq


Those interested can follow the E2E discussion here:


I've also contacted TI through my day job contacts to see if I can get any information as well.

Jerrill 

Christopher Piggott

unread,
Apr 17, 2012, 12:18:13 PM4/17/12
to beagl...@googlegroups.com
I have received word to not panic, an addendum is forthcoming -- PRU
docs may have simple been relocated.

>> > beagleboard...@googlegroups.com


>> > Frequently asked questions: http://beagleboard.org/faq
>
>
> Those interested can follow the E2E discussion here:
>
> http://e2e.ti.com/support/dsp/sitara_arm174_microprocessors/f/416/t/163158.aspx
>
> I've also contacted TI through my day job contacts to see if I can get any
> information as well.
>
> Jerrill
>

> -- To join: http://beagleboard.org/discuss
> To unsubscribe from this group, send email to:

> beagleboard...@googlegroups.com

Norbyte

unread,
Apr 17, 2012, 12:29:59 PM4/17/12
to beagl...@googlegroups.com
Good to hear :)

The only thing that's missing from the pasm v1 AFAIK is support for SXIN/SXOUT/SXCHG, NOP0-F and XFR bus ID-s for the scratch registers and the multiplier unit.
All other instructions are supported.


>> > Frequently asked questions: http://beagleboard.org/faq
>
>
> Those interested can follow the E2E discussion here:
>
> http://e2e.ti.com/support/dsp/sitara_arm174_microprocessors/f/416/t/163158.aspx
>
> I've also contacted TI through my day job contacts to see if I can get any
> information as well.
>
> Jerrill
>
> -- To join: http://beagleboard.org/discuss
> To unsubscribe from this group, send email to:

Christopher Piggott

unread,
Apr 17, 2012, 5:21:44 PM4/17/12
to beagl...@googlegroups.com
Hi all,

Here is the response I received from TI:

> Hi Chris,
>
> The TRM has been updated to better reflect the supported PRUSSv2 feature set (the Industrial communications protocols included in the Industrial SDK: http://www.ti.com/tool/sysbiossdk-ind-sitara). > This included both renaming the PRUSS to PRU-ICSS (Industrial Communication SubSystem) and removing PRU technical details.
>
> However, these PRU technical details will still be provided to the open-source community . The PRU assembler will be released to the open-source community as part of a PRU support package. This package will also include a PRU-ICSS chapter addendum to the TRM (containing all PRU technical details), a PRU application driver, and several basic PRU examples.
>
> I apologize for any concerns generated by rev. D of the TRM.
>
> Regards,
>
> Melissa

Jerrill

unread,
Apr 17, 2012, 8:46:04 PM4/17/12
to beagl...@googlegroups.com


On Tuesday, April 17, 2012 5:21:44 PM UTC-4, Christopher Piggott wrote:
Hi all,

Here is the response I received from TI:

> Hi Chris,
>
> The TRM has been updated to better reflect the supported PRUSSv2 feature set (the Industrial communications protocols included in the Industrial SDK: http://www.ti.com/tool/sysbiossdk-ind-sitara).  > This included both renaming the PRUSS to PRU-ICSS (Industrial Communication SubSystem) and removing PRU technical details.
>
> However, these PRU technical details will still be provided to the open-source community .  The PRU assembler will be released to the open-source community as part of a PRU support package.  This package will also include a PRU-ICSS chapter addendum to the TRM (containing all PRU technical details), a PRU application driver, and several basic PRU examples.
>
> I apologize for any concerns generated by rev. D of the TRM.
>
> Regards,
>
> Melissa


My contact said that the new documentation isn't expected to be released until the May 1 to June 1 time frame.

So, I guess I'll hold on to my Rev C TRM and press on! :-)

Jerrill

Jerrill

unread,
Apr 17, 2012, 11:12:57 PM4/17/12
to beagl...@googlegroups.com
Well it looks like the __prussdrv.h included in prussdrv.c is the culprit. Apparently, the included library is configured for another device. I was able to make the following changes for the BeagleBone (AM3558) in app_loader/interface/__prussdrv.h and get my code loaded into the PRUSS correctly:

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// the following definitions are for the AM335x (BeagleBone)
//

#define PRUSS_PERIPHERAL_BASE         0x4A300000  

#define PAGE_SIZE                     4096 //verified using sysconf(_SC_PAGE_SIZE)
#define PRUSS_IRAM_SIZE               8192
#define PRUSS_DATARAM_SIZE            8192

#define DATARAM0_PHYS_BASE            (PRUSS_PERIPHERAL_BASE + 0x00000000)
#define DATARAM1_PHYS_BASE            (PRUSS_PERIPHERAL_BASE + 0x00002000)
#define DATARAM2_PHYS_BASE            (PRUSS_PERIPHERAL_BASE + 0x00010000)
#define INTC_PHYS_BASE                (PRUSS_PERIPHERAL_BASE + 0x00020000)
#define PRU0CONTROL_PHYS_BASE         (PRUSS_PERIPHERAL_BASE + 0x00022000)
#define PRU0DEBUG_PHYS_BASE           (PRUSS_PERIPHERAL_BASE + 0x00022400)
#define PRU1CONTROL_PHYS_BASE         (PRUSS_PERIPHERAL_BASE + 0x00024000)
#define PRU1DEBUG_PHYS_BASE           (PRUSS_PERIPHERAL_BASE + 0x00024400)
#define PRU0IRAM_PHYS_BASE            (PRUSS_PERIPHERAL_BASE + 0x00034000)
#define PRU1IRAM_PHYS_BASE            (PRUSS_PERIPHERAL_BASE + 0x00038000)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Using the aliases provided by Christopher earlier:

# imem0
/dev/mem opened.
Memory mapped at address 0x402a3000.
Read at address  0x4A334000 (0x402a3000): 0x240000E1
/dev/mem opened.
Memory mapped at address 0x40157000.
Read at address  0x4A334004 (0x40157004): 0x0101E1E1
/dev/mem opened.
Memory mapped at address 0x402a5000.
Read at address  0x4A334008 (0x402a5008): 0x21000100

Using Rob's single stepping technique I can now see the PRUSS operating as expected!

beaglebone:~/projects/pru/sandbox# dm 0x4a322000 0x10a
0x00000001
beaglebone:~/projects/pru/sandbox# dm 0x4a322404 0
0x00000000
beaglebone:~/projects/pru/sandbox# dm 0x4a322000 0x10b && dm 0x4a322004 && dm 0x4a322404
0x00000109
0x00000002
0x00000001
beaglebone:~/projects/pru/sandbox# dm 0x4a322000 0x10b && dm 0x4a322004 && dm 0x4a322404
0x00000109
0x00000001
0x00000001
beaglebone:~/projects/pru/sandbox# dm 0x4a322000 0x10b && dm 0x4a322004 && dm 0x4a322404
0x00000109
0x00000002
0x00000002
beaglebone:~/projects/pru/sandbox# dm 0x4a322000 0x10b && dm 0x4a322004 && dm 0x4a322404
0x00000109
0x00000001
0x00000002
beaglebone:~/projects/pru/sandbox# dm 0x4a322000 0x10b && dm 0x4a322004 && dm 0x4a322404
0x00000109
0x00000002
0x00000003
beaglebone:~/projects/pru/sandbox# dm 0x4a322000 0x10b && dm 0x4a322004 && dm 0x4a322404
0x00000109
0x00000001
0x00000003

Now, on to GPIO!

Thank you all for your help! You really helped get me going quicker that I ever would have otherwise!
Jerrill

Jerrill

unread,
Apr 18, 2012, 10:42:15 AM4/18/12
to beagl...@googlegroups.com


On Tuesday, April 17, 2012 8:46:04 PM UTC-4, Jerrill wrote:


My contact said that the new documentation isn't expected to be released until the May 1 to June 1 time frame.

So, I guess I'll hold on to my Rev C TRM and press on! :-)

Jerrill


Here is some additional information from TI:

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
AM335x PRU is going black box. There will be an open source compiler that
will be release to beagle community. Most of the information/documentation
will be placed in this package for customers.

Here is what documentation I expect included in this new package:

* AM335x TRM Addendum with PRU technical details
* AM18x to AM335x PRU software migration guide
* AM335x PRU Linux Application Driver Documentation
* CCS AM335x PRU Debugger training slides
* AM335x_PRUSS gel file for use with CCS AM335x PRU Debugger

I believe they were looking to use github as a storage location.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Jerrill
 
Reply all
Reply to author
Forward
0 new messages