2 * This file is part of Betaflight.
4 * Betaflight is free software. You can redistribute this software
5 * and/or modify this software under the terms of the GNU General
6 * Public License as published by the Free Software Foundation,
7 * either version 3 of the License, or (at your option) any later
10 * Betaflight is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14 * See the GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public
17 * License along with this software.
19 * If not, see <http://www.gnu.org/licenses/>.
28 #include "timer_def.h"
29 #include "drivers/adc.h"
30 #include "drivers/bus_spi.h"
31 #include "drivers/dma_reqmap.h"
32 #include "drivers/serial.h"
33 #include "drivers/serial_uart.h"
35 #include "pg/timerio.h"
37 typedef struct dmaPeripheralMapping_s
{
38 dmaPeripheral_e device
;
41 } dmaPeripheralMapping_t
;
43 typedef struct dmaTimerMapping_s
{
49 #define REQMAP_SGL(periph) { DMA_PERIPH_ ## periph, 0, DMA_REQUEST_ ## periph }
50 #define REQMAP(periph, device) { DMA_PERIPH_ ## periph, periph ## DEV_ ## device, DMA_REQUEST_ ## periph ## device }
51 #define REQMAP_DIR(periph, device, dir) { DMA_PERIPH_ ## periph ## _ ## dir, periph ## DEV_ ## device, DMA_REQUEST_ ## periph ## device ## _ ## dir }
52 #define REQMAP_TIMUP(periph, timno) { DMA_PERIPH_TIMUP, timno - 1, DMAMUX_DMAREQ_ID_ ## TMR ## timno ## _OVERFLOW }
54 #define DMA_REQUEST_UART1_RX DMAMUX_DMAREQ_ID_USART1_RX
55 #define DMA_REQUEST_UART1_TX DMAMUX_DMAREQ_ID_USART1_TX
56 #define DMA_REQUEST_UART2_RX DMAMUX_DMAREQ_ID_USART2_RX
57 #define DMA_REQUEST_UART2_TX DMAMUX_DMAREQ_ID_USART2_TX
58 #define DMA_REQUEST_UART3_RX DMAMUX_DMAREQ_ID_USART3_RX
59 #define DMA_REQUEST_UART3_TX DMAMUX_DMAREQ_ID_USART3_TX
60 #define DMA_REQUEST_UART4_RX DMAMUX_DMAREQ_ID_UART4_RX
61 #define DMA_REQUEST_UART4_TX DMAMUX_DMAREQ_ID_UART4_TX
62 #define DMA_REQUEST_UART5_RX DMAMUX_DMAREQ_ID_UART5_RX
63 #define DMA_REQUEST_UART5_TX DMAMUX_DMAREQ_ID_UART5_TX
65 #define DMA_REQUEST_UART6_RX DMAMUX_DMAREQ_ID_USART6_RX
66 #define DMA_REQUEST_UART6_TX DMAMUX_DMAREQ_ID_USART6_TX
68 // Resolve our preference for SDO/SDI rather than TX/RX
69 #define DMA_REQUEST_SPI1_SDO DMAMUX_DMAREQ_ID_SPI1_TX
70 #define DMA_REQUEST_SPI1_SDI DMAMUX_DMAREQ_ID_SPI1_RX
71 #define DMA_REQUEST_SPI2_SDO DMAMUX_DMAREQ_ID_SPI2_TX
72 #define DMA_REQUEST_SPI2_SDI DMAMUX_DMAREQ_ID_SPI2_RX
73 #define DMA_REQUEST_SPI3_SDO DMAMUX_DMAREQ_ID_SPI3_TX
74 #define DMA_REQUEST_SPI3_SDI DMAMUX_DMAREQ_ID_SPI3_RX
75 #define DMA_REQUEST_SPI4_SDO DMAMUX_DMAREQ_ID_SPI4_TX
76 #define DMA_REQUEST_SPI4_SDI DMAMUX_DMAREQ_ID_SPI4_RX
78 #define DMA_REQUEST_ADC1 DMAMUX_DMAREQ_ID_ADC1
79 #define DMA_REQUEST_ADC2 DMAMUX_DMAREQ_ID_ADC2
80 #define DMA_REQUEST_ADC3 DMAMUX_DMAREQ_ID_ADC3
82 static const dmaPeripheralMapping_t dmaPeripheralMapping
[] = {
84 REQMAP_DIR(SPI
, 1, SDO
),
85 REQMAP_DIR(SPI
, 1, SDI
),
86 REQMAP_DIR(SPI
, 2, SDO
),
87 REQMAP_DIR(SPI
, 2, SDI
),
88 REQMAP_DIR(SPI
, 3, SDO
),
89 REQMAP_DIR(SPI
, 3, SDI
),
90 REQMAP_DIR(SPI
, 4, SDO
),
91 REQMAP_DIR(SPI
, 4, SDI
),
101 REQMAP_DIR(UART
, 1, TX
),
102 REQMAP_DIR(UART
, 1, RX
),
103 REQMAP_DIR(UART
, 2, TX
),
104 REQMAP_DIR(UART
, 2, RX
),
105 REQMAP_DIR(UART
, 3, TX
),
106 REQMAP_DIR(UART
, 3, RX
),
107 REQMAP_DIR(UART
, 4, TX
),
108 REQMAP_DIR(UART
, 4, RX
),
109 REQMAP_DIR(UART
, 5, TX
),
110 REQMAP_DIR(UART
, 5, RX
),
111 REQMAP_DIR(UART
, 6, TX
),
112 REQMAP_DIR(UART
, 6, RX
),
116 REQMAP_TIMUP(TIMUP
, 1),
117 REQMAP_TIMUP(TIMUP
, 2),
118 REQMAP_TIMUP(TIMUP
, 3),
119 REQMAP_TIMUP(TIMUP
, 4),
120 REQMAP_TIMUP(TIMUP
, 5),
121 REQMAP_TIMUP(TIMUP
, 6),
122 REQMAP_TIMUP(TIMUP
, 7),
123 REQMAP_TIMUP(TIMUP
, 8),
124 REQMAP_TIMUP(TIMUP
, 20),
133 #define TC(chan) DEF_TIM_CHANNEL(CH_ ## chan)
135 #define REQMAP_TIM(tim, chan) { tim, TC(chan), DMAMUX_DMAREQ_ID_ ## tim ## _ ## chan }
137 static const dmaTimerMapping_t dmaTimerMapping
[] = {
138 REQMAP_TIM(TMR1
, CH1
),
139 REQMAP_TIM(TMR1
, CH2
),
140 REQMAP_TIM(TMR1
, CH3
),
141 REQMAP_TIM(TMR1
, CH4
),
142 REQMAP_TIM(TMR2
, CH1
),
143 REQMAP_TIM(TMR2
, CH2
),
144 REQMAP_TIM(TMR2
, CH3
),
145 REQMAP_TIM(TMR2
, CH4
),
146 REQMAP_TIM(TMR3
, CH1
),
147 REQMAP_TIM(TMR3
, CH2
),
148 REQMAP_TIM(TMR3
, CH3
),
149 REQMAP_TIM(TMR3
, CH4
),
150 REQMAP_TIM(TMR4
, CH1
),
151 REQMAP_TIM(TMR4
, CH2
),
152 REQMAP_TIM(TMR4
, CH3
),
153 REQMAP_TIM(TMR4
, CH4
),
154 REQMAP_TIM(TMR5
, CH1
),
155 REQMAP_TIM(TMR5
, CH2
),
156 REQMAP_TIM(TMR5
, CH3
),
157 REQMAP_TIM(TMR5
, CH4
),
158 REQMAP_TIM(TMR8
, CH1
),
159 REQMAP_TIM(TMR8
, CH2
),
160 REQMAP_TIM(TMR8
, CH3
),
161 REQMAP_TIM(TMR8
, CH4
),
162 REQMAP_TIM(TMR20
, CH1
),
163 REQMAP_TIM(TMR20
, CH2
),
164 REQMAP_TIM(TMR20
, CH3
),
165 REQMAP_TIM(TMR20
, CH4
),
166 // XXX Check non-CH1 for TIM15,16,17 and 20
172 #define DMA(d, c) { DMA_CODE(d, c, 0), (dmaResource_t *) DMA ## d ## _CHANNEL ## c , 0 }
174 static dmaChannelSpec_t dmaChannelSpec
[MAX_PERIPHERAL_DMA_OPTIONS
] = {
193 static void dmaSetupRequest(dmaChannelSpec_t
*dmaSpec
, uint8_t request
)
195 dmaSpec
->dmaMuxId
= request
;
196 dmaCode_t code
= dmaSpec
->code
;
197 dmaSpec
->code
= DMA_CODE(DMA_CODE_CONTROLLER(code
), DMA_CODE_STREAM(code
), dmaSpec
->dmaMuxId
);
200 const dmaChannelSpec_t
*dmaGetChannelSpecByPeripheral(dmaPeripheral_e device
, uint8_t index
, int8_t opt
)
202 if (opt
< 0 || opt
>= MAX_PERIPHERAL_DMA_OPTIONS
) {
206 for (unsigned i
= 0 ; i
< ARRAYLEN(dmaPeripheralMapping
) ; i
++) {
207 const dmaPeripheralMapping_t
*periph
= &dmaPeripheralMapping
[i
];
208 if (periph
->device
== device
&& periph
->index
== index
) {
209 dmaChannelSpec_t
*dmaSpec
= &dmaChannelSpec
[opt
];
210 dmaSetupRequest(dmaSpec
, periph
->dmaRequest
);
218 dmaoptValue_t
dmaoptByTag(ioTag_t ioTag
)
220 #ifdef USE_TIMER_MGMT
221 for (unsigned i
= 0; i
< MAX_TIMER_PINMAP_COUNT
; i
++) {
222 if (timerIOConfig(i
)->ioTag
== ioTag
) {
223 return timerIOConfig(i
)->dmaopt
;
230 return DMA_OPT_UNUSED
;
233 const dmaChannelSpec_t
*dmaGetChannelSpecByTimerValue(TIM_TypeDef
*tim
, uint8_t channel
, dmaoptValue_t dmaopt
)
235 if (dmaopt
< 0 || dmaopt
>= MAX_PERIPHERAL_DMA_OPTIONS
) {
239 for (unsigned i
= 0 ; i
< ARRAYLEN(dmaTimerMapping
) ; i
++) {
240 const dmaTimerMapping_t
*timerMapping
= &dmaTimerMapping
[i
];
241 if (timerMapping
->tim
== tim
&& timerMapping
->channel
== channel
) {
242 dmaChannelSpec_t
*dmaSpec
= &dmaChannelSpec
[dmaopt
];
243 dmaSetupRequest(dmaSpec
, timerMapping
->dmaRequest
);
251 const dmaChannelSpec_t
*dmaGetChannelSpecByTimer(const timerHardware_t
*timer
)
257 dmaoptValue_t dmaopt
= dmaoptByTag(timer
->tag
);
258 return dmaGetChannelSpecByTimerValue(timer
->tim
, timer
->channel
, dmaopt
);
261 // dmaGetOptionByTimer is called by pgResetFn_timerIOConfig to find out dmaopt for pre-configured timer.
263 dmaoptValue_t
dmaGetOptionByTimer(const timerHardware_t
*timer
)
265 for (unsigned opt
= 0; opt
< ARRAYLEN(dmaChannelSpec
); opt
++) {
266 if (timer
->dmaRefConfigured
== dmaChannelSpec
[opt
].ref
) {
267 return (dmaoptValue_t
)opt
;
271 return DMA_OPT_UNUSED
;
274 // A variant of dmaGetOptionByTimer that looks for matching dmaTimUPRef
275 dmaoptValue_t
dmaGetUpOptionByTimer(const timerHardware_t
*timer
)
277 for (unsigned opt
= 0; opt
< ARRAYLEN(dmaChannelSpec
); opt
++) {
278 if (timer
->dmaTimUPRef
== dmaChannelSpec
[opt
].ref
) {
279 return (dmaoptValue_t
)opt
;
283 return DMA_OPT_UNUSED
;
286 #endif // USE_DMA_SPEC