Add DMA APIs for count modes #2059

Closed
opened 2024-11-19 15:29:19 -06:00 by kilograham · 5 comments
kilograham commented 2024-11-19 15:29:19 -06:00 (Migrated from github.com)

There is no ability to configure the Count Modes field of the DMA`s CHx_TRANS_COUNT register for RP2350 - its processing is missing in the SDK API version 2.0.0.

From RP2350 datasheet:
image
image

File "~\.pico-sdk\sdk\2.0.0\src\rp2_common\hardware_dma\include\hardware\dma.h"
Actual code:

static inline void dma_channel_set_trans_count(uint channel, uint32_t trans_count, bool trigger) {
    if (!trigger) {
        dma_channel_hw_addr(channel)->transfer_count = trans_count;
    } else {
        dma_channel_hw_addr(channel)->al1_transfer_count_trig = trans_count;
    }
}

Expected code example:

static inline void dma_channel_set_trans_count(uint channel, uint32_t mode, uint32_t trans_count, bool trigger) {
    assert(mode == DMA_CH0_TRANS_COUNT_MODE_VALUE_NORMAL || mode == DMA_CH0_TRANS_COUNT_MODE_VALUE_TRIGGER_SELF || mode == DMA_CH0_TRANS_COUNT_MODE_VALUE_ENDLESS);
    assert(trans_count < (1 << DMA_CH0_TRANS_COUNT_MODE_LSB));
    if (!trigger) {
        dma_channel_hw_addr(channel)->transfer_count = trans_count;
    } else {
        dma_channel_hw_addr(channel)->al1_transfer_count_trig = trans_count;
    }
    dma_channel_hw_addr(channel)->transfer_count |= mode << DMA_CH0_TRANS_COUNT_MODE_LSB;
}
There is no ability to configure the Count Modes field of the DMA`s CHx_TRANS_COUNT register for RP2350 - its processing is missing in the SDK API version 2.0.0. From RP2350 datasheet: ![image](https://github.com/user-attachments/assets/12b1c7e6-088b-4984-bb79-58e11f72f1da) ![image](https://github.com/user-attachments/assets/fdf64a21-78f6-4bc6-84ca-87122b9f76b9) File "~\\.pico-sdk\sdk\2.0.0\src\rp2_common\hardware_dma\include\hardware\dma.h" Actual code: ``` static inline void dma_channel_set_trans_count(uint channel, uint32_t trans_count, bool trigger) { if (!trigger) { dma_channel_hw_addr(channel)->transfer_count = trans_count; } else { dma_channel_hw_addr(channel)->al1_transfer_count_trig = trans_count; } } ``` Expected code example: ``` static inline void dma_channel_set_trans_count(uint channel, uint32_t mode, uint32_t trans_count, bool trigger) { assert(mode == DMA_CH0_TRANS_COUNT_MODE_VALUE_NORMAL || mode == DMA_CH0_TRANS_COUNT_MODE_VALUE_TRIGGER_SELF || mode == DMA_CH0_TRANS_COUNT_MODE_VALUE_ENDLESS); assert(trans_count < (1 << DMA_CH0_TRANS_COUNT_MODE_LSB)); if (!trigger) { dma_channel_hw_addr(channel)->transfer_count = trans_count; } else { dma_channel_hw_addr(channel)->al1_transfer_count_trig = trans_count; } dma_channel_hw_addr(channel)->transfer_count |= mode << DMA_CH0_TRANS_COUNT_MODE_LSB; } ```
TheLostLambda commented 2024-12-28 00:19:50 -06:00 (Migrated from github.com)

Also running into this issue — is this working on the development branch yet?

Or alternatively, is this something that still needs help?

Also running into this issue — is this working on the development branch yet? Or alternatively, is this something that still needs help?
TheLostLambda commented 2024-12-28 01:05:50 -06:00 (Migrated from github.com)

For what it's worth, this didn't work for me outside of the SDK:

 dma_channel_hw_addr(channel)->transfer_count |= mode << DMA_CH0_TRANS_COUNT_MODE_LSB;

I found that reading dma_channel_hw_addr(channel)->transfer_count (or dma_hw->ch[dma_chan].transfer_count in my code) always returned zero until after the channel was started / triggered, at which point updating the transfer count had no effect. I needed to set it before dma_channel_start(), but I couldn't read it until after dma_channel_start().

To avoid this issue, I ended up with something that just directly wrote the final value to transfer_count:

dma_channel_hw_addr(channel)->transfer_count = trans_count | mode << DMA_CH0_TRANS_COUNT_MODE_LSB;
For what it's worth, this didn't work for me outside of the SDK: ```c dma_channel_hw_addr(channel)->transfer_count |= mode << DMA_CH0_TRANS_COUNT_MODE_LSB; ``` I found that reading `dma_channel_hw_addr(channel)->transfer_count` (or `dma_hw->ch[dma_chan].transfer_count` in my code) always returned zero until *after* the channel was started / triggered, at which point updating the transfer count had no effect. I needed to set it before `dma_channel_start()`, but I couldn't read it until after `dma_channel_start()`. To avoid this issue, I ended up with something that just directly wrote the final value to `transfer_count`: ```c dma_channel_hw_addr(channel)->transfer_count = trans_count | mode << DMA_CH0_TRANS_COUNT_MODE_LSB; ```
TheLostLambda commented 2024-12-28 01:38:02 -06:00 (Migrated from github.com)

Happy to write a PR for this, but it would be good to know if people think we should update dma_channel_configure too, since that is another common route for setting transfer_count?

Happy to write a PR for this, but it would be good to know if people think we should update `dma_channel_configure` too, since that is another common route for setting `transfer_count`?
kilograham commented 2025-07-22 17:13:45 -05:00 (Migrated from github.com)

For what it's worth, this didn't work for me outside of the SDK:

dma_channel_hw_addr(channel)->transfer_count |= mode << DMA_CH0_TRANS_COUNT_MODE_LSB;

I found that reading dma_channel_hw_addr(channel)->transfer_count (or dma_hw->ch[dma_chan].transfer_count in my code) always returned zero until after the channel was started / triggered, at which point updating the transfer count had no effect. I needed to set it before dma_channel_start(), but I couldn't read it until after dma_channel_start().

To avoid this issue, I ended up with something that just directly wrote the final value to transfer_count:

dma_channel_hw_addr(channel)->transfer_count = trans_count | mode << DMA_CH0_TRANS_COUNT_MODE_LSB;

Do the existing APIs work correctly if you pre-encode the trans_count?

I'm thinking i may just document the trans_count as being pre-encoded, and add helpers to produce a

  • unlimited (RP2350)
  • self-triggering (RP2350)
  • normal
    argument
> For what it's worth, this didn't work for me outside of the SDK: > > dma_channel_hw_addr(channel)->transfer_count |= mode << DMA_CH0_TRANS_COUNT_MODE_LSB; > > I found that reading `dma_channel_hw_addr(channel)->transfer_count` (or `dma_hw->ch[dma_chan].transfer_count` in my code) always returned zero until _after_ the channel was started / triggered, at which point updating the transfer count had no effect. I needed to set it before `dma_channel_start()`, but I couldn't read it until after `dma_channel_start()`. > > To avoid this issue, I ended up with something that just directly wrote the final value to `transfer_count`: > > dma_channel_hw_addr(channel)->transfer_count = trans_count | mode << DMA_CH0_TRANS_COUNT_MODE_LSB; Do the existing APIs work correctly if you pre-encode the trans_count? I'm thinking i may just document the trans_count as being pre-encoded, and add helpers to produce a * unlimited (RP2350) * self-triggering (RP2350) * normal argument
kilograham commented 2025-07-25 09:26:09 -05:00 (Migrated from github.com)

merged into develop

merged into develop
Sign in to join this conversation.
No milestone
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
gh-raspberrypi/pico-sdk#2059
No description provided.