Two problems with capturing data from eppi0 and eppi1 using list mode of dma on bf607

Anonymous
Anonymous

Hi ADI,

I have a dual-channel parallel-out adc connected to eppi0 and eppi1 with data captured to a pair of 2048 long buffers under dma. Each sample is 14 bits signed. The adc is clocked at 76MHz.

The first problem is about starting the capture.

The fs1 inputs of both eppi channels are connected to an io line so that I can start the capture on both channels simultaneously by changing the state of the io line. The problem is that, as soon as I enable the capture in software, the eppi/dma starts running, before I set the fs1 line.

I presume this is a problem with my config but have been unable to find a config that works so could somebody at ADI please look at the settings and see if they can spot the mistake?


The second problem is to do with capturing the data.

With an input to the adc of 37.109kHz, there should be precisely one cycle captured in 2048 samples, however I get two cycles in a buffer. (The frequencies of the input and clock verified by oscilloscope). The interval between irqs is also double what is should be, so it seems that the hardware is only capturing every second sample.

I suspect that there is something wrong with my EPPI or DMA settings but cannot find out what it is.

Could you somebody at ADI take a look and see if they can see something wrong.

I have pasted the setup items extracted from my code below.

The settings are in dma.c

The processor clock is set to max with calls to
            adi_pwr_Init(25000000, 500000000, 250000000, 0);
            adi_pwr_SetFreq(500000000, 250000000);

Regards, John


#pragma pack(4)  /* pack as in adi example code */
typedef struct
    {
    void * descptr_nxt;
    void * addrstart;
    uint32_t cfg;
    uint32_t xcnt;
    uint32_t xmod;
    uint32_t ycnt;
    uint32_t ymod;
    } dma_descriptor;
#pragma pack()


#if 1  /* normal mode dma writes to ram */
    #define DMA_DIRECTION ENUM_DMA_CFG_WRITE
#else  /* test only mode ram left unchanged by dma */
    #define DMA_DIRECTION ENUM_DMA_CFG_READ
#endif

/* long to set the dma config value in the descriptors and register
 * not all bits in the register are used */
#define DMA_CFG_SETTING (0 \
    | ENUM_DMA_CFG_PDAT_NOTFWD /* don't forward */ \
    | ENUM_DMA_CFG_ADDR1D /* 1 dimension */ \
    | ENUM_DMA_CFG_NO_COPY /* never copy ? TODO check */ \
    | ENUM_DMA_CFG_TOV_DIS /* ignore overruns */ \
    | ENUM_DMA_CFG_NO_TRIG /* no trigger */ \
    | ENUM_DMA_CFG_XCNT_INT /* interrupt on xcnt 0 */ \
    | ENUM_DMA_CFG_FETCH07 /* fetch all 7 descriptor elements */ \
    | ENUM_DMA_CFG_NO_TRGWAIT /* don't wait for trigger */ \
    | ENUM_DMA_CFG_DSCLIST /* descriptor list flow mode */ \
    | ENUM_DMA_CFG_MSIZE02 /* memory size 2 bytes */ \
    | ENUM_DMA_CFG_PSIZE02 /* peripheral size 2 bytes */ \
    /* | ENUM_DMA_CFG_MSIZE04 * memory size 4 bytes */ \
    /* | ENUM_DMA_CFG_PSIZE04 * peripheral size 4 bytes */ \
    | ENUM_DMA_CFG_LD_STARTADDR /* load start address */ \
    | ENUM_DMA_CFG_SYNC /* clears the fifo on first descriptor */ \
    | DMA_DIRECTION /* read or write eppi from memory */ \
    | 0)


