PRU multiple shift out && pattern generation

Hello,

I’m trying to generate pattern with the PRU in several channel at the same time.
So the objective is to be able to send different sequence of value on six channel of the PRU and all of them need to be sent at the same (based on a clock signal).
For example send
channel 0 : 0 1 1 0 0 0 1 1 0 0
channel 1 : 1 0 1 0 0 1 1 1 0 0
channel 2 : 0 1 1 0 0 0 1 0 0 0
channel 3 : 0 1 1 0 1 0 1 1 0 0
channel 4 : 0 0 1 0 0 1 0 1 0 0
channel 5 : 1 1 1 0 0 0 1 1 0 1
And on each rise up of the clock, the data are sending out.
(The value of the data are not important, it’s just an example).
To do so I’have follow the chapter 13 of Derek molloy book on ADC.

Then from the PRUADC.p program, I have extract the part which allowed me to do shift out of data, I have regroup it in the file pru_sequence_one_channel_out.p.
I have also use a pru_sequence.c (based on the PRUADC.c program) which allow me to send the assembly code into the PRU
(Just to be clear I have rename pru_sequence.p into pru_sequence_one_channel_out.p in order be able to explain you the difference with pru_sequence_two_channel_out.p).

This example works very well, I observe the expected data on the pin P9_29.

However, when I tried to send two data at the same time it is not working, in the way that I can’t observe anything on P9_27 (but I still observed the same signal on the P9_29).
It’s not due to the DTS, because if I change the PIN of the DATA_OUT to P9_27, it’s work well.
The code is on the pru_sequence_two_channel_out.p program, it is use with the same pru_sequence.c program. The main change are on SEQCLK part.
I have also tried to move the part for the OUT_2 on different places in the program, but I didn’t succeed to making it works.
In addition, I have tried to shift out the same data in two channels, but it’s still doesn’t work.

So I’m wondering if it’s possible to do shift out on multiple Pins at the same time ? If yes, have you got an example which can do that,
or have you some clue on what I’m doing wrong ?

Remark :
I have also think to the Direct Connection mode instead of the Shift out one. However, I didn’t know how can I do such a thing with a clock synchronization because each movement will cost me one clock cycle.

Thanks by advance
Regards
Vincent

pru_sequence.c (2.54 KB)

pru_sequence_one_channel_out.p (3.85 KB)

pru_sequence_two_channel_out.p (4.44 KB)

The modifications you made to the code to support two channels are
just wrong, you need to set/clear both output data bits before setting
the clock pin high. Also, you'll use far fewer cycles if you can
manage to shift out bytes or words instead of single bits, but that
will depend on how you have the PRU I/O pinned out and if you can
tolerate the extra overhead in the ARM to PRU communications.

Hi Charles,
first thanks for your answer.
Then, I tried to follow your idea, I have change the code to the following

`

SEQCLK:
MOV r0, DELAY_HIGH // time for clock low – assuming clock low before cycle
CLKLOW:
SUB r0, r0, 1 // decrement the counter by 1 and loop (next line)
QBNE CLKLOW, r0, 0 // check if the count is still low

//for OUT_1
QBBC DATALOW_1, REGISTER_OUT_1.t31 // The write state needs to be set right here – bit 31 shifted left
SET DATA_OUT_1
SET DATA_OUT_2

QBA DATACONTD
DATALOW_1:
CLR DATA_OUT_1
CLR DATA_OUT_2

DATACONTD:
SET PIN_CLK // set the clock high
MOV r0, DELAY_LOW // time for clock high
CLKHIGH:
SUB r0, r0, 1 // decrement the counter by 1 and loop (next line)
QBNE CLKHIGH, r0, 0 // check the count
LSL REGISTER_OUT_1, REGISTER_OUT_1, 1 //shift left the data
LSL REGISTER_OUT_2, REGISTER_OUT_2, 1 //shift left the data

// clock goes low now
CLR PIN_CLK // set the clock low
DATAINLOW:
RET
`

