Am 18.01.21 um 04:03 schrieb phfbertoleti:
I'll write the newest iamge on my BBGW. I think after that everything
will back to normal.
Regarding PRUs, I think you can answer me the following: I was able to
write data succesfully to shared data segment using PRU0, to confirm
I've checked memory using devmem2. However, I'm not so sure on how I
can read it from host (Linux) side, once Linux side uses virtual
memory (= no physical memory address are referred there, per my
understanding).
How do you recommend me to read (or write) data to shared memory from
host (Linux) side in C? Is there any special library for this? I
assume this is the easiest (maybe the only, as I've understood so far)
way to communicate Linux side and PRUs side.
I have mostly made a FFT analyzer from a BBB. There are up to 3 LTC2500
ADCs sampling analog
data at 1MSPS, 32 Bits per sample. I got my Agilent 89441A back to work,
therefore this here is idle
for >> 1 year. I started that with PRU0, but PRU1 has more usable pins.
PRU 1 was reading the data with the help of an external CPLD that
converted SPI to Bytes since even
the PRU could not read SPI at 3*100 MBit. There is a 12 KB dual port
buffer somewhere accessible to
both the ARM and the PRU. The lowest words of the buffer make a
command/status interface between
ARM and PRU (command, status, 3 parameters, 3 test results, etc). The
rest of the buffer is used to
transfer long time series to the ARM in a ping-pong way. (The way I
used it.)
The shared buffer has a fixed address on the PRU side, and also on the
ARM side. You cannot use
this address in your ARM program but you can mmap() it into the virtual
memory space of the ARM.
That is a standard system call.
The following source code was not meant for publication, it is
half-done. Don't hit me too hard.
But the access to the shared ram works from both sides, this here is the
ARM side.
It seems you have the PRU side already. What you need is probably openpru().
Sorry for the semi-German in the source.
regards, Gerhard
-----------------------------------------------
// pru_if.h
//
// extern int init_spi_pins(void);
extern int open_pru(void);
extern int close_pru(void);
extern void run_pru_cmnd( int pru_argc, char **pru_argv);
extern int do_aquisition_cmnd( int n_samples);
#define ADC_BUFFER_SIZE (32*1024)
extern int adc_buffer[ADC_BUFFER_SIZE];
-----------------------------------------------
pru_if.c
#include <sys/types.h> /* type definitions used by many programs */
#include <stdio.h> /* standard IO functions */
#include <stdlib.h> /* commonly used functions, EXIT_SUCCESS
and EXIT_FAILURE */
#include <errno.h>
#include <string.h>
#include <math.h>
#include <sys/time.h> /* setitimer(2) and getitimer(2) */
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <unistd.h> /* for nice system call */
#include "ltcsrv.h" /* for panic() */
#include "pru_if.h" /* to enforce consistency with .c */
#include "cmnd_stat_codes.h"
int adc_buffer[ADC_BUFFER_SIZE];
int dev_mem_fd;
volatile int *shared_ram;
volatile int *pru_ram; // the 8 KB local data = 2 KWORDS
int cmnd_to_send;
int init_BBB_pins(){
// printf("initializing pins for SPI and PRU\n");
// 2> stderr umleiten &> stdout und stderr umleiten
system("/bin/rm -f spitest.log");
// this here worked from bash, never change a winning team.
if (system("/usr/bin/config-pin p8.45 pruin 2> spitest.log"))
return 1; // PRU1.0 q0
if (system("/usr/bin/config-pin p8.46 pruin 2> spitest.log"))
return 1; // PRU1.1 q1
if (system("/usr/bin/config-pin p8.43 pruin 2> spitest.log"))
return 1; // PRU1.2 q2
if (system("/usr/bin/config-pin p8.44 pruin 2> spitest.log"))
return 1; // PRU1.3 q3
if (system("/usr/bin/config-pin p8.41 pruin 2> spitest.log"))
return 1; // PRU1.4 q4
if (system("/usr/bin/config-pin p8.42 pruin 2> spitest.log"))
return 1; // PRU1.5 q5
if (system("/usr/bin/config-pin p8.39 pruin 2> spitest.log"))
return 1; // PRU1.6 q6
if (system("/usr/bin/config-pin p8.40 pruin 2> spitest.log"))
return 1; // PRU1.7 q7
if (system("/usr/bin/config-pin p8.27 pruout 2> spitest.log"))
return 1; // PRU1.8 qsel0 cpld.19 könnte auch zusätzlich
SDI sein
if (system("/usr/bin/config-pin p8.29 pruout 2> spitest.log"))
return 1; // PRU1.9 qsel1 cpld.16
if (system("/usr/bin/config-pin p8.28 pruout 2> spitest.log"))
return 1; // PRU1.10 prog_clk cpld.36
if (system("/usr/bin/config-pin p8.30 pruout 2> spitest.log"))
return 1; // PRU1.11 prog_data / sdi
if (system("/usr/bin/config-pin p9.26 pruin 2> spitest.log"))
return 1; // PRU1.16_in data available from CPLD.12 ( Busy or DRL,
depending chan B/A)
if (system("/usr/bin/config-pin p9.22 out 2> spitest.log"))
return 1; // GPIO0.2 prog_ena cpld.39
if (system("/usr/bin/config-pin p9.18 out 2> spitest.log"))
return 1; // GPIO0.4 use_chan_b cpld.8
// printf("done with initializing pins.\n");
return 0;
}
void copy_shared_ram_to_file(char *fn){
FILE * phyle;
int i, j;
phyle = fopen(fn, "w"); // FIXME return value
fprintf(phyle, "%s\n", fn);
fprintf(phyle, "byte index dec byte index hex word index
content\n\n");
for (i=0; i< 3*1024; i++){ // 12 KB are 3 Kwords
fprintf(phyle, "\n%12d %8x %8x = 0x%8x %12d", 4*i, 4*i,
i, shared_ram[i], shared_ram[i]);
switch(i){
case 0: fprintf(phyle, " unused"); break;
case COMMAND: fprintf(phyle, " command"); break;
case STATUS: fprintf(phyle, " status"); break;
case PARAM1: fprintf(phyle, " param1"); break;
case PARAM2: fprintf(phyle, " param2"); break;
case PARAM3: fprintf(phyle, " param3"); break;
case TEST1: fprintf(phyle, " test1"); break;
case TEST2: fprintf(phyle, " test2"); break;
case TEST3: fprintf(phyle, " test3"); break;
case PING_FULL: fprintf(phyle, " ping_full"); break;
case PONG_FULL: fprintf(phyle, " pong_full"); break;
case PING: fprintf(phyle, " ping buffer
start"); break;
case PONG: fprintf(phyle, " pong buffer
start"); break;
}
}
fclose(phyle); // FIXME return value
}
void copy_pru_ram_to_file(char *fn){
FILE * phyle;
int i, j;
phyle = fopen(fn, "w"); // FIXME return value
fprintf(phyle, "%s\n", fn);
fprintf(phyle, "byte index word index content all hex\n\n");
fprintf(phyle, "stack lowest and data nil pointer\n");
for (i=0; i< 4*1024; i++){ // 2 * 8 KB are 4 Kwords
if (0x100/4 == i) { fprintf(phyle, "\nstack highest -
heap lowest\n"); }
else if (0x200/4 == i) { fprintf(phyle, "\nheap highest\n"); }
fprintf(phyle, "%8x %8x = %8x\n", 4*i, i, pru_ram[i]);
}
fclose(phyle); // FIXME return value
}
void display_cmnd( int cmnd){
printf(" <%c> %d = ", cmnd, cmnd);
switch (cmnd){
case CMND_NONE: printf("none\n"); break;
case CMND_HALT: printf("halt\n"); break;
case CMND_BLINK_FAST: printf("blink fast\n"); break;
case CMND_BLINK_SLOWLY: printf("blink slowly\n"); break;
case CMND_CHAN: printf("Channel select 1=B\n");
break;
case CMND_INIT_ADC: printf("init ADC\n"); break;
case CMND_START_AQUISITION: printf("start_aquisition\n"); break;
case CMND_CLEAR_RAM: printf("wipe out the rams\n"); break;
case CMND_XMIT_WORD: printf("xmit word via spi\n"); break;
case CMND_TEST: printf("test\n"); break;
case CMND_WRITE_ADDRESS: printf("write address\n"); break;
case CMND_READ_ADDRESS: printf("read address\n"); break;
case CMND_UIUIUI: printf("uiuiui\n"); break;
case CMND_READ_ADC: printf("read ADC\n"); break;
default: printf("????\n");
}
} // display_cmnd()
// %i matches 0XABC 0xabc as hex , 0777 as oct, the rest in decimal
// octal may come as a surprise! I still love the PDP-11.
// %i funktioniert irgendwie nicht mit großen Zahlen wie 0xDEADBEEF, da
kommt 7fff ffff raus.
// so we do it without %i and without octal.
int num_to_int(const char *s){
int result;
if ((*s == '0') && (*(s+1) == 'x')){ // *s+1 kann das Null-byte sein!
sscanf(s, "%x", &result);
} else {
sscanf(s, "%d", &result);
}
// sscanf(s, "%i", &result);
return result;
}
// display status cannot have the state as param since it must do busy
waiting.
void display_status(){
if (shared_ram[STATUS] == STAT_BUSY){
printf("PRU program is Busy. Waiting...\n");
while (shared_ram[STATUS] == STAT_BUSY){};
}
printf("status = %08x = ", shared_ram[STATUS]);
switch (shared_ram[STATUS]){
case STAT_CLEARED: printf("cleared"); break;
case STAT_RDY_FOR_CMND: printf("ready for command"); break;
case STAT_INITIALIZING: printf("initializing"); break;
case STAT_BUSY: printf("busy"); break;
default: printf("stat_unknown");
}
printf("error = %08x = ", shared_ram[ERRCODE]);
switch (shared_ram[ERRCODE]){
case ERR_NONE: printf("none\n"); break;
case ERR_HALTED: printf("halted\n"); break;
case ERR_BAD_CMND: printf("bad command\n"); break;
case ERR_BAD_PARAM: printf("bad parameter\n"); break;
case ERR_PIPO_OVERRUN: printf("ping pong buffer
overflow\n"); break;
case ERR_SPI_OVERRUN: printf("SPI overrun\n"); break;
// case ERR_UNEXPECTED_BUSY: printf("unexpected busy\n"); break;
default: printf("error_unknown\n");
}
} // display_status()
// this is now the aquisition command for the client command interpreter.
// Nevertheless it can return PRU error codes.
// TODO analoge Vcc überwachen, Timeout einbauen
int do_aquisition_cmnd( int n_samples){
// FILE * phyle;
int i;
int *adc_buf_p; // pointer into adc buffer for data
collection
volatile int * ppp; // ping pong pointer
int words_transferred;
printf("do aqu - on entry %d n_samples\n", n_samples);
adc_buf_p = adc_buffer; // destination in ARM RAM
words_transferred = 0;
// should not be busy when we start aquisition. cannot happen, really.
if (shared_ram[STATUS] != STAT_RDY_FOR_CMND){
return shared_ram[ERRCODE];
}
// That can be timelimited by setitimer(2) and getitimer(2),
// avoid checking faster for done than PRU notes that it has work to do
// den Sinn sehe ich gerade nicht ein FIXME
?????????????????????????????????????????????????
shared_ram[STATUS] = STAT_CLEARED;
shared_ram[PARAM1] = compose_adc_ctl(); // 1 word from SCPI options
shared_ram[COMMAND] = CMND_INIT_ADC;
// Wait util PRU is done with initializing the ADC.
// FIXME can take forever if ADC has no power or clock
while (shared_ram[STATUS] != STAT_RDY_FOR_CMND){};
shared_ram[PARAM1] = use_chan_b; // Set 1 MSPS or
decimated output
shared_ram[COMMAND] = CMND_CHAN;
while (shared_ram[STATUS] != STAT_RDY_FOR_CMND){};
printf("\nentering nice mode - starting aquisition n_samples =
%d\n, n_samples");
nice (-19);
shared_ram[STATUS] = STAT_CLEARED;
shared_ram[PARAM1] = n_samples;
shared_ram[COMMAND] = CMND_START_AQUISITION;
while ( words_transferred <= n_samples) {
if (shared_ram[PING_FULL] = 1){
printf("i");
ppp = & shared_ram[PING]; // + 0x400
i = 1024;
while (i--){
*adc_buf_p++ = *ppp++;
}
shared_ram[PING_FULL] = 0; // we got the contents, can
now be re-used
words_transferred += 1024;
} // ping buffer full
if (shared_ram[PONG_FULL] = 1){
printf("o");
ppp = & shared_ram[PONG]; // + 0x800
i = 1024;
while (i--){
*adc_buf_p++ = 48; // FIXME *ppp++;
}
shared_ram[PONG_FULL] = 0; // we got the contents, can
now be re-used
words_transferred += 1024;
} // pong buffer full
} // while()
nice(0);
printf (" transferred %d words\n", words_transferred );
if ( ERR_PIPO_OVERRUN == shared_ram[STATUS]) return ERR_PIPO_OVERRUN;
if ( ERR_SPI_OVERRUN == shared_ram[STATUS]) return
ERR_SPI_OVERRUN; // cannot happen now.
phyle = fopen("adc_result.txt", "w"); // FIXME return value
fprintf(phyle, "word index content\n\n");
for (i=0; i< words_transferred; i++){ // 12 KB are 3 Kwords
fprintf(phyle, "%12d 0x%8x = %8x %12d\n", i, i,
adc_buffer[i], adc_buffer[i]);
}
fclose(phyle); // FIXME return value
return 0;
} // do_aquisition_cmnd()
int pr_val(unsigned u, unsigned bit){
return (u & (1<<bit) ? '1' : '0');
}
// some commands may need some postprocessing to display meaningful
results etc
void command_postprocessing(){
// int t1, t2, t3;
if (cmnd_to_send == CMND_START_AQUISITION) { // that must go
fast now. No inspection by hand.
printf("\npostprocessing aquisition command\n");
do_aquisition_cmnd(32000);
} else if ( cmnd_to_send == CMND_WRITE_ADDRESS){
printf("\nPRU data space at 0x%08x written with 0x%08x check
read = 0x%08x\n",
shared_ram[PARAM1], shared_ram[PARAM2],
shared_ram[PARAM3]);
} else if ( cmnd_to_send == CMND_READ_ADDRESS) {
printf("\nPRU data space 0x%08x reads 0x%08x dec %d\n",
shared_ram[PARAM1], shared_ram[PARAM3],
shared_ram[PARAM3]);
//decode_some_registers(shared_ram[PARAM1], shared_ram[PARAM3]);
}
}
void disp_shared_ram_state(){
//printf("share0 = %10d 0x%08x\n", shared_ram[0 ],
shared_ram[0 ] );
printf("param1 = %12d 0x%08x", shared_ram[PARAM1],
shared_ram[PARAM1] );
printf(" test1 = %12d 0x%08x\n", shared_ram[TEST1],
shared_ram[TEST1] );
printf("param2 = %12d 0x%08x", shared_ram[PARAM2],
shared_ram[PARAM2] );
printf(" test2 = %12d 0x%08x\n", shared_ram[TEST2],
shared_ram[TEST2] );
printf("param3 = %12d 0x%08x", shared_ram[PARAM3],
shared_ram[PARAM3] );
printf(" test3 = %12d 0x%08x\n", shared_ram[TEST3],
shared_ram[TEST3] );
}
// when there are arguments given to the ltcsrv, they are commands for
the pru and up to 3 parameters
// Just numbers. pass them on to the PRU and display the results.
void run_pru_cmnd( int argc, char *argv[]){
int i;
// printf("entered run_pru_cmnd()\n");
// printf("\nStatus before running PRU command: "); // Cannot be
done later b/c we might change params for
// a prog that
still might run.
// display_status(); // this will wait
until PRU program is no longer busy.
if (shared_ram[STATUS] == STAT_BUSY){
printf("PRU program is already busy. Try to abort? (y/ any
key)\n");
if (getchar() == 'y'){
shared_ram[COMMAND] = CMND_ABORT;
printf("trying to abort it and exit\n");
exit (-1);
} else {
printf("waiting...\n");
while (shared_ram[STATUS] == STAT_BUSY) {};
}
}
//printf("Leftover command word before launching new command: ");
//display_cmnd(shared_ram[COMMAND]);
cmnd_to_send = argv[1][0]; // atoi(argv[1]);
printf("\ncommand to send: ");
display_cmnd(cmnd_to_send);
if (cmnd_to_send == CMND_CLEAR_RAM){
// this works locally just to fill it with FFFF.
// The PRU will need a restart after that.
for (i=0; i < 3*1024; i++) shared_ram[i] = 0xffffffff;
for (i=0; i < 4*1024; i++) pru_ram[i] = 0xfffffff0;
printf("\nthat was no real command, just wiped out PRU data and
shared RAM\n");
printf("to make a nice background for the memory dumps. restart
the PRU.\n");
printf("exiting.\n");
exit (0);
}
// printf("\nnach command2send\n");
if (argc == 3){
shared_ram[PARAM1] = num_to_int(argv[2]);
} else if (argc == 4){
shared_ram[PARAM1] = num_to_int(argv[2]);
shared_ram[PARAM2] = num_to_int(argv[3]);
} else if (argc == 5){
shared_ram[PARAM1] = num_to_int(argv[2]);
shared_ram[PARAM2] = num_to_int(argv[3]);
shared_ram[PARAM3] = num_to_int(argv[4]);
} else if (argc >= 6){
printf("argc too large: %d, giving up\n", argc);
exit(-1);
}
shared_ram[TEST1] = -1;
shared_ram[TEST2] = -2;
shared_ram[TEST3] = -3;
// printf("huhuh\n");
// nicht existierende argv anzufassen führt zu segfault.
// printf("%d %d %d \n", atoi(argv[1]), atoi(argv[2]),
atoi(argv[3]));
// for (int k= 0; k<8; k++) printf("\nshared ram[%d] = 0x%x %d",
k, shared_ram[k], shared_ram[k]);
// printf("\n");
// now display & safe the pre-conditions.
disp_shared_ram_state();
// copy_pru_ram_to_file("pre_pru.txt");
// copy_shared_ram_to_file("pre_shared.txt");
//-------------------------------------------------------------------------------
//printf("\nKicking it off\n");
shared_ram[COMMAND] = cmnd_to_send; // Now trigger the action.
command_postprocessing();
printf("\nStatus after running PRU command: ");
display_status(); // this will wait until PRU program is no
longer busy.
//printf("Hopefully cleared command word after execution: ");
//display_cmnd(shared_ram[COMMAND]);
disp_shared_ram_state();
// printf("copying shared ram to file\n");
copy_pru_ram_to_file("post_pru.txt");
copy_shared_ram_to_file("post_shared.txt");
exit(0);
} // run_pru_cmnd()
int open_pru(){
int i;
//if (verbose) printf("enter open_pru()\n");
if (init_BBB_pins()) return 1;
// map the shared ram into our virtual memory
dev_mem_fd = open("/dev/mem",O_RDWR | O_SYNC);
// mmap params:
// address where the kernel creates the mapping. NULL= do as you like
// size of the mapped region 12288 = 12 KBytes
// protection
// flags
// file descriptor von /dev/mem
// pru-base = 0x4A30_0000, shared ram starts at +0x10000
shared_ram = (int *) mmap(NULL, 12*1024, PROT_READ | PROT_WRITE,
MAP_SHARED,
dev_mem_fd, 0x4A300000 + 0x10000);
if (-1 == (int)shared_ram) panic("could not mmap() shared PRU ram");
// both PRU local data rams together
pru_ram = (int *) mmap(NULL, 2*8*1024, PROT_READ | PROT_WRITE,
MAP_SHARED,
dev_mem_fd, 0x4A300000 + 0x00000);
if (-1 == (int)pru_ram) panic("could not mmap() local PRU rams");
return 0;
}
int close_pru(void){
// FIXME: shared RAM must be un-mapped and file descriptors should
be closed
if (verbose) printf("enter close_pru()\n");
// if (!stop_pru()) return 1;
if (verbose) printf("leaving close_pru()\n");
return 0;
}
--
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/98d0fac4-809e-1db1-9954-5194dacd7baa%40hoffmann-hochfrequenz.de.