PRU - Can't read data up to 2.5 MHz

Hello, I need your help

I have to read data from an SPI master device, which sends the clock at 10 MHz. Since the SPI kernel driver only allows to the beagle bone to working as SPI Master I had to implement this functionality using a PRU.

From what I’ve read throughout the internet the PRU processing rate is 200 MHz, so I thought I could easily read data at 10 MHz. Oddly, it happens that with transmission rates up to 2.5 MHz I am being unable to catch all the rising edges on the clock pin.

So, here’s what I did:

In the PRU0 I wrote the following code:


bool WaitForRisingEdge_sclk(uint32_t sclk)
state[0] = ((__R31&sclk) == sclk) ? true : false;

if((state[0] == true) && (previous_state[0] == false))
previous_state[0] = state[0];
return true; //Rising edge
previous_state[0] = state[0];
return false;

void main(void)

count_clocks = 0;

while(gpio2[GPIO_DATAIN/4] & P8_8) //Receive notification from the beagle bone to read data

if(WaitForRisingEdge_sclk(sclk)) // wait for rising edge on clock pin
//buffer[i] = ((__R31&miso) == miso)? buffer[i] | 0x01 << k : buffer[i] | 0x00 << k;
//buffer[i] = buffer[i] | 0x01 << k;
else if(WaitForRisingEdge_cs(cs))
gpio2[GPIO_SETDATAOUT/4] = P8_7; // Notify the beagle bone that the data was already read
buffer[2600] = count_clocks;
goto START;

goto LOOP;


and I did one simple program ON PRU1 which sends at a certain frequency. I got to the conclusion that with transmission rates up to 2.5 MHz and can’t count all the clocks. I was wondering if there is any better way for reading the rising edge, I might be lossoing performance on that function itself.

Thank you very much for your help,
– Fred Gomes


state[0] = ((__R31&sclk) == sclk) ? true : false;|
state[0] = (__R31&sclk) == sclk;

should do the same thing, but I would expect the compiler to optimize|
that away. Unrolling the loops and inlining should help, also.

This is how I do the read:

Remember that I read now the SPI data into a CPLD and fetch
them bytewise.

I switch the 2 byte address lines to the CPLD and then have to wait
7 ns for propagation through the CPLD and some time more until
the ringing at the P8/P9 connector has calmed down. So I must
wait, say 4 Instructions à 5 nsec before I really get the data.
That is done with some volatile reads. I had the impression that
the number of instructions and the delay did not always scale 1:1,
so it took some pruning with the oscilloscope until I was satisfied.

The canonical solution for your problem is probably to use the
hardware SPI interface with the PRU, which should work to 48 MBit/s.
I could not make that work, and in the end I wanted 100 MBit/s anyway.


I Gerhard, thank you very much for your answer.

I replaced the “IF” statements by “While”, as shown in your example and the communication got a way faster. However, I am can’t still get data at 10 MHz, I think the problem has to be with writing in the shared memory zone, I’ve got the following piece of code:

#define PRU_SHARED_MEM_ADDR 0x00010000

volatile int* buffer = (volatile int *) PRU_SHARED_MEM_ADDR;

int k = 0;
while((__R31&cs) != cs){ // CS = 0

while((__R31&sclk) == sclk){ //sclk = 1

if((__R31&cs) == cs)
goto END;

while((__R31&sclk) != sclk); //SCLK = 0 → RISING EDGE

buffer[k/32] = ((__R31&miso) >> miso) << (K%32); → I lOOSE CLOCKS HERE

Any idea how can I get it a little bit faster? If I remove the MISO reading line I can catch all the SCK clocks, the problem comes when I add that line, I think it gets slower because of the access to that memory zone.

Thank you very much,
Fred Gomes

Gerhard Hoffmann <> escreveu no dia quarta, 28/11/2018 à(s) 13:42: