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
<http://exploringbeaglebone.com/chapter13/#prettyPhoto>.
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
--
For more options, visit http://beagleboard.org/discuss
---
You received this message because you are subscribed to the Google Groups
"BeagleBoard" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to beagleboard+unsubscr...@googlegroups.com.
To view this discussion on the web visit
https://groups.google.com/d/msgid/beagleboard/f1b39d9c-072a-4cd5-962f-87d25afe8c12%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
/* This program loads the two PRU programs into the PRU-ICSS transfers the configuration
* to the PRU memory spaces and starts the execution of both PRU programs.
* pressed.
*/
#include <stdio.h>
#include <stdlib.h>
#include <prussdrv.h>
#include <pruss_intc_mapping.h>
#define PRU_NUM_0 0 // using PRU0 for the ADC capture
#define MMAP1_LOC "/sys/class/uio/uio0/maps/map1/"
#define NUMBER_OF_PINS 2
#define SIZE_UNSIGNED_INT 4
#define DEDICATED_DATA 2
#define SIZE_ARRAY_SEQUENCE DEDICATED_DATA+NUMBER_OF_PINS
// Short function to load a single unsigned int from a sysfs entry
unsigned int readFileValue(char filename[]){
FILE* fp;
unsigned int value = 0;
fp = fopen(filename, "rt");
fscanf(fp, "%x", &value);
fclose(fp);
return value;
}
int main (void)
{
if(getuid()!=0){
printf("You must run this program as root. Exiting.\n");
exit(EXIT_FAILURE);
}
// Initialize structure used by prussdrv_pruintc_intc
// PRUSS_INTC_INITDATA is found in pruss_intc_mapping.h
tpruss_intc_initdata pruss_intc_initdata = PRUSS_INTC_INITDATA;
// data for PRU0 based on the MCPXXXX datasheet
unsigned int sequenceData[SIZE_ARRAY_SEQUENCE];
sequenceData[0] = readFileValue(MMAP1_LOC "addr");
sequenceData[1] = readFileValue(MMAP1_LOC "size");
sequenceData[2] = 0xaa500000; // an example of data send on the DATA OUT PIN
sequenceData[3] = 0xaaa00000; // use in case of two channel pru sequence only
printf("Sending the SPI Control Data: 0x%x and 0x%x\n", sequenceData[2],sequenceData[3]);
printf("The DDR External Memory pool has location: 0x%x and size: 0x%x bytes\n", sequenceData[0], sequenceData[1]);
int numberSamples = sequenceData[1]/2;
printf("-> this space has capacity to store %d 16-bit samples (max)\n", numberSamples);
// Allocate and initialize memory
prussdrv_init ();
prussdrv_open (PRU_EVTOUT_0);
// Write the address and size into PRU0 Data RAM0.
prussdrv_pru_write_memory(PRUSS0_PRU0_DATARAM, 0, sequenceData, SIZE_ARRAY_SEQUENCE*SIZE_UNSIGNED_INT); // sequence code
// Map the PRU's interrupts
prussdrv_pruintc_init(&pruss_intc_initdata);
// Load and execute the PRU program on the PRU
prussdrv_exec_program (PRU_NUM_0, "./pru_sequence.bin");
// Wait for event completion from PRU, returns the PRU_EVTOUT_0 number
int n = prussdrv_pru_wait_event (PRU_EVTOUT_0);
printf("EBBADC PRU0 program completed, event number %d.\n", n);
// Disable PRU and close memory mappings
prussdrv_pru_disable(PRU_NUM_0);
prussdrv_exit ();
return EXIT_SUCCESS;
}
//The program generates a sequence on DATA OUT(P9_29h is send on every clock cycle of the PIN_CLK(P9_30)
// sequence out : P9_29 pr1_pru0_pru_r30_1 r30.t1
// CLK : P9_30 pr1_pru0_pru_r30_2 r30.t2
.setcallreg r29.w2 // set a non-default CALL/RET register
.origin 0 // start of program in PRU memory
.entrypoint START // program entry point (for a debugger)
#define BASE_ADRESSE 0x00000000
#define SIZE_UNSIGNED_INT 4
#define PRU0_R31_VEC_VALID 32 // allows notification of program completion
#define PRU_EVTOUT_0 3 // the event number that is sent back
#define DATA_OUT_1 r30.t1 //P9_29 mode OUT
#define DATA_OUT_2 r30.t5 //P9_27 mode OUT
#define PIN_CLK r30.t2 //P9_30_OUT
#define PARA_0 0 //parameter number 0
#define PARA_1 1 //parameter number 1
#define PARA_2 2 //parameter number 2
#define PARA_3 3 //parameter number 3
#define REGISTER_OUT_1 r9 // can be any register but I prefer to define it here
#define REGISTER_OUT_2 r10 // can be any register but I prefer to define it here
#define TIME_CLOCK 12 // T_hi and t_lo = 125ns = 25 instructions (min)
//For now DELAY_HIGH=DELAY_LOW=TIME_CLOCK, but the objectif is latter to change them
#define DELAY_HIGH TIME_CLOCK
#define DELAY_LOW TIME_CLOCK
#define NUMBER_OF_LOOP 10
#define NUMBER_OF_BITS_READ 24 // you have to keep it under or equal to 31 otherwise it will cost you an additional clock cycle
START:
//Initialisation part
MOV r5, NUMBER_OF_LOOP
MOV r1, BASE_ADRESSE // load the base address into r1
// PRU memory 0x00 stores the sequence command - e.g., 0x01 0x80 0x00
LBBO r7, r1, PARA_0*SIZE_UNSIGNED_INT, SIZE_UNSIGNED_INT // load the Linux address that is passed into r7 -- to store sample values
LBBO r8, r1, PARA_1*SIZE_UNSIGNED_INT, SIZE_UNSIGNED_INT // load the size that is passed into r8 -- the number of samples to take
CLR DATA_OUT_1 // clear the data out 1
GET_SAMPLE: // load the send value on each sample, allows sampling re-configuration
//Load the 2 value form the C program
LBBO REGISTER_OUT_1, r1, PARA_2*SIZE_UNSIGNED_INT, SIZE_UNSIGNED_INT //send value on each sample the MCP3XXX states are now stored in r9 -- need the 16 MSBs
SAMPLE_WAIT_HIGH:
MOV r4, NUMBER_OF_BITS_READ // going to write/read 24 bits (3 bytes)
SEQCLK_BIT: // loop for each of the NUMBER_OF_BITS_READ bits
SUB r4, r4, 1 // count down through the bits
CALL SEQCLK // repeat call the SPEQCLK_BIT procedure until all NUMBER_OF_BITS_READ-bits written/read
QBNE SEQCLK_BIT, r4, 0
SUB r5,r5,1 //decrese the r5 counter
QBNE GET_SAMPLE, r5, 0 //allow you to send multiple time the data
END:
MOV r31.b0, PRU0_R31_VEC_VALID | PRU_EVTOUT_0
HALT
// This procedure applies an SEQUENCE clock cycle to the PIN_CLK clock and on the rising edge of the clock
// it writes the current MSB bit in r2 (i.e. r31) to the P9_29 pin.
// The clock cycle is determined by the datasheet of the product where DELAY_LOW and DELAY_HIGH are the
// time that the clock must remain low and the time it must remain high
// The outputs data are shifted left on each clock cycle
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
QBA DATACONTD
DATALOW_1:
CLR DATA_OUT_1
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
CLR PIN_CLK // set the clock low
DATAINLOW:
RET
//The program generates a sequence on DATA OUT(P9_29h is send on every clock cycle of the PIN_CLK(P9_30)
// sequence out 1 : P9_29 pr1_pru0_pru_r30_1 r30.t1
// sequence out 2 : P9_27 pr1_pru0_pru_r30_5 r30.t5
// CLK : P9_30 pr1_pru0_pru_r30_2 r30.t2
.setcallreg r29.w2 // set a non-default CALL/RET register
.origin 0 // start of program in PRU memory
.entrypoint START // program entry point (for a debugger)
#define BASE_ADRESSE 0x00000000
#define SIZE_UNSIGNED_INT 4
#define PRU0_R31_VEC_VALID 32 // allows notification of program completion
#define PRU_EVTOUT_0 3 // the event number that is sent back
#define DATA_OUT_1 r30.t1 //P9_29 mode OUT
#define DATA_OUT_2 r30.t5 //P9_27 mode OUT
#define PIN_CLK r30.t2 //P9_30_OUT
#define PARA_0 0 //parameter number 0
#define PARA_1 1 //parameter number 1
#define PARA_2 2 //parameter number 2
#define PARA_3 3 //parameter number 3
#define REGISTER_OUT_1 r9 // can be any register but I prefer to define it here
#define REGISTER_OUT_2 r10 // can be any register but I prefer to define it here
#define TIME_CLOCK 12 // T_hi and t_lo = 125ns = 25 instructions (min)
//For now DELAY_HIGH=DELAY_LOW=TIME_CLOCK, but the objectif is latter to change them
#define DELAY_HIGH TIME_CLOCK
#define DELAY_LOW TIME_CLOCK
#define NUMBER_OF_LOOP 10
#define NUMBER_OF_BITS_READ 24 // you have to keep it under or equal to 31 otherwise it will cost you an additional clock cycle
START:
//Initialisation part
MOV r5, NUMBER_OF_LOOP
MOV r1, BASE_ADRESSE // load the base address into r1
// PRU memory 0x00 stores the SPI command - e.g., 0x01 0x80 0x00
// the SGL/DIFF and D2, D1, D0 are the four LSBs of byte 1 - e.g. 0x80
LBBO r7, r1, PARA_0*SIZE_UNSIGNED_INT, SIZE_UNSIGNED_INT // load the Linux address that is passed into r7 -- to store sample values
LBBO r8, r1, PARA_1*SIZE_UNSIGNED_INT, SIZE_UNSIGNED_INT // load the size that is passed into r8 -- the number of samples to take
CLR DATA_OUT_1 // clear the data out 1
CLR DATA_OUT_2 // clear the data out 2
GET_SAMPLE: // load the send value on each sample, allows sampling re-configuration
//Load the 2 value form the C program
LBBO REGISTER_OUT_1, r1, PARA_2*SIZE_UNSIGNED_INT, SIZE_UNSIGNED_INT //send value on each sample the MCP3XXX states are now stored in r9 -- need the 16 MSBs
LBBO REGISTER_OUT_2, r1, PARA_3*SIZE_UNSIGNED_INT, SIZE_UNSIGNED_INT //send value on each sample the MCP3XXX states are now stored in r10 -- need the 16 MSBs
SAMPLE_WAIT_HIGH:
MOV r4, NUMBER_OF_BITS_READ // going to write/read 24 bits (3 bytes)
SEQCLK_BIT: // loop for each of the NUMBER_OF_BITS_READ bits
SUB r4, r4, 1 // count down through the bits
CALL SEQCLK // repeat call the SPEQCLK_BIT procedure until all NUMBER_OF_BITS_READ-bits written/read
QBNE SEQCLK_BIT, r4, 0
SUB r5,r5,1 //decrese the r5 counter
QBNE GET_SAMPLE, r5, 0 //allow you to send multiple time the data
END:
MOV r31.b0, PRU0_R31_VEC_VALID | PRU_EVTOUT_0
HALT
// This procedure applies an SEQUENCE clock cycle to the PIN_CLK clock and on the rising edge of the clock
// it writes the current MSB bit in r2 (i.e. r31) to the MOSI pin.
// The clock cycle is determined by the datasheet of the product where DELAY_LOW and DELAY_HIGHare the
// time that the clock must remain low and the time it must remain high
// The outputs data are shifted left on each clock cycle
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
QBA DATACONTD
DATALOW_1:
CLR DATA_OUT_1
DATACONTD:
SET PIN_CLK // set the clock high
MOV r0, DELAY_LOW // time for clock high
LSL REGISTER_OUT_1, REGISTER_OUT_1, 1 //shift left the data
//for OUT_2
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 CLKHIGH
DATALOW_2:
CLR DATA_OUT_2
CLKHIGH:
SUB r0, r0, 1 // decrement the counter by 1 and loop (next line)
QBNE CLKHIGH, r0, 0 // check the count
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