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, g...@hoffmann-hochfrequenz.de 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 beagleboard+unsubscr...@googlegroups.com. To view this discussion on the web visit https://groups.google.com/d/msgid/beagleboard/20f8b793-6549-4708-a355-8f56322a4b93n%40googlegroups.com.