→ Lead that I observed the data of Out_1 on both OUT (1 and 2), however, it doesn’t sound right for me because, we don’t check the REGISTER_OUT_2.t31,
and it didn’t allow me to send two different data.

I have also tried

`
SEQCLK:
MOV r0, DELAY_HIGH // time for clock low – assuming clock low before cycle
CLKLOW:
SUB r0, r0, 1 // decrement the counter by 1 and loop (next line)
QBNE CLKLOW, r0, 0 // check if the count is still low

QBBC DATALOW_1, REGISTER_OUT_1.t31 // The write state needs to be set right here – bit 31 shifted left
SET DATA_OUT_1
QBBC DATALOW_2, REGISTER_OUT_2.t31 // The write state needs to be set right here – bit 31 shifted left
SET DATA_OUT_2

QBA DATACONTD
DATALOW_1:
CLR DATA_OUT_1
QBBC DATALOW_2, REGISTER_OUT_2.t31 // The write state needs to be set right here – bit 31 shifted left
SET DATA_OUT_2
QBA DATACONTD

DATALOW_2:
CLR DATA_OUT_2

DATACONTD:
SET PIN_CLK // set the clock high
MOV r0, DELAY_LOW // time for clock high

CLKHIGH:
SUB r0, r0, 1 // decrement the counter by 1 and loop (next line)
QBNE CLKHIGH, r0, 0 // check the count
LSL REGISTER_OUT_1, REGISTER_OUT_1, 1 //shift left the data
LSL REGISTER_OUT_2, REGISTER_OUT_2, 1 //shift left the data
// clock goes low now
CLR PIN_CLK // set the clock low
DATAINLOW:

RET
`

Which normally check REGISTER_OUT_1 and 2 and also set/clear both output data bits before setting
the clock pin high. Nevertheless, it led that I still doesn’t observe any signal on OUT_2.

So, are my ideas in the good direction, if so what can I improve, else what is still wrong ?

For the part of trying to shift out bytes or words instead of single bits, I was guessing that it was linked to LSL command,

If I change it by

`
LSL REGISTER_OUT_1, REGISTER_OUT_1, 2 //shift left the data
LSL REGISTER_OUT_2, REGISTER_OUT_2, 2 //shift left the data

`

It’s lead to the same result as

`
LSL REGISTER_OUT_1, REGISTER_OUT_1, 2 //shift left the data
LSL REGISTER_OUT_2, REGISTER_OUT_2, 1 //shift left the data

`

i.e. the two data are the same and it is one out of two bits.

So is it the idea to shift out more bits at the same time, or is it completely something else ?

Thanks by advance
Regards
Vincent

I can only guess at what you are trying to do based on the changes you
made to the code.

What I *THINK* you want is to have two (or more) values you're
shifting out, each in it's own PRU register, and have each value
shifted out on it's own PRU pin.

If that's the case, you want to test and set each value register and
then toggle the clock. So in (totally not optimized) pseudo code:

Loop:
  test left bit of value 1
  set/clear output 1 as appropriate
  shift value 1

  test left bit of value 2
  set/clear output2 as appropriate
  shift value 2

  ... (repeat for however many values you have)

  Set the clock high
  Delay for clock-high time

  If all bits have been shifted out then
    read new values from memory

  Set the clock low

  goto Loop

Instead of testing and setting each bit individually, you can use a
byte or word move to PRU register 31, but that will require the C
program to seralize and interleave the data before sending it to the
PRU (or you could do this on the PRU, but it would take more cycles).

There are lots of other options for tweaking the code, depending on
how fast it needs to run and whether or not you need all the outputs
to change simultaneously. Since you're currently delaying 12 cycles
for each state of the clock, you could pretty easily update eight
outputs without slowing down the code, but you'll have to be
pre-calculating the next outputs instead of busy-waiting in the clock
delay loops.