PRU multiple shift out && pattern generation

95 views
Skip to first unread message

Le Costaouec Vincent

unread,
May 17, 2016, 11:16:52 AM5/17/16
to BeagleBoard
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
pru_sequence_one_channel_out.p
pru_sequence_two_channel_out.p

Charles Steinkuehler

unread,
May 17, 2016, 6:04:16 PM5/17/16
to beagl...@googlegroups.com
On 5/17/2016 10:16 AM, Le Costaouec Vincent wrote:
>
> 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).

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.

--
Charles Steinkuehler
cha...@steinkuehler.net

Vincent lc

unread,
May 18, 2016, 4:45:28 AM5/18/16
to BeagleBoard
Le mercredi 18 mai 2016 00:04:16 UTC+2, Charles Steinkuehler a écrit :
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.

--
Charles Steinkuehler
cha...@steinkuehler.net
 
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 ?

Charles Steinkuehler

unread,
May 18, 2016, 11:26:18 AM5/18/16
to beagl...@googlegroups.com
On 5/18/2016 3:45 AM, Vincent lc wrote:
>
> So is it the idea to shift out more bits at the same time, or is it completely
> something else ?

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.

--
Charles Steinkuehler
cha...@steinkuehler.net
Reply all
Reply to author
Forward
0 new messages