2013-07-23 83 views
4

我正在使用AM335x上的一个PRU单元来驱动BeagleBone(GPIO1_2,GPIO1_3,GPIO1_6,GPIO1_7)上的4个GPIO引脚,并且我想同步边沿转换(我的完整源代码在底部)。BeagleBone GPIO输出与PRU同步(TI AM335x)

使用Beaglebone在引脚上设置输出HI,将地址0x4804c194的对应位设置为1,然后将其设置为LO,将地址0x4804c190处的位设置为1。因此,我的PRU汇编代码首先设置输出HI位,然后将输出LO位:

MOV r4, GPIO1 | GPIO_CLEARDATAOUT 
MOV r5, GPIO1 | GPIO_SETDATAOUT  
... 
... 
//Loop the following: 
MAIN_LOOP: 
    LBCO r2, CONST_PRUDRAM, r1, 8//Read in LO and HI data into r2/r3 
    SBBO r3, r5, 0, 1 //Write HI data 
    SBBO r2, r4, 0, 1 //Write LO data 
    ADD r1, r1, 8 
    QBEQ EXIT, r1, 112 //Done? Exit 
    QBA MAIN_LOOP 

由于它需要多少个周期来运行的每一个,所述LO周期显著长于HI(50ns的VS 110ns,从而)。不幸的是,我太新了,无法发布图像,here is a link to a logic analyzer screenshot from the previous code

即使超时,我在设置HI和LO位之间交替,因此周期在80ns时相等,但HI和LO转换彼此偏移80ns :

MOV r4, GPIO1 | GPIO_CLEARDATAOUT 
MOV r5, GPIO1 | GPIO_SETDATAOUT  
... 
... 
//Loop the following: 
MAIN_LOOP: 
    LBCO r2, CONST_PRUDRAM, r1, 8 //Read in LO and HI data into r2/r3 
    SBBO r3, r5, 0, 1 //Write HI data 
    SBBO r2, r4, 0, 1 //Write LO data 
    ADD r1, r1, 8 
    QBEQ EXIT, r1, 112 
    QBA MAIN_LOOP2 

MAIN_LOOP2: 
    LBCO r2, CONST_PRUDRAM, r1, 8 //Read in LO and HI data into r2/r3 
    SBBO r2, r4, 0, 1 //Write LO data 
    SBBO r3, r5, 0, 1 //Write HI data 
    ADD r1, r1, 8 
    QBEQ EXIT, r1, 112 
    QBA MAIN_LOOP 

Here too is a logic analyzer screenshot of the previous code.

所以我的问题是我怎样才能到发生在同一时间边缘过渡?即如果您比较GPIO1_6和GPIO_7,那么在GPIO1_7转换LO然后50ns BEFORE,GPIO1_6转换HI时,屏幕截图的中心位置为200ns,我希望它们都同时转换。我不介意放慢速度来实现这一目标。

这里是我的源代码:

文件:main.p

.origin 0 
.entrypoint START 

#include "main.hp" 

#define GPIO1 0x4804c000 
#define PINMUX 0x44E10800 

#define GPIO_CLEARDATAOUT 0x190 
#define GPIO_SETDATAOUT 0x194 
#define GPIO_DIRECTION 0x134 
#define GPIO_DIRECTION2 0x142 


START: 
    //clear STANDBY_INIT bit 
    LBCO r0, C4, 4, 4 
    CLR r0, r0, 4 
    SBCO r0, C4, 4, 4 

    //TODO SET the pin(s) direction to OUTPUT, currently sets ALL bits to output 
    MOV r4, GPIO1 | GPIO_DIRECTION 
    MOV r7, 0x00000000 
    SBBO r7, r4, 0, 4 
    MOV r4, GPIO1 | GPIO_DIRECTION2 
    SBBO r7, r4, 0, 4 

    //TODO SET the pins to GPIO Mode aka MODE 7, i.e. GPIO1_6 to mode GPIO1_6 

    MOV r4, GPIO1 | GPIO_CLEARDATAOUT 
    MOV r5, GPIO1 | GPIO_SETDATAOUT 

    //Read in number of patterns into R20 
    LBCO r20, CONST_PRUDRAM, 0, 4 

    //Set R1 to 4bytes 
    MOV r1, 32 

MAIN_LOOP: 
    //Read pin data into r2/r3 
    LBCO r2, CONST_PRUDRAM, r1, 8 
    //Set Pin outputs by writing to the GPIO1 memory 
    //SBBO r2, r4, 0, 8 
    SBBO r3, r5, 0, 1 
    SBBO r2, r4, 0, 1 
    //Increment Pin Data to next 8 bytes 
    ADD r1, r1, 8 
    //Check if done, after 80bytes 
    QBEQ EXIT, r1, 112 
    QBA MAIN_LOOP2 
    //QBA MAIN_LOOP //To get first screenshot, comment line before & uncomment this 

