Gehard, thank you very much!
Considering the code you've provided, I understand that:
- I need these header files:
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <unistd.h>
#include "ltcsrv.h"
#include "pru_if.h"
- A file descriptor must be used for /dev/mem:
int dev_mem_fd;
dev_mem_fd = open("/dev/mem",O_RDWR | O_SYNC);
- Shared RAM is mapped (prepared for use) by this line:
shared_ram = (int *) mmap(NULL, 12*1024, PROT_READ | PROT_WRITE,
MAP_SHARED, dev_mem_fd, 0x4A300000 + 0x10000);
- Here follows examples of usage (in this case, writing to shared ram
memory):
shared_ram[0] = ... ; //write to 0x4A310000
shared_ram[1] = ... ; //write to 0x4A310004
shared_ram[1] = ... ; //write to 0x4A310008
Am I right?
Regarding header files, I noticed the pru related headerfile has been
included as #include "pru_if.h". Is it a local file from your project or a
header file referred to a lib? In case of being referred to a lib, it could
be included as #include <pru_if.h>, right?
Best Regards,
Pedro Bertoleti
Em segunda-feira, 18 de janeiro de 2021 às 02:03:13 UTC-3,
[email protected] escreveu:
>
> 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 [email protected].
To view this discussion on the web visit
https://groups.google.com/d/msgid/beagleboard/20f8b793-6549-4708-a355-8f56322a4b93n%40googlegroups.com.