aboutsummaryrefslogtreecommitdiffstats
path: root/notes/dma.txt
blob: 97b23a0a1b1988c1b7e834ca41e07ef2bf96d838 (plain)
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
DMA Notes
=========

Medium-density devices have one DMA controller, DMA1.  High-density
devices and up also have DMA2.  DMA1 has 7 channels; DMA2 has 5.  Each
channel multiplexes DMA requests from various peripherals, like so:

Channel Capabilities
--------------------

DMA1:

    * Channel 1: ADC1, TIM2_CH3, TIM4_CH1
    * Channel 2: USART3_TX, TIM1_CH1, TIM2_UP,  TIM3_CH3, SPI1_RX
    * Channel 3: USART3_RX, TIM1_CH2, TIM3_CH4, TIM3_UP,  SPI1_TX
    * Channel 4: USART1_TX, TIM1_CH4, TIM1_TRIG, TIM1_COM, TIM4_CH2,
                 SPI2/I2S2_RX, I2C2_TX
    * Channel 5: USART1_RX, TIM1_UP, TIM2_CH1, TIM4_CH3,
                 SPI2/I2S2_TX, I2C2_RX
    * Channel 6: USART2_RX, TIM1_CH3, TIM3_CH1, TIM3_TRIG, I2C1_TX
    * Channel 7: USART2_TX, TIM2_CH2, TIM2_CH4, TIM4_UP, I2C1_RX

DMA2:

    * Channel 1: TIM5_CH4, TIM5_TRIG, TIM8_CH3, TIM8_UP, SPI/I2S3_RX
    * Channel 2: TIM8_CH4, TIM8_TRIG, TIM8_COM, TIM5_CH3, TIM5_UP, SPI/I2S3_TX
    * Channel 3: TIM8_CH1, UART4_RX, TIM6_UP/DAC_CH1
    * Channel 4: TIM5_CH2, SDIO, TIM7_UP/DAC_CH2
    * Channel 5: ADC3, TIM8_CH2, TIM5_CH1, UART4_TX

An example usage: via DMA1, channel 1, you can have ADC1 periodically
dump converted data into an array in memory.  The DMA controller can
then interrupt you when the array is half-full and full, and if any
error occurred.

Since channels are multiplexed in hardware, you can't simultaneously
use the same DMA channel to serve requests from two of its peripherals
at the same time.  For example, if you are using DMA 1 channel 1 to
serve DMA requests from ADC1, you can't also serve requests from Timer
2 channel 3.

Channel Priority
----------------

An arbiter prioritizes simultaneous channel DMA requests.  Channel
priority levels are configurable (4 levels of priority).  Ties within
a DMA controller are broken by choosing the lower channel number;
between the controllers, DMA1 has higher priority than DMA2.

Interrupts
----------

You can cause an interrupt to fire once half the transfers are
complete, when all the transfers are complete, if an error occurs
during transfer, or any combination of the three.

If an error occurs, the transfer is automatically disabled.

Configuration
-------------

In order to configure a DMA transfer for DMA controller n, channel x,
ST RM0008 says you should do the following:

    A. Set the peripheral register address in DMAn_BASE->CPARx.
    B. Set the memory address in DMAn_BASE->CMARx.
    C. Set the number of data to be transferred in DMAn_BASE->CNDTRx.
    D. Set the channel priority via the PL bits in DMAn_BASE->CCRx.
    E. Configure various other things (e.g. data transfer sizes, what
       events cause channel interrupts) in DMAn_BASE->CCRx as desired.
    F. Activate the channel by setting ENABLE bit in DMAn_BASE->CCRx.

The channel will start serving DMA requests as soon as it's activated.

The DMA library lets you accomplish these tasks as follows:

    **Setup transfer**

    Do (A), (B), and (E) using dma_setup_transfer().

    This also does (D), but chooses the lowest priority by default.

    **Perform any other desired configuration**

    You can do (C) using dma_set_num_transfers().

    You can do (D) using dma_set_priority().

    You can attach interrupt handlers with dma_attach_interrupt().

    **Activate the channel**

    Do (F) with dma_enable().

Once you're all done, you can dma_disable() the channel.  If you
dma_detach_interrupt() an interrupt handler, the channel interrupts
will stop firing, but the transfer itself won't stop until it's done
(which never happens if you set the DMA_CIRC_MODE flag when you called
dma_setup_transfer()).