MAIN_LOOP2: 
    //Read pin data into r2/r3 
    LBCO r2, CONST_PRUDRAM, r1, 8 
    //Set Pin outputs by writing to the GPIO1 memory 
    //SBBO r2, r4, 0, 8 
    SBBO r2, r4, 0, 1 
    SBBO r3, r5, 0, 1 
    //Increment Pin Data to next 8 bytes 
    ADD r1, r1, 8 
    //Check if done, after 80bytes 
    QBEQ EXIT, r1, 112 
    QBA MAIN_LOOP 

EXIT: 

#ifdef AM33XX 
    // Send notification to Host for program completion 
    MOV R31.b0, PRU0_ARM_INTERRUPT+16 
#else 
    MOV R31.b0, PRU0_ARM_INTERRUPT 
#endif 
HALT 

main.c文件:

#include <stdio.h> 
// Driver header file 
#include <prussdrv.h> 
#include <pruss_intc_mapping.h> 

#define PRU_NUM   0 
#define AM33XX 

static int LOCAL_exampleInit(); 

static void *pruDataMem; 
static unsigned int *pruDataMem_int; 

int main (void) 
{ 
    unsigned int pindata[12]; 
    unsigned int pinmask = 0; 
    int j = 0; 

    unsigned int ret, i; 
    tpruss_intc_initdata pruss_intc_initdata = PRUSS_INTC_INITDATA; 

    /* Initialize the PRU */ 
    printf("\nINFO: Starting %s.\r\n", "main"); 
    prussdrv_init(); 

    /* Open PRU Interrupt */ 
    ret = prussdrv_open(PRU_EVTOUT_0); 
    if (ret) 
    { 
     printf("prussdrv_open open failed\n"); 
     return (ret); 
    } 

    /* Get the interrupt initialized */ 
    prussdrv_pruintc_init(&pruss_intc_initdata); 

    /* Initialize memory */ 
    printf("\tINFO: Initializing.\r\n"); 
    LOCAL_Init(); 

    pruDataMem_int[0] = 10; //ignored 

    //Load up the pin data 
    pruDataMem_int[4] = 0x88; 
    pruDataMem_int[5] = 0x44; 

    pruDataMem_int[6] = 0x44; 
    pruDataMem_int[7] = 0x88; 
    pruDataMem_int[8] = 0x88; 
    pruDataMem_int[9] = 0x44; 

    pruDataMem_int[10] = 0x44; 
    pruDataMem_int[11] = 0x88; 
    pruDataMem_int[12] = 0x88; 
    pruDataMem_int[13] = 0x44; 

    pruDataMem_int[14] = 0x44; 
    pruDataMem_int[15] = 0x88; 
    pruDataMem_int[16] = 0x88; 
    pruDataMem_int[17] = 0x44; 

    pruDataMem_int[18] = 0x44; 
    pruDataMem_int[19] = 0x88; 
    pruDataMem_int[20] = 0x88; 
    pruDataMem_int[21] = 0x44; 
    pruDataMem_int[22] = 0x44; 
    pruDataMem_int[23] = 0x88; 

    printf("\tINFO: Executing PRU.\r\n"); 
    prussdrv_exec_program (PRU_NUM, "main.bin"); 

    // Wait until PRU0 has finished execution 

    printf("\tINFO: Waiting for HALT command.\r\n"); 
    prussdrv_pru_wait_event (PRU_EVTOUT_0); 
    printf("\tINFO: PRU completed transfer.\r\n"); 
    prussdrv_pru_clear_event (PRU0_ARM_INTERRUPT); 

    // Disable PRU and close memory mapping 
    prussdrv_pru_disable (PRU_NUM); 
    prussdrv_exit(); 

    return(0); 
} 

static int LOCAL_Init() 
{ 
    prussdrv_map_prumem (PRUSS0_PRU0_DATARAM, &pruDataMem); 
    pruDataMem_int = (unsigned int) pruDataMem; 

    pruDataMem_int[0] = 0x00; 
    pruDataMem_int[1] = 0x00; 
    pruDataMem_int[2] = 0x00; 
    pruDataMem_int[3] = 0x00; 
    return(0); 
} 

文件main.hp:

#ifndef _main_HP_ 
#define _main_HP_ 
#define AM33XX 

#ifdef AM33XX 

// Refer to this mapping in the file - \prussdrv\include\pruss_intc_mapping.h 
#define PRU0_PRU1_INTERRUPT  17 
#define PRU1_PRU0_INTERRUPT  18 
#define PRU0_ARM_INTERRUPT  19 
#define PRU1_ARM_INTERRUPT  20 
#define ARM_PRU0_INTERRUPT  21 
#define ARM_PRU1_INTERRUPT  22 