/* eppi register settings for both eppi0 and eppi1 */
#define EPPI_CFG_SETTING (0 \
    | ENUM_EPPI_CTL_CLKGATE_DIS  /* CLKGATEN: Disable */ \
    | ENUM_EPPI_CTL_MUXSEL0      /* MUXSEL: Normal Operation */ \
    | ENUM_EPPI_CTL_FINISH_DIS   /* DMAFINEN: No Finish Command */ \
    | ENUM_EPPI_CTL_DMA1CHAN     /* DMACFG: PPI uses one DMA Channel */ \
    | ENUM_EPPI_CTL_RGBFMT_DIS   /* RGBFMTEN: Disable RGB Formatted Output */ \
    | ENUM_EPPI_CTL_NO_WORDSPLIT /* SPLTWRD: PPI_DATA has (DLEN-1) bits of */ \
    | ENUM_EPPI_CTL_NO_SUBSPLIT  /* SUBSPLTODD: Disable */ \
    | ENUM_EPPI_CTL_SPLTEO_DIS   /* SPLTEO: Do Not Split Samples */ \
    | ENUM_EPPI_CTL_SWAP_DIS     /* SWAPEN: Disable */ \
    | ENUM_EPPI_CTL_PACK_EN      /* PACKEN: Enable */ \
    | ENUM_EPPI_CTL_SKIPODD      /* SKIPEO: Skip Odd Samples */ \
    | ENUM_EPPI_CTL_NO_SKIP      /* SKIPEN: No Samples Skipping */ \
    | ENUM_EPPI_CTL_NO_MIRROR    /* DMIRR: No Data Mirroring */ \
    | ENUM_EPPI_CTL_DLEN14       /* DLEN: 14 bits */ \
    /*| ENUM_EPPI_CTL_FS1LO_FS2LO   POLS: FS1 and FS2 are active high */ \
    | ENUM_EPPI_CTL_FS1HI_FS2HI   /* ccPOLS: FS1 and FS2 are active high */ \
    | ENUM_EPPI_CTL_POLC11       /* POLC: Clock/Sync polarity mode 3 */ \
    | ENUM_EPPI_CTL_SIGNEXT      /* SIGNEXT: Sign Extended */ \
    | ENUM_EPPI_CTL_EXTFS         /* IFSGEN: External Frame Sync */ \
    | ENUM_EPPI_CTL_EXTCLK        /* ICLKGEN: External Clock */ \
    | ENUM_EPPI_CTL_NO_BLANKGEN  /* BLANKGEN: Disable */ \
    | ENUM_EPPI_CTL_INTERLACED   /* ITUTYPE: Interlaced */ \
    /* docs suggest that this must be 1 for ext trigger */ \
    | ENUM_EPPI_CTL_FLDSEL_LO    /* FLDSEL: Field Mode 0 */ \
    | ENUM_EPPI_CTL_SYNC0        /* FSCFG: Sync Mode 0 */ \
    | ENUM_EPPI_CTL_NON656       /* XFRTYPE: Non-ITU656 Mode (GP Mode) */ \
    | ENUM_EPPI_CTL_RXMODE       /* DIR: Receive Mode */ \
    | ENUM_EPPI_CTL_DIS          /* EN: Disable */ \
    | 0)


#define NUM_DESC 4  /* 4 descriptors per DMA channel*/

/* Number of bytes to copy per descriptor */
#define BYTES_PER_DESC (EPPI_BLOCK_LENGTH * 2)

/* Word/Memory transfer size to use */
#define MSIZE ADI_DMA_MSIZE_2BYTES
#define MSIZE_IN_BYTES (2u)

#pragma align 4  /* align as in adi example code */
static dma_descriptor eppi_0_descriptor_list[NUM_DESC];
static dma_descriptor eppi_1_descriptor_list[NUM_DESC];


static void prepare_descriptors(void) {
    int32_t i;
    /* Populate List descriptor instances with common values */
    for (i = 0; i < NUM_DESC; i++)
    {
        eppi_0_descriptor_list[i].cfg = DMA_CFG_SETTING | ENUM_DMA_CFG_EN;
        eppi_0_descriptor_list[i].xcnt = (BYTES_PER_DESC / MSIZE_IN_BYTES);
        eppi_0_descriptor_list[i].xmod = MSIZE_IN_BYTES;
        eppi_0_descriptor_list[i].ycnt = 0;
        eppi_0_descriptor_list[i].ymod = 0;

        eppi_1_descriptor_list[i].cfg = DMA_CFG_SETTING | ENUM_DMA_CFG_EN;
        eppi_1_descriptor_list[i].xcnt = (BYTES_PER_DESC / MSIZE_IN_BYTES);
        eppi_1_descriptor_list[i].xmod = MSIZE_IN_BYTES;
        eppi_1_descriptor_list[i].ycnt = 0;
        eppi_1_descriptor_list[i].ymod = 0;
    }
    /* Now customise each to point to the correct memory area */
    eppi_0_descriptor_list[0].addrstart = (void *)CORE0_FIRST_CURRENT;
    eppi_0_descriptor_list[0].descptr_nxt = &eppi_0_descriptor_list[1];
    eppi_0_descriptor_list[1].addrstart = (void *)CORE1_FIRST_CURRENT;
    eppi_0_descriptor_list[1].descptr_nxt = &eppi_0_descriptor_list[2];
    eppi_0_descriptor_list[2].addrstart = (void *)CORE0_SECOND_CURRENT;
    eppi_0_descriptor_list[2].descptr_nxt = &eppi_0_descriptor_list[3];
    eppi_0_descriptor_list[3].addrstart = (void *)CORE1_SECOND_CURRENT;
    eppi_0_descriptor_list[3].descptr_nxt = &eppi_0_descriptor_list[0];

    eppi_1_descriptor_list[0].addrstart = (void *)CORE0_FIRST_VOLTAGE;
    eppi_1_descriptor_list[0].descptr_nxt = &eppi_1_descriptor_list[1];
    eppi_1_descriptor_list[1].addrstart = (void *)CORE1_FIRST_VOLTAGE;
    eppi_1_descriptor_list[1].descptr_nxt = &eppi_1_descriptor_list[2];
    eppi_1_descriptor_list[2].addrstart = (void *)CORE0_SECOND_VOLTAGE;
    eppi_1_descriptor_list[2].descptr_nxt = &eppi_1_descriptor_list[3];
    eppi_1_descriptor_list[3].addrstart = (void *)CORE1_SECOND_VOLTAGE;
    eppi_1_descriptor_list[3].descptr_nxt = &eppi_1_descriptor_list[0];
}


