Am 20.11.18 um 16:36 schrieb fred.p.gome...@gmail.com:

I am developing an application on the beagle bone for reading data for an SPI slave. For that, I have to use the PRU since the data transmission is up to 15 KHz.

Very interesting. I could not make the SPI say a single word. :-(   I had some leftover space

in a CPLD so I implemented a serial->par converter and now I read in my ADC bytewise

over R30 7 downto 0 in PRU 1. I now also get the 100 MBit/sec I originally wanted instead of 48 Mbit/s only.


The memory access works here this way:

ARM side:

int                dev_mem_fd;
volatile int    *shared_ram;
volatile int    *pru_ram;            // the 8 KB local data = 2 KWORDS

...

#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>

    // map the shared ram into our virtual memory
    dev_mem_fd = open("/dev/mem",O_RDWR | O_SYNC);

    // mmap params:
    // addres where the kernel creates the mapping. NULL= do as you like
    // size of the mapped region  12288 = 12 KBytes
    // protection
    // flags
    // file descriptor of /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");

...
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
}

I access the few words that I need in the shared RAM simply as

#define COMMAND 5   /* offset for integers */

shared_ram[COMMAND] = .....

...

// something like this may be needed to configure the SPI pins:

    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

...

...

PRU side:    (probably you don't need everything)


#include <stdint.h>
#include <pru_cfg.h>
#include "resource_table_empty.h"


typedef struct {
    int revision;            // 0
    int filler1 [3];
    int sysconfig;            // 0x10
    int filler2[3];
    int eoi;                // 0x20
    int irqstatus_raw_o;
    int irqstatus_raw_1;
    int irqstatus_0;
    int irqstatus_1;
    int irqstatus_set_0;
    int irqstatus_set_1;
    int irqstatus_clr_0;
    int irqstatus_clr_1;
    int irqwaken_0;
    int irqwaken_1;            // 0x48
    int filler3[0x32];
    int sysstatus;            // 0x114
    int filler4[0x06];
    int ctrl;                // 0x130
    int oe;
    int datain;
    int dataout;
    int leveldetect_0;
    int leveldetect_1;
    int risingdetect;
    int fallingdetect;
    int debounceEnable;
    int debouncingtime;        // 0x154
    int filler5[0x0e];
    int cleardataout;        // 0x190
    int setdataout;            // 0x194
} gpioregs;



typedef struct {            // the order MATTERS!!!
    int revision;            // 0
    char filler1 [0x10c];
    int sysconfig;            // 0x110
    int sysstatus;            // 0x114
    int irqstatus;            // 0x118
    int irqenable;            // 0x11c
    char filler2[4];
    int syst;                // 0x124
    int modulctrl;            // 0x128

    int ch0conf;            // 0X12C
    int ch0stat;            // 0x130
    int ch0ctrl;            // 0x134
    int tx0;                // 0x138   ch0 fifo transmit buffer register
    int rx0;                // 0x13c   ch0 fifo receive  buffer register

    int ch1conf;            // 0x140
    int ch1stat;
    int ch1ctrl;
    int tx1;
    int rx1;

    int ch2conf;            // 0x154
    int ch2stat;
    int ch2ctrl;
    int tx2;
    int rx2;

    int ch3conf;            // 0x168
    int ch3stat;
    int ch3ctrl;
    int tx3;
    int rx3;

    int xferlevel;            // 0x17c
    int daftx;                // 0x180  DMA address aligned FIFO transmitter reg
    char filler3[28];
    int dafrx;                // 0x1A0
} spiregs;


volatile spiregs  * const spi0         = (volatile spiregs *) 0x48030000;    // constants are stored at PRU-RAM offset 0x100 volatile spiregs  * const spi1         = (volatile spiregs *) 0x481A0000;    // offset 104

volatile gpioregs * const gpio0     = (volatile gpioregs *) 0x44E07000;    // offset 108 volatile gpioregs * const gpio1     = (volatile gpioregs *) 0x4804C000;     // user LEDs live here
volatile gpioregs * const gpio2     = (volatile gpioregs *) 0x481AC000;
volatile gpioregs * const gpio3     = (volatile gpioregs *) 0x481AE000;


// bit positions of the user LEDs in the GPIO 1 block. Calling them USER LEDs is outright wrong. // You can use them anyway. Just don't get irritated when you don't expect them to light.

//    USER0 is the heartbeat indicator from the Linux kernel.
//    USER1 turns on when the SD card is being accessed
//    USER2 is an activity indicator. It turns on when the kernel is not in the idle loop.
//    USER3 turns on when the onboard eMMC is being accessed.


#define USR_LED0 (1<<21)
#define USR_LED1 (1<<22)
#define USR_LED2 (1<<23)
#define USR_LED3 (1<<24)

// GPIO, Clearing or setting takes about 40 nsec
#define PROG_ENA   (1<<2)
#define USE_CHAN_B (1<<4)

// per default, SPI gets no power nor clock.
// spi clock control registers in power, reset & clock management
// CM_PER clock module peripheral registers

volatile unsigned int *const cm_per_spi0_clk_ctrl = (volatile unsigned int *)(0x44E00000 + 0x4c); volatile unsigned int *const cm_per_spi1_clk_ctrl = (volatile unsigned int *)(0x44E00000 + 0x50);

volatile register unsigned int __R30;        // CPU register R30 connects directly to some output pins volatile register unsigned int __R31;        // CPU register R31 connects directly to some input pins

// some highly visible data to find out where the C compiler stores it's stuff: // variables in main end up on the stack. We only have 0x100 bytes by default. // global variables are on the heap. Stack and heap are on the bottom of the PRU data RAM.

volatile int      heapmarker = 0x22222222;
volatile char     *bla = "HEAP @ @ @ ";
int             i;
volatile int     *pipo_pointer;
int             pipo_offset;


// my communication registers between ARM CPU and the PRU
// The ARM deposits command codes in *command

volatile int * const command     = (volatile int *) (0x10000 + 4*COMMAND);    // start of shared data ram is 0x10000 PRU-local
volatile int * const status      = (volatile int *) (0x10000 + 4*STATUS);
volatile int * const errcode    = (volatile int *) (0x10000 + 4*ERRCODE);

....



void main(void) {
                                                // so you can find it in a memory dump:     volatile int  stackmarker = 0x11111111;        // That ends up in PRUram, offset 0F8.                                                 // The more variables one declares, the lower this sinks.
    int buffered_cmnd;
    int i;
    volatile int stackmarker2 = 0x11111112;

    // Clear SYSCFG[STANDBY_INIT] to enable OCP master port access by the PRU     // so that the PRU can access external memories. Each PRU has one OCP master port,     // There is also an OCP slave port so that the ARM CPU can access the PRU local bus.
    // OCP means open core protocol, a hardware module interface spec.
    // I have the gut feeling that it may take some clocks to be effective. (race condition?)

    CT_CFG.SYSCFG_bit.STANDBY_INIT = 0;



    * (int *) 0        = 0xdeadbeef;            // the NIL pointer, that is pru data ram offset 0, stack segment
    shared_ram[0]    = 0x01010101;            // That works.

    *status          = STAT_INITIALIZING;      // until init is done
    *command        = CMND_NONE;
    *ping_full = 0;
    *pong_full = 0;
    gpio0->setdataout     = USE_CHAN_B;            // use 24 bit ADC channel
    gpio0->cleardataout    = PROG_ENA;

.....

somewhere in my PRU command interpreter:

(someone else had problems accessing the LEDs from PRU)

           case CMND_BLINK_FAST:
            // USR3 LED is the one of the block of 4  closest to Ethernet connector             // We do not have the user LEDs exclusively, this one also lights shortly for EMMC accesses.

                *status  = STAT_BUSY;
                *test1  = 999;            // I had doubts about the control flow ...  :-(
                for(i=0; i<500; i++) {

                    if (*command == CMND_ABORT) break;
                    gpio1->setdataout = USR_LED3;
                    us_delay(50000);                // 50 msec

                    gpio1->cleardataout = USR_LED3;
                    us_delay(50000);
                }

                *status  = STAT_RDY_FOR_CMND;
                *command = CMND_NONE;
                break;

Hope it helps & best regards,

Gerhard




--
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/ef8ba5c4-8162-20f3-3a30-9fe89d6accea%40hoffmann-hochfrequenz.de.
For more options, visit https://groups.google.com/d/optout.

Reply via email to