AM6442: Configuring burst transfers with norlike gpmc and udma

Part Number: AM6442
Other Parts Discussed in Thread: SYSCONFIG

Tool/software:

I am using mcupsdk-core REL.MCUSDK.10.01.00.32

I am attempting to setup the udma to do burst gpmc transfers like in figure 6-40 and 6-41 in the AM64x datasheet.
Reading on the forums imply that norlike burst mode is not supported in the drivers and you will need to use udma if you want to have consistent bursts.
I built off of the udma example at examples/drivers/udma/udma_memcpy_polling

The code below is able to do transfers to the GPMC but from the captures it looks like it is doing 16 single transfers, and it is not driving the GPMC0_CLK pin, even though burst transfers are enabled in GPMC0_CONFIG1.

Questions:

- What else needs to be modified to enable burst mode?

- What are the maximum achievable burst sizes?

- 32 bit mode is not supported in sysconfig, can I just configure the device size to 32 GPMC_CONFIG1 and pinmux the rest of the pins to enable 32 bit mode, or is there more?

Capture:

This should be burst, but is doing 16 individual transfers

GPMC0_CONFIG* registers:

(gdb) printf "%p %p\n",GPMC0_CONFIG1,*GPMC0_CONFIG1
0x3b000060 0x78000003
(gdb) printf "%p %p\n",GPMC0_CONFIG2,*GPMC0_CONFIG2
0x3b000064 0x10001
(gdb) printf "%p %p\n",GPMC0_CONFIG3,*GPMC0_CONFIG3
0x3b000068 0x22060514
(gdb) printf "%p %p\n",GPMC0_CONFIG4,*GPMC0_CONFIG4
0x3b00006c 0x305e016
(gdb) printf "%p %p\n",GPMC0_CONFIG5,*GPMC0_CONFIG5
0x3b000070 0x10f1111
(gdb) printf "%p %p\n",GPMC0_CONFIG6,*GPMC0_CONFIG6
0x3b000074 0x8f000000
(gdb) printf "%p %p\n",GPMC0_CONFIG7,*GPMC0_CONFIG7
0x3b000078 0xf50

Code:

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
#include <drivers/gpio.h>
#include <drivers/gpmc/v0/cslr_gpmc.h>
#include <drivers/gpmc/v0/gpmc.h>
#include <drivers/hw_include/cslr.h>
#include <drivers/soc.h>
#include <kernel/dpl/AddrTranslateP.h>
#include "ti_drivers_config.h"
#include "ti_drivers_open_close.h"
#include <string.h>

#define UDMA_TEST_NUM_BYTES             (16U)
#define UDMA_TEST_TRPD_SIZE             (UDMA_GET_TRPD_TR15_SIZE(1U))
uint8_t gUdmaTestTrpdMem[UDMA_TEST_TRPD_SIZE] __attribute__((aligned(UDMA_CACHELINE_ALIGNMENT)));
uint8_t gUdmaTestSrcBuf[UDMA_ALIGN_SIZE(UDMA_TEST_NUM_BYTES)] __attribute__((aligned(UDMA_CACHELINE_ALIGNMENT)));

uint32_t *GPMC0_CONFIG1 = (uint32_t*)(CSL_GPMC0_CFG_BASE + CSL_GPMC_CONFIG1(0));
uint32_t *GPMC0_CONFIG2 = (uint32_t*)(CSL_GPMC0_CFG_BASE + CSL_GPMC_CONFIG2(0));
uint32_t *GPMC0_CONFIG3 = (uint32_t*)(CSL_GPMC0_CFG_BASE + CSL_GPMC_CONFIG3(0));
uint32_t *GPMC0_CONFIG4 = (uint32_t*)(CSL_GPMC0_CFG_BASE + CSL_GPMC_CONFIG4(0));
uint32_t *GPMC0_CONFIG5 = (uint32_t*)(CSL_GPMC0_CFG_BASE + CSL_GPMC_CONFIG5(0));
uint32_t *GPMC0_CONFIG6 = (uint32_t*)(CSL_GPMC0_CFG_BASE + CSL_GPMC_CONFIG6(0));
uint32_t *GPMC0_CONFIG7 = (uint32_t*)(CSL_GPMC0_CFG_BASE + CSL_GPMC_CONFIG7(0));

void App_udmaTrpdInit(Udma_ChHandle chHandle, uint8_t *trpdMem, const void *destBuf, const void *srcBuf, uint32_t length);
void gpmc_configure();
void transfer(uint64_t trpdMemPhy, Udma_ChHandle chHandle);

