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.

Reply via email to