使用PRU从模拟读取所有7个输入,并使用主机C程序读取beaglebone black

时间:2014-09-25 09:07:40

标签: real-time sampling beagleboneblack adc

对于在AM335X Cortex A8处理器上运行的beaglebone黑色世界,我有点新手,我想使用PRU以最快的采样率进行快速模拟读取。

我想以循环形式阅读所有7个输入,如:

while( n*7 < sampling_rate){ //initial value for n = 0
    read(AIN0); //and store it in shared memory(7*n + 0)
    read(AIN1); //and store it in shared memory(7*n + 1)
    read(AIN2); //and store it in shared memory(7*n + 2)
    read(AIN3); //and store it in shared memory(7*n + 3)
    read(AIN4); //and store it in shared memory(7*n + 4)
    read(AIN5); //and store it in shared memory(7*n + 5)
    read(AIN6); //and store it in shared memory(7*n + 6)
    n++;
}

这样我就可以从主处理器上运行的主程序中读取它们。知道怎么做吗?我尝试从名为AM335x_pru_package的包中使用名为ADCCollector.c的现成代码,但我无法弄清楚如何获取所用寄存器的所有地址和值。

这是我试图修改的代码(ADCCollector.p):

.origin 0 // offset of the start of the code in PRU memory
.entrypoint START // program entry point, used by debugger only

#include "ADCCollector.hp"

#define BUFF_SIZE 0x00000fa0 //Total buff size: 4kbyte(Each buffer has 2kbyte: 500 piece of data
#define HALF_SIZE BUFF_SIZE / 2

#define SAMPLING_RATE 1 //Sampling rate(16khz) //***//16000
#define DELAY_MICRO_SECONDS (1000000 / SAMPLING_RATE) //Delay by sampling rate
#define CLOCK 200000000 // PRU is always clocked at 200MHz
#define CLOCKS_PER_LOOP 2 // loop contains two instructions, one clock each
#define DELAYCOUNT DELAY_MICRO_SECONDS * CLOCK / CLOCKS_PER_LOOP / 1000 / 1000 * 3  //if sampling rate = 98000 --> = 3061.224

.macro DELAY
    MOV r10, DELAYCOUNT
    DELAY:
        SUB r10, r10, 1
        QBNE DELAY, r10, 0
.endm

.macro READADC
    //Initialize buffer status (0: empty, 1: first buffer is ready, 2: second buffer is ready)
    MOV r2, 0
    SBCO r2, CONST_PRUSHAREDRAM, 0, 4 

    INITV:
        MOV r5, 0 //Shared RAM address of ADC Saving position 
        MOV r6, BUFF_SIZE  //Counting variable 

    READ:
        //Read ADC from FIFO0DATA
        MOV r2, 0x44E0D100 
        LBBO r3, r2, 0, 4 
        //Add address counting
        ADD r5, r5, 4
        //Write ADC to PRU Shared RAM
        SBCO r3, CONST_PRUSHAREDRAM, r5, 4 

        DELAY

        SUB r6, r6, 4
        MOV r2, HALF_SIZE
        QBEQ CHBUFFSTATUS1, r6, r2 //If first buffer is ready
        QBEQ CHBUFFSTATUS2, r6, 0 //If second buffer is ready
        QBA READ

    //Change buffer status to 1
    CHBUFFSTATUS1:
        MOV r2, 1 
        SBCO r2, CONST_PRUSHAREDRAM, 0, 4
        QBA READ

    //Change buffer status to 2
    CHBUFFSTATUS2:
        MOV r2, 2
        SBCO r2, CONST_PRUSHAREDRAM, 0, 4
        QBA INITV

    //Send event to host program
    MOV r31.b0, PRU0_ARM_INTERRUPT+16 
    HALT
.endm

// Starting point
START:
    // Enable OCP master port
    LBCO r0, CONST_PRUCFG, 4, 4      //#define CONST_PRUCFG      C4     taken from ADCCollector.hp
    CLR r0, r0, 4
    SBCO r0, CONST_PRUCFG, 4, 4

    //C28 will point to 0x00012000 (PRU shared RAM)
    MOV r0, 0x00000120
    MOV r1, CTPPR_0
    ST32 r0, r1

    //Init ADC CTRL register
    MOV r2, 0x44E0D040
    MOV r3, 0x00000005
    SBBO r3, r2, 0, 4

    //Enable ADC STEPCONFIG 1
    MOV r2, 0x44E0D054
    MOV r3, 0x00000002
    SBBO r3, r2, 0, 4



    //Init ADC STEPCONFIG 1
    MOV r2, 0x44E0D064
    MOV r3, 0x00000001 //continuous mode
    SBBO r3, r2, 0, 4

    //Read ADC and FIFOCOUNT
    READADC

另一个问题是:如果我只是将#define Sampling_rate从16000更改为(.p)文件中低于或等于200000的任何其他数字,我将获得该采样率?或者我应该改变其他事情?

提前致谢。

2 个答案:

答案 0 :(得分:0)

我使用了libpruio的c包装器:http://www.freebasic.net/forum/viewtopic.php?f=14&t=22501

然后使用此代码获取我的所有ADC值:

#include "stdio.h"
#include "c_wrapper/pruio.h" // include header
#include "sys/time.h"

//! The main function.
int main(int argc, char **argv) {
    struct timeval start, now;
    long mtime, seconds, useconds;    
    gettimeofday(&start, NULL);
    int i,x;
    pruIo *io = pruio_new(PRUIO_DEF_ACTIVE, 0x98, 0, 1); //! create new driver structure
    if (pruio_config(io, 1, 0x1FE, 0, 4)){ // upload (default) settings, start IO mode
      printf("config failed (%s)\n", io->Errr);}
    else {

        do {
            gettimeofday(&now, NULL);
            seconds  = now.tv_sec  - start.tv_sec;
            useconds = now.tv_usec - start.tv_usec;
            mtime = ((seconds) * 1000 + useconds/1000.0) + 0.5;
            printf("%lu",mtime);
            for(i = 1; i < 9; i++) {
                printf(",%d", io->Adc->Value[i]); //0-66504 for 0-1.8v
            }
            printf("\n"); 

            x++;
        }while (mtime < 100);

        printf("count: %d \n", x);

        pruio_destroy(io);        /* destroy driver structure */
    }
    return 0;
}

答案 1 :(得分:0)

在您的示例中,您在IO模式下使用libpruio(同步),因此您无法控制采样率,因为主机CPU无法实时工作。

要获得最大采样率(如OP中所述),您必须使用RB或MM模式。在这些模式下,libpruio将样本缓冲在内存中,主机可以异步访问它们。请参阅libpruio包中的示例rb_file.c(或triggers.bas)。