> For the complete documentation index, see [llms.txt](https://mujoseph.gitbook.io/mujoseph-docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://mujoseph.gitbook.io/mujoseph-docs/emma-mk1-drsstc/drsstc_driver-firmware-overview/dma-configuration.md).

# DMA Configuration

## DMA1

### Channel Configuration

The following table outlines the source, destination, and trigger for each of the DMA1 channels.

{% hint style="info" %}
DMA source/destination type: **Peripheral** or *Memory (i.e. app variable/constant)*
{% endhint %}

<table><thead><tr><th width="75" data-type="number">CH</th><th width="144">Source</th><th>Trigger</th><th width="125">Destination</th><th>Notes</th></tr></thead><tbody><tr><td>6</td><td><strong>USART1.RDR</strong></td><td>RXNE hardware event: USART1.RDR holds a received byte</td><td><em>Receive Buffer</em></td><td>USART1 Receive Data</td></tr><tr><td>7</td><td><em>Transmit buffer</em></td><td>Software trigger</td><td><strong>USART1.TDR</strong></td><td>USART1 Transmit Data</td></tr></tbody></table>

### DMA2 Channel 6 Role

Channel 6 is used by the `mujoe_usart` driver for receiving bytes from the host via the UART peripheral in a non-blocking configuration.

Channel 6 copies the received byte from the USART Receive Data register ( `RDR` ) into the `mujoe_usart` driver receive buffer. The USART RX transfer complete interrupt service routine (ISR) notifies the [`commTask`](/mujoseph-docs/emma-mk1-drsstc/drsstc_driver-firmware-overview.md#general-architecture) via an ISR-safe task message.

The `commTask` is notified only after the minimum number of bytes is received by the USART peripheral (set by `USART1_DMA_RX_LEN` in `mujoe_settings.h`).

### DMA2 Channel 7 Role

Channel 6 is used by the `mujoe_usart` driver for transmitting bytes to the host via the UART peripheral in a non-blocking configuration. Once the channel is armed by the `mujoe_usart` driver, it loads the transmit buffer into the USART Transmit Data register ( `TDR` ), and notifies the [`commTask`](/mujoseph-docs/emma-mk1-drsstc/drsstc_driver-firmware-overview.md#general-architecture) once all bytes have been transmitted (USART TX transfer complete ISR sends an ISR-safe task message).

## DMA2

### Channel Configuration

The following table outlines the source, destination, and trigger for each of the DMA2 channels.

{% hint style="info" %}
DMA source/destination type: **Peripheral** or *Memory (i.e. app variable/constant)*
{% endhint %}

<table><thead><tr><th width="75" data-type="number">CH</th><th width="144">Source</th><th>Trigger</th><th width="125">Destination</th><th>Notes</th></tr></thead><tbody><tr><td>1</td><td><strong>TIME.CPT1ER</strong></td><td>TIME Capture 1</td><td><strong>TIM2.ARR</strong></td><td>H-Bridge open-loop drive frequency seed and lead-time injection</td></tr><tr><td>2</td><td><em>output_reset</em> </td><td>TIMB Capture 2</td><td><strong>HRTIM.BDMADR</strong></td><td>Update TIMB/C output config via DMA Burst for pulse-skipping</td></tr><tr><td>3</td><td><em>output_set</em></td><td>TIMD Compare 1</td><td><strong>HRTIM.BDMADR</strong></td><td>Restore TIMB/C output config via DMA Burst for normal operation</td></tr><tr><td>4</td><td><strong>TIME.CPT1ER</strong></td><td>TIMC Capture 2</td><td><strong>TIMD.CMP1DR</strong></td><td>Update TIMD compare value with TIME capture</td></tr><tr><td>5</td><td><em>OENR_ENABLE_BRIDGE_DRV_OUT</em></td><td>TIM5 Update</td><td><strong>HRTIM.OENR</strong></td><td>Exits Delayed Protection "Delayed Idle" state</td></tr><tr><td>6</td><td><em>start_period</em></td><td>TIM5 Compare 2</td><td><strong>TIM2.ARR</strong></td><td>Resets start frequency when <em>Burst Reload</em> is enabled</td></tr><tr><td>7</td><td><strong>TIME.CPT1ER</strong></td><td>TIME Capture 1</td><td><em>Resonant Period Capture Buffer</em></td><td>Stores the captured resonant period into a buffer for later processing</td></tr></tbody></table>

### DMA2 Channel 1 Role

Channel 1 is used to update the [TIM2](/mujoseph-docs/emma-mk1-drsstc/drsstc_driver-firmware-overview/tim2-open-loop-switching-frequency-and-lead-time.md) period (by updating its `ARR` register) once the loop is closed (ZCD feedback received) by copying the [TIME Capture 1](/mujoseph-docs/emma-mk1-drsstc/drsstc_driver-firmware-overview/high-resolution-timer-hrtim/time-resonant-frequency-capture.md#time-capture-1-role) register (which contains the real-time resonant frequency of the system).&#x20;

[Recall](/mujoseph-docs/emma-mk1-drsstc/drsstc_driver-firmware-overview/tim2-open-loop-switching-frequency-and-lead-time.md#open-loop-switching-frequency-seed-and-lead-time-injection) that TIM2 is used as the initial starting frequency seed during the open-loop period at the start of each PRF burst cycle. DMA2 Channel 1 ensures that TIM2 frequency eventually matches that of the measured resonant frequency of the DRSSTC.

### DMA2 Channel 2 Role

Channel 2 is used for [pulse-skipping](/mujoseph-docs/emma-mk1-drsstc/drsstc_driver-firmware-overview/high-resolution-timer-hrtim/timd-pulse-skipping-timer/pulse-skipping-via-burst-dma-transfers.md#hrtim-burst-dma-sequence-within-the-drsstc_driver-context) during an active PRF cycle. It is triggered by [TIMB Capture 2](/mujoseph-docs/emma-mk1-drsstc/drsstc_driver-firmware-overview/high-resolution-timer-hrtim/timb-half-bridge-1-driver.md#timb-capture-2-role).

### DMA2 Channel 3 Role

Channel 3 is used for restoring normal H-bridge after an OCD ([EEV8](/mujoseph-docs/emma-mk1-drsstc/drsstc_driver-firmware-overview/high-resolution-timer-hrtim/external-event-eev-configuration.md#eev8-over-current-detection-ocd-signal)) event triggers [pulse-skipping](/mujoseph-docs/emma-mk1-drsstc/drsstc_driver-firmware-overview/high-resolution-timer-hrtim/timd-pulse-skipping-timer/pulse-skipping-via-burst-dma-transfers.md) operation. It writes the `output_set` constant array, which contains the original set sources configuration, to the `SETB1R`, `SETB2R`, `SETC1R` and `SETC2R` registers.

### DMA2 Channel 4 Role

Channel 4 is used to update the HRTIM [TIMD Compare 1](/mujoseph-docs/emma-mk1-drsstc/drsstc_driver-firmware-overview/high-resolution-timer-hrtim/timd-pulse-skipping-timer.md#timd-compare-1-role) register with the value from [TIME Capture 1](/mujoseph-docs/emma-mk1-drsstc/drsstc_driver-firmware-overview/high-resolution-timer-hrtim/time-resonant-frequency-capture.md#time-capture-1-role), which contains the real-time resonant period of the DRSSTC. It is triggered by [TIMC Capture 2](/mujoseph-docs/emma-mk1-drsstc/drsstc_driver-firmware-overview/high-resolution-timer-hrtim/timc-half-bridge-2-driver.md#timc-capture-2-role).

### DMA2 Channel 5 Role

Channel 5 is used to exit [Delayed Idle](/mujoseph-docs/emma-mk1-drsstc/drsstc_driver-firmware-overview/high-resolution-timer-hrtim/timb-half-bridge-1-driver.md#delayed-protection-within-the-drsstc_driver-context) state at the start of a PRF cycle. When a [resonant burst is started](/mujoseph-docs/emma-mk1-drsstc/drsstc_driver-firmware-overview/serial-interface.md#start-burst-command), [TIM5](/mujoseph-docs/emma-mk1-drsstc/drsstc_driver-firmware-overview/tim5-internal-prf-interrupter-source.md) is reset and generates an update event, which triggers Channel 5 to update the *HRTIM Output Enable* register ( `HRTIM_OENR` ) from the constant below:

{% code title="mujoe\_resdrv.c" overflow="wrap" lineNumbers="true" expandable="true" %}

```c
static const uint32_t OENR_ENABLE_BRIDGE_DRV_OUT = HRTIM_OENR_TB1OEN | HRTIM_OENR_TB2OEN | HRTIM_OENR_TC1OEN | HRTIM_OENR_TC2OEN;
```

{% endcode %}

Setting the respective bits restores the [TB1/TB2 and TC1/TC2](/mujoseph-docs/emma-mk1-drsstc/drsstc_driver-firmware-overview/high-resolution-timer-hrtim/timb-half-bridge-1-driver.md#timb-outputs-tb1-and-tb2-roles) inverter drive signals to their respective pins, allowing the H-bridge to be driven for the current PRF cycle.

{% hint style="warning" %}
In order for an external PRF signal to be used (i.e. output of the [fiber optic receiver](/mujoseph-docs/emma-mk1-drsstc/hardware-overview/electrical-design/pcb-design/motherboard.md#interrupter-signal-source-selection)), DMA2 Channel 5 trigger source must be changed to a [COMP4](/mujoseph-docs/emma-mk1-drsstc/drsstc_driver-firmware-overview.md#comp4-interrupter) output rising edge (or similar trigger), since TIM5 will not be running within this configuration and thus the associated update event will be unavailable to restore inverter drive signals at the start of a PRF cycle.
{% endhint %}

### DMA2 Channel 6 Role

When burst reload is enabled (via `mujoe_settings.h`), [TIM5 Compare 2](/mujoseph-docs/emma-mk1-drsstc/drsstc_driver-firmware-overview/tim5-internal-prf-interrupter-source.md#starting-open-loop-frequency-reload) event triggers DMA2 Channel 6 to reload [TIM2](/mujoseph-docs/emma-mk1-drsstc/drsstc_driver-firmware-overview/tim2-open-loop-switching-frequency-and-lead-time.md) Auto Reload register (`ARR`) with the [requested start/open-loop frequency](/mujoseph-docs/emma-mk1-drsstc/drsstc_driver-firmware-overview/serial-interface.md). TIM5 Compare 2 events occur slightly before the end of the current PRF cycle (e.g., slightly before the next PRF cycle). This lead time is set by `BURST_DMARQ_LEADTIME_US` in `mujoe_settings.h` (default set to 100 $$\mu s$$).

### DMA2 Channel 7 Role

Channel 7 is responsible for storing the captured resonant period of the DRSSTC for each resonant cycle into a dynamically allocated buffer. When the *Emma Mk1* is idle, the [resonant period capture buffer can be dumped via UART](/mujoseph-docs/emma-mk1-drsstc/drsstc_driver-firmware-overview/serial-interface.md#dump-resonant-period-capture-buffer-command) for further processing by the host.

Channel 7 is triggered by the [TIME Capture 1](/mujoseph-docs/emma-mk1-drsstc/drsstc_driver-firmware-overview/high-resolution-timer-hrtim/time-resonant-frequency-capture.md#time-capture-1-role) event; it intentionally has a lower priority than [DMA2 Channel 1](#dma2-channel-1-role) to not interfere with the critical task of updating [TIM2](/mujoseph-docs/emma-mk1-drsstc/drsstc_driver-firmware-overview/tim2-open-loop-switching-frequency-and-lead-time.md), which is responsible for driving the HRTIM during the [open-loop portion of the PRF cycle](/mujoseph-docs/emma-mk1-drsstc/drsstc_driver-firmware-overview/tim2-open-loop-switching-frequency-and-lead-time.md#open-loop-switching-frequency-seed-and-lead-time-injection).

## :warning:Major DMA Burst Configuration Discrepancy

The reference project uses the configuration built using the `HRTIM_DMA_BURST_REFERENCE_CONFIG` predefined symbol. This configuration follows the suggested settings outlined in the `STM32G474RE` reference manual:

> *From section 28.3.23 DMA:*
>
> The burst DMA mode is permanently enabled (there is no enable bit). A burst DMA> &#x20;operation is started by the first write access into the HRTIM\_BDMADR register. <br>
>
> It is only necessary to have the DMA controller pointing to the HRTIM\_BDMADR register as> &#x20;the destination, in the memory, to the peripheral configuration with the peripheral increment> &#x20;mode disabled (the HRTIM handles internally the data re-routing to the final destination> \
> register).
>
> \
> To re-initialize the burst DMA mode if it was interrupted during a transaction, it is necessary> \
> to write at least to one of the 6 update registers.

However, what has been used thus far (undefine `HRTIM_DMA_BURST_REFERENCE_CONFIG`) has been based on this [ST forum post](https://community.st.com/t5/stm32-mcus-products/hrtim-burst-controller-help/m-p/784837#M275531), which seems to work as intended. See the code snippet below:

{% code title="mujoe\_hrtim\_dma\_burst\_config() within mujoe\_htrim.c" lineNumbers="true" %}

```c
#ifdef HRTIM_DMA_BURST_REFERENCE_CONFIG

		// This is how it is configured in reference project
		uint32_t transferDir = LL_DMA_DIRECTION_MEMORY_TO_PERIPH;
		uint32_t periphSize = LL_DMA_PDATAALIGN_WORD;
		uint32_t memSize = LL_DMA_MDATAALIGN_WORD;
		uint32_t periphInc = LL_DMA_PERIPH_NOINCREMENT;
		uint32_t memInc = LL_DMA_MEMORY_INCREMENT;

#else	// This has been working so far
		// NOTE: Refer to this thread for DMA config in context of HRTIM Burst DMA:
		// https://community.st.com/t5/stm32-mcus-products/hrtim-burst-controller-help/m-p/784837#M275531
		uint32_t transferDir = LL_DMA_DIRECTION_PERIPH_TO_MEMORY;
		uint32_t periphSize = LL_DMA_PDATAALIGN_WORD;
		uint32_t memSize = LL_DMA_MDATAALIGN_WORD;
		uint32_t periphInc = LL_DMA_PERIPH_INCREMENT;
		uint32_t memInc = LL_DMA_MEMORY_NOINCREMENT;
#endif // #ifdef HRTIM_DMA_BURST_REFERENCE_CONFIG
```

{% endcode %}