#define CONST_PRUDRAM C24 
#define CONST_SHAREDRAM C28 
#define CONST_L3RAM  C30 
#define CONST_DDR  C31 

// Address for the Constant table Programmable Pointer Register 0(CTPPR_0) 
#define CTBIR_0   0x22020 
// Address for the Constant table Programmable Pointer Register 0(CTPPR_0) 
#define CTBIR_1   0x22024 

// Address for the Constant table Programmable Pointer Register 0(CTPPR_0) 
#define CTPPR_0   0x22028 
// Address for the Constant table Programmable Pointer Register 1(CTPPR_1) 
#define CTPPR_1   0x2202C 

#else 

// Refer to this mapping in the file - \prussdrv\include\pruss_intc_mapping.h 
#define PRU0_PRU1_INTERRUPT  32 
#define PRU1_PRU0_INTERRUPT  33 
#define PRU0_ARM_INTERRUPT  34 
#define PRU1_ARM_INTERRUPT  35 
#define ARM_PRU0_INTERRUPT  36 
#define ARM_PRU1_INTERRUPT  37 

#define CONST_PRUDRAM C3 
#define CONST_HPI  C15 
#define CONST_DSPL2  C28 
#define CONST_L3RAM  C30 
#define CONST_DDR  C31 

// Address for the Constant table Programmable Pointer Register 0(CTPPR_0) 
#define CTPPR_0   0x7028 
// Address for the Constant table Programmable Pointer Register 1(CTPPR_1) 
#define CTPPR_1   0x702C 

#endif 

.macro LD32 
.mparam dst,src 
    LBBO dst,src,#0x00,4 
.endm 

.macro LD16 
.mparam dst,src 
    LBBO dst,src,#0x00,2 
.endm 

.macro LD8 
.mparam dst,src 
    LBBO dst,src,#0x00,1 
.endm 

.macro ST32 
.mparam src,dst 
    SBBO src,dst,#0x00,4 
.endm 

.macro ST16 
.mparam src,dst 
    SBBO src,dst,#0x00,2 
.endm 

.macro ST8 
.mparam src,dst 
    SBBO src,dst,#0x00,1 
.endm 

#define sp r0 
#define lr r23 
#define STACK_TOP  (0x2000 - 4) 
#define STACK_BOTTOM (0x2000 - 0x200) 

.macro stack_init 
    mov  sp, STACK_BOTTOM 
.endm 

.macro push 
.mparam reg, cnt 
    sbbo reg, sp, 0, 4*cnt 
    add  sp, sp, 4*cnt 
.endm 

.macro pop 
.mparam reg, cnt 
    sub  sp, sp, 4*cnt 
    lbbo reg, sp, 0, 4*cnt 
.endm 
#endif //_main_HP_ 

回答

2

在与某人谈论这个问题后,解决方法是直接写入数据出注册而不是使用设置/清除数据出寄存器,那么所有的转换将在同一时间:

#define GPIO_DATAOUT 0x13C 

... 
MOV r4, GPIO1 | GPIO_DATAOUT 
... 
... 
//Loop the following: 
MAIN_LOOP: 
    LBCO r2, CONST_PRUDRAM, r1, 4//Read pin state data into r2 
    SBBO r2, r4, 0, 4 //Write pin state data to Dataout 
    ADD r1, r1, 4 
    QBEQ EXIT, r1, 112 //Done? Exit 
    QBA MAIN_LOOP 
+0

因为我们正在处理的只是GPIO,一个能只需将引脚复用到PRU,然后通过寄存器R30同时写入两者(这将需要全部5ns而不是50-200) - 当然,唯一的缺点是引脚必须被复用为输出或输入只要。看到这个例子:https://github.com/TekuConcept/PRU_Demo/blob/master/Read-from-Pin/prucode.p – TekuConcept

0

虽然你可以使用GPIO_DATAOUT寄存器,这有副作用重新设置所有的引脚,即使是你可能不想改变的引脚。但是,由于GPIO_CLEARDATAOUTGPIO_SETDATAOUT在存储器映射中相邻,因此可以在单个SBBO指令中写入它们两者。相反的:

MOV r4, GPIO1 | GPIO_CLEARDATAOUT 
MOV r5, GPIO1 | GPIO_SETDATAOUT  
... 
LBCO r2, CONST_PRUDRAM, r1, 8//Read in LO and HI data into r2/r3 
SBBO r3, r5, 0, 1 //Write HI data 
SBBO r2, r4, 0, 1 //Write LO data 

你可以做这样的(这也节省了一个寄存器,因为你不需要r4r5):

MOV r4, GPIO1 | GPIO_CLEARDATAOUT 
... 
LBCO r2, CONST_PRUDRAM, r1, 8// Read in LO and HI data into r2/r3 
SBBO r2, r4, 0, 8 // Write both LO and HI data in a single pass