I use one of the PRUs on the AM335x to control the 4 GPIO pins on the BeagleBone (GPIO1_2, GPIO1_3, GPIO1_6, GPIO1_7), and I want to synchronize the edge transitions (my full source code is at the bottom).
Using Beaglebone to set the output HI on the output, you set the corresponding bit to 1 at 0x4804c194, then set LO, you set the bit to 1 at 0x4804c190. Therefore, my PRU assembly code first sets the output bits of the HI, and then sets the output bits of 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
due to how many cycles are required to start each of them, the LO period is much longer than HI (50 ns versus 110 ns). Unfortunately, I'm too new to posting images, here is a link to a screenshot of the logic analyzer from the previous code
To equalize the time, I alternate setting the HI and LO bits, so that the periods are 80ns, but the transitions of HI and LO are 80ns offset from each other:
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
It also shows a screenshot of the logic analyzer of the previous code.
So my question is, how can I get edge transitions at the same time? That is, if you compare GPIO1_6 and GPIO_7, then in the center of the screenshot there will be 200 ns, when GPIO1_7 goes to LO then 50ns BEFORE, GPIO1_6 goes to HI, I would like them both to go at the same time. I don't mind slowing it down to doing it.
Here is my source code:
File: 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:
Main.c file:
#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 file:
#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_