Skip to content

Commit 9c4cd30

Browse files
talih0kartben
authored andcommitted
drivers: dma_xmc4xxx: Use DAR instead of CTL.BLOCK_TS to set pending_length
When quering the DMA status we need to return the number of pending bytes left in the transfer. Currently this is inferred by calling XMC_DMA_CH_GetTransferredData(). However, this function actually returns the number of items read from the source peripheral (via CTL.BLOCK_TS). It doesn't guarantee that the last item was fully transferred to the destination. When using the ADDR_ADJ_INCREMENT/DECREMENT options it is better to use DAR register to infer the number of transferred bytes. This points to the memory address where the next data will be written. It only increments after the ongoing transfer from source to destination is completed. Signed-off-by: Andriy Gelman <[email protected]>
1 parent 00ab7a9 commit 9c4cd30

File tree

1 file changed

+23
-3
lines changed

1 file changed

+23
-3
lines changed

drivers/dma/dma_xmc4xxx.c

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,12 @@ LOG_MODULE_REGISTER(dma_xmc4xxx, CONFIG_DMA_LOG_LEVEL);
3232
struct dma_xmc4xxx_channel {
3333
dma_callback_t cb;
3434
void *user_data;
35+
uint32_t dest_address;
3536
uint16_t block_ts;
3637
uint8_t source_data_size;
3738
uint8_t dlr_line;
39+
uint8_t channel_direction;
40+
uint8_t dest_addr_adj;
3841
};
3942

4043
struct dma_xmc4xxx_config {
@@ -62,7 +65,7 @@ do {
6265
if (dma_channel->cb) { \
6366
dma_channel->cb(dev, dma_channel->user_data, channel, (ret)); \
6467
} \
65-
} \
68+
} \
6669
} while (0)
6770

6871
/* Isr is level triggered, so we don't have to loop over all the channels */
@@ -287,6 +290,9 @@ static int dma_xmc4xxx_config(const struct device *dev, uint32_t channel, struct
287290
dev_data->channels[channel].block_ts = block->block_size / config->source_data_size;
288291
dev_data->channels[channel].source_data_size = config->source_data_size;
289292
dev_data->channels[channel].dlr_line = dlr_line;
293+
dev_data->channels[channel].channel_direction = config->channel_direction;
294+
dev_data->channels[channel].dest_addr_adj = block->dest_addr_adj;
295+
dev_data->channels[channel].dest_address = block->dest_address;
290296

291297
XMC_DMA_CH_DisableEvent(dma, channel, ALL_EVENTS);
292298
XMC_DMA_CH_EnableEvent(dma, channel, XMC_DMA_CH_EVENT_TRANSFER_COMPLETE);
@@ -368,6 +374,7 @@ static int dma_xmc4xxx_reload(const struct device *dev, uint32_t channel, uint32
368374
return -EINVAL;
369375
}
370376
dma_channel->block_ts = block_ts;
377+
dma_channel->dest_address = dst;
371378

372379
/* do we need to clear any errors */
373380
dma->CH[channel].SAR = src;
@@ -384,6 +391,7 @@ static int dma_xmc4xxx_get_status(const struct device *dev, uint32_t channel,
384391
const struct dma_xmc4xxx_config *dev_cfg = dev->config;
385392
XMC_DMA_t *dma = dev_cfg->dma;
386393
struct dma_xmc4xxx_channel *dma_channel;
394+
uint32_t transferred_bytes;
387395

388396
if (channel >= dev_data->ctx.dma_channels) {
389397
LOG_ERR("Invalid channel number");
@@ -393,8 +401,20 @@ static int dma_xmc4xxx_get_status(const struct device *dev, uint32_t channel,
393401

394402
stat->busy = XMC_DMA_CH_IsEnabled(dma, channel);
395403

396-
stat->pending_length = dma_channel->block_ts - XMC_DMA_CH_GetTransferredData(dma, channel);
397-
stat->pending_length *= dma_channel->source_data_size;
404+
/* Use DAR to check for transferred bytes when possible. Value CTL.BLOCK_TS does not */
405+
/* appear to guarantee that the last value is fully transferred to dest. */
406+
if (dma_channel->dest_addr_adj == DMA_ADDR_ADJ_INCREMENT) {
407+
transferred_bytes = dma->CH[channel].DAR - dma_channel->dest_address;
408+
stat->pending_length = dma_channel->block_ts - transferred_bytes;
409+
} else if (dma_channel->dest_addr_adj == DMA_ADDR_ADJ_DECREMENT) {
410+
transferred_bytes = dma_channel->dest_address - dma->CH[channel].DAR;
411+
stat->pending_length = dma_channel->block_ts - transferred_bytes;
412+
} else {
413+
transferred_bytes = XMC_DMA_CH_GetTransferredData(dma, channel);
414+
stat->pending_length = dma_channel->block_ts - transferred_bytes;
415+
stat->pending_length *= dma_channel->source_data_size;
416+
}
417+
398418
/* stat->dir and other remaining fields are not set. They are not */
399419
/* useful for xmc4xxx peripheral drivers. */
400420

0 commit comments

Comments
 (0)