void enable_capture(void) {
    /* ensure any outstanding irqs are cleared (there should be none) */
    *(volatile uint32_t *)pREG_DMA29_STAT = 0x1;
    *(volatile uint32_t *)pREG_EPPI0_STAT = 0xFF;
    *(volatile uint32_t *)pREG_DMA33_STAT = 0x1;
    *(volatile uint32_t *)pREG_EPPI1_STAT = 0xFF;
    set_capture_finished(false);
    #if ENABLE_CAPTURE == 1
            *pREG_DMA29_CFG |= BITM_DMA_CFG_EN;
            *pREG_DMA33_CFG |= BITM_DMA_CFG_EN;
            *pREG_EPPI0_CTL |= BITM_EPPI_CTL_EN;
            *pREG_EPPI1_CTL |= BITM_EPPI_CTL_EN;
    #endif
    /* now need to trigger the capture with the fs1 line which should
       then be ignored */
    gpio_write_nppi_fs1(1);
    gpio_write_nppi_fs1(0);
}


void initialise_dma(void) {
    /* Prepare descriptors for EPPI capture */
    prepare_descriptors();
    /* EPPI 0 uses DMA channel 29 */
    *(volatile uint32_t *)REG_DMA29_DSCPTR_NXT = \
        (uint32_t)&eppi_0_descriptor_list[0];
    *(volatile uint32_t *)REG_DMA29_CFG = DMA_CFG_SETTING;
    *(volatile uint32_t *)REG_DMA29_BWLCNT = 0;
    /* EPPI 1 uses DMA channel 33 */
    *(volatile uint32_t *)REG_DMA33_DSCPTR_NXT = \
        (uint32_t)&eppi_1_descriptor_list[0];
    *(volatile uint32_t *)REG_DMA33_CFG = DMA_CFG_SETTING;
    *(volatile uint32_t *)REG_DMA33_BWLCNT = 0;
    /* all setup so enable them */
    *(volatile uint32_t *)REG_DMA29_CFG =
        (DMA_CFG_SETTING & (~(BITM_DMA_CFG_INT | BITM_DMA_CFG_EN)));
    *(volatile uint32_t *)REG_DMA33_CFG =
        (DMA_CFG_SETTING & (~(BITM_DMA_CFG_INT | BITM_DMA_CFG_EN)));
    gpio_write_nppi_fs1(0);
}


void initialise_eppi(void) {
    /* Initialise the eppi registers
     * this only sets those that seem important but I might be wrong....
    */
    *(volatile uint32_t *)REG_EPPI0_CTL = EPPI_CFG_SETTING;
    *(volatile uint32_t *)REG_EPPI1_CTL = EPPI_CFG_SETTING;
    /*The EPPI_HDLY register contains the number of clock cycles to delay after
      the assertion of PPI_FS1 is detected before starting to read data. */
    *(volatile uint32_t *)REG_EPPI0_HDLY = 0;
    *(volatile uint32_t *)REG_EPPI1_HDLY = 0;
    /* The EPPI_CLKDIV register provides the divisor for EPPI internal clock
       generation. The generated clock frequency is given by following formula:
       PPI_CLK = (SCLK) / (2 * (EPPI_CLKDIV + 1)) */
    *(volatile uint32_t *)REG_EPPI0_CLKDIV = 0;
    *(volatile uint32_t *)REG_EPPI1_CLKDIV = 0;
    /* from ADI example */
    *pREG_EPPI0_IMSK = 0xFF;
    *pREG_EPPI1_IMSK = 0xFF;

    *pREG_EPPI0_LINE = 0;
    *pREG_EPPI0_HCNT = 0;
    *pREG_EPPI0_FRAME = 0;
    *pREG_EPPI0_VCNT =  0;
    *pREG_EPPI0_VDLY =  0;
    *pREG_EPPI0_FS1_WLHB = 0;
    *pREG_EPPI0_FS1_PASPL = 0;
    *pREG_EPPI0_FS1_DLY = 0;

    *pREG_EPPI1_LINE = 0;
    *pREG_EPPI1_HCNT = 0;
    *pREG_EPPI1_FRAME = 0;
    *pREG_EPPI1_VCNT =  0;
    *pREG_EPPI1_VDLY =  0;
    *pREG_EPPI1_FS1_WLHB = 0;
    *pREG_EPPI1_FS1_PASPL = 0;
    *pREG_EPPI1_FS1_DLY = 0;
}