int main() {
    System_init();
    Drivers_open();

    // Configure gpmc with burst mode
    gpmc_configure();
    GPMC_Handle *handle = GPMC_getHandle(0);

    // Get source and destination buffers
    uint32_t length = UDMA_TEST_NUM_BYTES;
    uint8_t *destBuf = (uint8_t*)AddrTranslateP_getLocalAddr(CSL_GPMC0_DATA_BASE);
    uint8_t *srcBuf = &gUdmaTestSrcBuf[0U];

    // Has to be done after driver open
    Udma_ChHandle chHandle = gConfigUdma0BlkCopyChHandle[0];

    // Get trpd buffers
    uint8_t *trpdMem = &gUdmaTestTrpdMem[0U];
    uint64_t trpdMemPhy = (uint64_t) Udma_defaultVirtToPhyFxn(trpdMem, 0U, NULL);

    // Fill src with dummy memory
    memset(srcBuf, 0x55, UDMA_TEST_NUM_BYTES);

    // Enable channel
    DebugP_assert(Udma_chEnable(chHandle) == UDMA_SOK);

    // Init TR packet descriptor
    App_udmaTrpdInit(chHandle, trpdMem, destBuf, srcBuf, length);

    for (;;) {
        transfer(trpdMemPhy, chHandle);
        CacheP_inv(trpdMem, UDMA_TEST_TRPD_SIZE, CacheP_TYPE_ALLD);
        DebugP_assert(UdmaUtils_getTrpdTr15Response(trpdMem, 1U, 0U) == CSL_UDMAP_TR_RESPONSE_STATUS_COMPLETE);
    }
}

/**
 * Used example udma_memcpy_polling for this
 * modified icnt0, icnt1, dictn0, dictn1 according to:
 * e2e.ti.com/.../am2434-gpmc-burst-transfer-to-fpga-using-udma-tr-type-settings
 */
void App_udmaTrpdInit(Udma_ChHandle chHandle, uint8_t *trpdMem, const void *destBuf, const void *srcBuf, uint32_t length)
{
    CSL_UdmapTR15  *pTr;
    uint32_t        cqRingNum = Udma_chGetCqRingNum(chHandle);

    /* Make TRPD with TR15 TR type */
    UdmaUtils_makeTrpdTr15(trpdMem, 1U, cqRingNum);

    /* Setup TR */
    pTr = UdmaUtils_getTrpdTr15Pointer(trpdMem, 0U);
    pTr->flags    = CSL_FMK(UDMAP_TR_FLAGS_TYPE, CSL_UDMAP_TR_FLAGS_TYPE_4D_BLOCK_MOVE_REPACKING_INDIRECTION);
    pTr->flags   |= CSL_FMK(UDMAP_TR_FLAGS_STATIC, 0U);
    pTr->flags   |= CSL_FMK(UDMAP_TR_FLAGS_EOL, CSL_UDMAP_TR_FLAGS_EOL_MATCH_SOL_EOL);
    pTr->flags   |= CSL_FMK(UDMAP_TR_FLAGS_EVENT_SIZE, CSL_UDMAP_TR_FLAGS_EVENT_SIZE_COMPLETION);
    pTr->flags   |= CSL_FMK(UDMAP_TR_FLAGS_TRIGGER0, CSL_UDMAP_TR_FLAGS_TRIGGER_NONE);
    pTr->flags   |= CSL_FMK(UDMAP_TR_FLAGS_TRIGGER0_TYPE, CSL_UDMAP_TR_FLAGS_TRIGGER_TYPE_ALL);
    pTr->flags   |= CSL_FMK(UDMAP_TR_FLAGS_TRIGGER1, CSL_UDMAP_TR_FLAGS_TRIGGER_NONE);
    pTr->flags   |= CSL_FMK(UDMAP_TR_FLAGS_TRIGGER1_TYPE, CSL_UDMAP_TR_FLAGS_TRIGGER_TYPE_ALL);
    pTr->flags   |= CSL_FMK(UDMAP_TR_FLAGS_CMD_ID, 0x25U);  /* This will come back in TR response */
    pTr->flags   |= CSL_FMK(UDMAP_TR_FLAGS_SA_INDIRECT, 0U);
    pTr->flags   |= CSL_FMK(UDMAP_TR_FLAGS_DA_INDIRECT, 0U);
    pTr->flags   |= CSL_FMK(UDMAP_TR_FLAGS_EOP, 1U);
    pTr->icnt0    = 2U;
    pTr->icnt1    = length/2;
    pTr->icnt2    = 1U;
    pTr->icnt3    = 1U;
    pTr->dim1     = pTr->icnt0;
    pTr->dim2     = (pTr->icnt0 * pTr->icnt1);
    pTr->dim3     = (pTr->icnt0 * pTr->icnt1 * pTr->icnt2);
    pTr->addr     = (uint64_t) Udma_defaultVirtToPhyFxn(srcBuf, 0U, NULL);
    pTr->fmtflags = 0x00000000U;    /* Linear addressing, 1 byte per elem */
    pTr->dicnt0   = 2U;
    pTr->dicnt1   = length/2;
    pTr->dicnt2   = 1U;
    pTr->dicnt3   = 1U;
    pTr->ddim1    = pTr->dicnt0;
    pTr->ddim2    = (pTr->dicnt0 * pTr->dicnt1);
    pTr->ddim3    = (pTr->dicnt0 * pTr->dicnt1 * pTr->dicnt2);
    pTr->daddr    = (uint64_t) Udma_defaultVirtToPhyFxn(destBuf, 0U, NULL);

    /* Perform cache writeback */
    CacheP_wb(trpdMem, UDMA_TEST_TRPD_SIZE, CacheP_TYPE_ALLD);

    return;
}

