DMA - Block Transfer Stalls

Tip / Sign in to post questions, reply, level up, and achieve exciting badges. Know more

cross mob
Not applicable
Hi all,

I am trying to configure the DMA module to read 3 ADC registers and transfer their contents into an array. It is similar to what is described in the following App. Note: http://www.infineon.com/dgdl/Infineon-GPDMA-XMC4000-AP32290-AN-v01_00-EN.pdf?fileId=5546d4624e765da5..., Multi block transfer of VADC result registers to RAM for
motor control.

In short, I configured the ADC to take 8 samples, which are distributed among 3 result registers (accumulation mode is ON). When the last conversion is completed and the result becomes available, an SR trigger is fired (e.g. G0SR1) to indicate the availability of all the results. This trigger is routed to GPDMA0, Channel 0, which is configured as follows:
     XMC_DMA_CH_CONFIG_t dma0_config_channel0 = {
.enable_interrupt = false,
.dst_transfer_width = XMC_DMA_CH_TRANSFER_WIDTH_16,
.src_transfer_width = XMC_DMA_CH_TRANSFER_WIDTH_16,
.dst_address_count_mode = XMC_DMA_CH_ADDRESS_COUNT_MODE_INCREMENT,
.src_address_count_mode = XMC_DMA_CH_ADDRESS_COUNT_MODE_INCREMENT,
.dst_burst_length = XMC_DMA_CH_BURST_LENGTH_1, /* TRANSACTION LENGTH - not applicable for memory transfers; memory transfers are limited by AHB transfer size */
.src_burst_length = XMC_DMA_CH_BURST_LENGTH_1,
.enable_dst_scatter = false, /* Target variables are 16 bit */
.enable_src_gather = true, /* To get 16-bit result from 32-bit register */
.src_gather_interval = 1U,
.src_gather_count = 1U,
.dst_scatter_interval = 0U,
.dst_scatter_count = 0U,
.block_size = 3U,
.transfer_flow = XMC_DMA_CH_TRANSFER_FLOW_P2M_DMA,
.src_addr = (uint32_t) &(VADC_G0->RES[1]),
.dst_addr = (uint32_t) &variables[0],
.transfer_type = XMC_DMA_CH_TRANSFER_TYPE_MULTI_BLOCK_SRCADR_RELOAD_DSTADR_RELOAD,
.priority = XMC_DMA_CH_PRIORITY_7,
.src_handshaking = XMC_DMA_CH_SRC_HANDSHAKING_HARDWARE,
.src_peripheral_request = DMA0_PERIPHERAL_REQUEST_VADC_G0SR1_4
};


In my understanding, what would happen is as follows:

(a) The DMA would look at VADC_G0->RES[1] (which it does properly, by the way, but I will elaborate on this a little later), take the value from that register and transfer it to variables[0]
(b) The source address would increment by 32 bits (because of gather settings), and would point at VADC_G0->RES[2]
(c) The destination address would increment by 16 bits and would point to variables[1] (Note: variables is an array of type uint16_t)
(d) This process would repeat, starting from (a), but for VADC_G0->RES[2]

However, the problem is that the DMA stalls once it has transferred the values out of RES[1] to variables[0]. In other words, when I look at the RES registers, I can see that the valid flag (VF) of RES[1] is cleared, meaning that the DMA has read that register. Also, a new value appears in variables[0]. But RES[2] and RES[3] both have their valid flags set to 1, i.e. VF = 1, meaning that the DMA has never read those registers.

One more observation that might help - if I remove wait_for_read_mode = 1 from result configuration registers, then DMA seems to work as it should, or at least transfer some values into variables[1] and variables[2]. Can it be that the first block transfer is different from the rest somehow?

Could someone please shed some light on this problem? Cheers!

Best regards,

Andrey
0 Likes
1 Reply
Not applicable
After trying a few more things with the DMA peripheral, I think I might have found the issue.

Could someone tell me, please, if the DMA completes the entire block transfer after it receives a trigger, or just a single transaction?

Cheers,

Andrey

UPD: My guess would be that indeed, a trigger only starts a single transaction (burst/single). As a result, if the Burst Length is set to 1, then only RES[1] would be read, and variables[0] would be written. However, even if I set each of the three registers (RES[1], RES[2] and RES[3]) to raise a trigger whenever the VF goes high, even then the block transfer does not complete as it should.

UPD2: For some reason, if I change the destination registers for various channels, the DMA behavior is different. For instance, if I route CH0 to RES[1] and CH2 to RES[2], then DMA works as described above - reads RES[1] and puts that into variables[0] and then stalls. However, if I switch those destinations around, i.e. CH0 to RES[2] and CH2 to RES[1], then the DMA stops working altogether. What could be the reason for that?
0 Likes