/**
 * Configure GPMC with synchronous burst mode
 */
void gpmc_configure() {
    CSL_FINST(*GPMC0_CONFIG1, GPMC_CONFIG1_WRITEMULTIPLE, WRMULTIPLE);
    CSL_FINST(*GPMC0_CONFIG1, GPMC_CONFIG1_READMULTIPLE, RDMULTIPLE);
    CSL_FINST(*GPMC0_CONFIG1, GPMC_CONFIG1_READTYPE, RDSYNC);
    CSL_FINST(*GPMC0_CONFIG1, GPMC_CONFIG1_WRITETYPE, WRSYNC);

    GPMC_Handle *handle = GPMC_getHandle(0);

    // If I don't run these, accesses to 0x50000000 fault
    GPMC_setDeviceType(handle);
    GPMC_setDeviceSize(handle);

    // If I don't run these, the UDMA fails to transfer
    GPMC_configurePrefetchPostWriteEngine(handle);
    GPMC_configureTimingParameters(handle);
}

/**
 * Polling udma queue and dequeue
 */
void transfer(uint64_t trpdMemPhy, Udma_ChHandle chHandle) {
    uint64_t pDesc;
    int32_t retVal = UDMA_SOK;
    retVal = Udma_ringQueueRaw(Udma_chGetFqRingHandle(chHandle), trpdMemPhy);
    DebugP_assert(retVal == UDMA_SOK);
    while(1)
    {
        retVal = Udma_ringDequeueRaw(Udma_chGetCqRingHandle(chHandle), &pDesc);
        if(UDMA_SOK == retVal)
        {
            break;
        }
    }

}
  • Hello Keaton Clark,

    I am really wondering if you might configure GPMC communication to be asynchronous.

    Can you please confirm if you configure asynchronous or synchronous communication ?

    In asynchronous communication, the clock is not presented.

    Yes, the MCU+SDK driver does not support 32bit. If you want 32bit, then go with changing the 32bit mode and, accordingly, configure the pin mux settings.

    If you need different burst sizes, we can play with a burst size selection.

    The maximum burst size can be supported to 32words.

    So, you can configure the icnt0 to the maximum burst size.

    I need your full project to look at the your code, or I have created an FAQ to auto-trigger DMA based on the GPIO input.

    In this example, I have used the GPMC with the DMA. You can follow the same implementation for the GPMC with DMA .

    In your setup, how did you initiate the GPMC. Did you initiate with syscfg ?

    Please try with these settings and confirm the your Test results .

    https://e2e.ti.com/support/processors-group/processors/f/processors-forum/1378150/faq-how-to-trigger-dma-with-the-help-of-gpio-on-am64x-am243-and-am62x-devices

    Regards,

    Anil.

  • Yes, it is on synchronous transfers (see GPMC0_CONFIG1) and I was initializing it with sysconfig. The issue was I was testing with an 8bit bus, which does not support burst mode as per the note on pg. 8562 of the TRM. Switching to a 16bit bus allowed it to do bursts.

  • Hello Keaton Clark,

    Thanks for the update .

    The Prefetch and DMA enablement are not needed for PSRAM/NOR memory type interfaces and they required only for the NAND devices.

    The PSRAM/NOR memories are memories mapped to SOC.

    So, when you interface the GPMC with the DMA, you can directly configure the TRPD with the source and destination address of the GPMC memory and destination memory.

    I am just curious about what the burst size is configured and how the icnt0 is configured.

    I assume that if the burst size is 16 words, then we need to configure the icnt0 = 32 (bytes) and inct1=length/32

    Here is your setup. If you configure it to 16bit, then 1 word is = 2 bytes.

    Please confirm what your setup is ?

    Regards,

    Anil.