GPS Home altitude is added to blackbox logging (#13939)
[betaflight.git] / src / main / drivers / dma.h
blob330126b3bbaaa8c38a9b112aff5c59f487b18497
1 /*
2 * This file is part of Cleanflight and Betaflight.
4 * Cleanflight and Betaflight are free software. You can redistribute
5 * this software and/or modify this software under the terms of the
6 * GNU General Public License as published by the Free Software
7 * Foundation, either version 3 of the License, or (at your option)
8 * any later version.
10 * Cleanflight and Betaflight are distributed in the hope that they
11 * will be useful, but WITHOUT ANY WARRANTY; without even the implied
12 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 * See the GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this software.
18 * If not, see <http://www.gnu.org/licenses/>.
21 #pragma once
23 #include "drivers/resource.h"
25 #if defined(USE_ATBSP_DRIVER)
26 #include "drivers/mcu/at32/dma_atbsp.h"
27 #endif
29 #if defined(APM32F4)
30 #include "drivers/mcu/apm32/dma_apm32.h"
31 #endif
33 #define CACHE_LINE_SIZE 32
34 #define CACHE_LINE_MASK (CACHE_LINE_SIZE - 1)
36 // dmaResource_t is a opaque data type which represents a single DMA engine,
37 // called and implemented differently in different families of STM32s.
38 // The opaque data type provides uniform handling of the engine in source code.
39 // The engines are referenced by dmaResource_t through out the Betaflight code,
40 // and then converted back to DMA_ARCH_TYPE which is a native type for
41 // the particular MCU type when calling library functions.
43 typedef struct dmaResource_s dmaResource_t;
45 #if defined(STM32F4) || defined(STM32F7)
46 #define DMA_ARCH_TYPE DMA_Stream_TypeDef
47 #elif defined(STM32H7)
48 // H7 has stream based DMA and channel based BDMA, but we ignore BDMA (for now).
49 #define DMA_ARCH_TYPE DMA_Stream_TypeDef
50 #elif defined(AT32F435)
51 #define DMA_ARCH_TYPE dma_channel_type
52 #elif defined(APM32F4)
53 #define DMA_ARCH_TYPE DMA_Stream_TypeDef
54 #else
55 #define DMA_ARCH_TYPE DMA_Channel_TypeDef
56 #endif
58 struct dmaChannelDescriptor_s;
59 typedef void (*dmaCallbackHandlerFuncPtr)(struct dmaChannelDescriptor_s *channelDescriptor);
61 typedef struct dmaChannelDescriptor_s {
62 DMA_TypeDef* dma;
63 dmaResource_t *ref;
64 #if defined(STM32F4) || defined(STM32F7) || defined(STM32G4) || defined(STM32H7) || defined(APM32F4)
65 uint8_t stream;
66 #endif
67 uint32_t channel;
68 dmaCallbackHandlerFuncPtr irqHandlerCallback;
69 uint8_t flagsShift;
70 IRQn_Type irqN;
71 uint32_t userParam;
72 resourceOwner_t owner;
73 uint8_t resourceIndex;
74 uint32_t completeFlag;
75 #if defined(USE_ATBSP_DRIVER)
76 dmamux_channel_type *dmamux;
77 #endif
78 } dmaChannelDescriptor_t;
80 #define DMA_IDENTIFIER_TO_INDEX(x) ((x) - 1)
82 #if defined(USE_ATBSP_DRIVER)
84 #elif defined(APM32F4)
85 // dma_apm32.h
87 #elif defined(STM32F4) || defined(STM32F7) || defined(STM32H7)
89 typedef enum {
90 DMA_NONE = 0,
91 DMA1_ST0_HANDLER = 1,
92 DMA1_ST1_HANDLER,
93 DMA1_ST2_HANDLER,
94 DMA1_ST3_HANDLER,
95 DMA1_ST4_HANDLER,
96 DMA1_ST5_HANDLER,
97 DMA1_ST6_HANDLER,
98 DMA1_ST7_HANDLER,
99 DMA2_ST0_HANDLER,
100 DMA2_ST1_HANDLER,
101 DMA2_ST2_HANDLER,
102 DMA2_ST3_HANDLER,
103 DMA2_ST4_HANDLER,
104 DMA2_ST5_HANDLER,
105 DMA2_ST6_HANDLER,
106 DMA2_ST7_HANDLER,
107 DMA_LAST_HANDLER = DMA2_ST7_HANDLER
108 } dmaIdentifier_e;
110 #define DMA_DEVICE_NO(x) ((((x)-1) / 8) + 1)
111 #define DMA_DEVICE_INDEX(x) ((((x)-1) % 8))
112 #define DMA_OUTPUT_INDEX 0
113 #define DMA_OUTPUT_STRING "DMA%d Stream %d:"
114 #define DMA_INPUT_STRING "DMA%d_ST%d"
116 #define DEFINE_DMA_CHANNEL(d, s, f) { \
117 .dma = d, \
118 .ref = (dmaResource_t *)d ## _Stream ## s, \
119 .stream = s, \
120 .irqHandlerCallback = NULL, \
121 .flagsShift = f, \
122 .irqN = d ## _Stream ## s ## _IRQn, \
123 .userParam = 0, \
124 .owner.owner = 0, \
125 .owner.resourceIndex = 0 \
128 #define DEFINE_DMA_IRQ_HANDLER(d, s, i) FAST_IRQ_HANDLER void DMA ## d ## _Stream ## s ## _IRQHandler(void) {\
129 const uint8_t index = DMA_IDENTIFIER_TO_INDEX(i); \
130 dmaCallbackHandlerFuncPtr handler = dmaDescriptors[index].irqHandlerCallback; \
131 if (handler) \
132 handler(&dmaDescriptors[index]); \
135 #define DMA_CLEAR_FLAG(d, flag) if (d->flagsShift > 31) d->dma->HIFCR = (flag << (d->flagsShift - 32)); else d->dma->LIFCR = (flag << d->flagsShift)
136 #define DMA_GET_FLAG_STATUS(d, flag) (d->flagsShift > 31 ? d->dma->HISR & (flag << (d->flagsShift - 32)): d->dma->LISR & (flag << d->flagsShift))
139 #define DMA_IT_TCIF ((uint32_t)0x00000020)
140 #define DMA_IT_HTIF ((uint32_t)0x00000010)
141 #define DMA_IT_TEIF ((uint32_t)0x00000008)
142 #define DMA_IT_DMEIF ((uint32_t)0x00000004)
143 #define DMA_IT_FEIF ((uint32_t)0x00000001)
145 void dmaMuxEnable(dmaIdentifier_e identifier, uint32_t dmaMuxId);
147 #else
149 #if defined(STM32G4)
151 typedef enum {
152 DMA_NONE = 0,
153 DMA1_CH1_HANDLER = 1,
154 DMA1_CH2_HANDLER,
155 DMA1_CH3_HANDLER,
156 DMA1_CH4_HANDLER,
157 DMA1_CH5_HANDLER,
158 DMA1_CH6_HANDLER,
159 DMA1_CH7_HANDLER,
160 DMA1_CH8_HANDLER,
161 DMA2_CH1_HANDLER,
162 DMA2_CH2_HANDLER,
163 DMA2_CH3_HANDLER,
164 DMA2_CH4_HANDLER,
165 DMA2_CH5_HANDLER,
166 DMA2_CH6_HANDLER,
167 DMA2_CH7_HANDLER,
168 DMA2_CH8_HANDLER,
169 DMA_LAST_HANDLER = DMA2_CH8_HANDLER
170 } dmaIdentifier_e;
172 #define DMA_DEVICE_NO(x) ((((x)-1) / 8) + 1)
173 #define DMA_DEVICE_INDEX(x) ((((x)-1) % 8) + 1)
175 uint32_t dmaGetChannel(const uint8_t channel);
177 #else // !STM32G4
179 typedef enum {
180 DMA_NONE = 0,
181 DMA1_CH1_HANDLER = 1,
182 DMA1_CH2_HANDLER,
183 DMA1_CH3_HANDLER,
184 DMA1_CH4_HANDLER,
185 DMA1_CH5_HANDLER,
186 DMA1_CH6_HANDLER,
187 DMA1_CH7_HANDLER,
188 DMA_LAST_HANDLER = DMA1_CH7_HANDLER
189 } dmaIdentifier_e;
191 #define DMA_DEVICE_NO(x) ((((x)-1) / 7) + 1)
192 #define DMA_DEVICE_INDEX(x) ((((x)-1) % 7) + 1)
194 #endif // STM32G4
196 #define DMA_OUTPUT_INDEX 0
197 #define DMA_OUTPUT_STRING "DMA%d Channel %d:"
198 #define DMA_INPUT_STRING "DMA%d_CH%d"
200 #define DEFINE_DMA_CHANNEL(d, c, f) { \
201 .dma = d, \
202 .ref = (dmaResource_t *)d ## _Channel ## c, \
203 .irqHandlerCallback = NULL, \
204 .flagsShift = f, \
205 .irqN = d ## _Channel ## c ## _IRQn, \
206 .userParam = 0, \
207 .owner.owner = 0, \
208 .owner.resourceIndex = 0 \
211 #define DMA_HANDLER_CODE
213 #define DEFINE_DMA_IRQ_HANDLER(d, c, i) DMA_HANDLER_CODE void DMA ## d ## _Channel ## c ## _IRQHandler(void) {\
214 const uint8_t index = DMA_IDENTIFIER_TO_INDEX(i); \
215 dmaCallbackHandlerFuncPtr handler = dmaDescriptors[index].irqHandlerCallback; \
216 if (handler) \
217 handler(&dmaDescriptors[index]); \
220 #define DMA_CLEAR_FLAG(d, flag) d->dma->IFCR = (flag << d->flagsShift)
221 #define DMA_GET_FLAG_STATUS(d, flag) (d->dma->ISR & (flag << d->flagsShift))
223 #define DMA_IT_TCIF ((uint32_t)0x00000002)
224 #define DMA_IT_HTIF ((uint32_t)0x00000004)
225 #define DMA_IT_TEIF ((uint32_t)0x00000008)
226 #endif
228 // Macros to avoid direct register and register bit access
230 #if defined(STM32F4) || defined(STM32F7)
231 #define IS_DMA_ENABLED(reg) (((DMA_ARCH_TYPE *)(reg))->CR & DMA_SxCR_EN)
232 #define REG_NDTR NDTR
233 #elif defined(STM32H7)
234 // For H7, we have to differenciate DMA1/2 and BDMA for access to the control register.
235 // HAL library has a macro for this, but it is extremely inefficient in that it compares
236 // the address against all possible values.
237 // Here, we just compare the address against regions of memory.
238 #if defined(STM32H7A3xx) || defined(STM32H7A3xxQ)
239 // For H7A3, if it's lower than CD_AHB2PERIPH_BASE, then it's DMA1/2 and it's stream based.
240 // If not, it's BDMA and it's channel based.
241 #define IS_DMA_ENABLED(reg) \
242 ((uint32_t)(reg) < CD_AHB2PERIPH_BASE) ? \
243 (((DMA_Stream_TypeDef *)(reg))->CR & DMA_SxCR_EN) : \
244 (((BDMA_Channel_TypeDef *)(reg))->CCR & BDMA_CCR_EN)
245 #else
246 // For H743 and H750, if it's not in D3 peripheral area, then it's DMA1/2 and it's stream based.
247 // If not, it's BDMA and it's channel based.
248 #define IS_DMA_ENABLED(reg) \
249 ((uint32_t)(reg) < D3_AHB1PERIPH_BASE) ? \
250 (((DMA_Stream_TypeDef *)(reg))->CR & DMA_SxCR_EN) : \
251 (((BDMA_Channel_TypeDef *)(reg))->CCR & BDMA_CCR_EN)
252 #endif
253 #elif defined(STM32G4)
254 #define IS_DMA_ENABLED(reg) (((DMA_ARCH_TYPE *)(reg))->CCR & DMA_CCR_EN)
255 // Missing __HAL_DMA_SET_COUNTER in FW library V1.0.0
256 #define __HAL_DMA_SET_COUNTER(__HANDLE__, __COUNTER__) ((__HANDLE__)->Instance->CNDTR = (uint16_t)(__COUNTER__))
257 #elif defined(AT32F4)
258 #define DMA_CCR_EN 1
259 #define IS_DMA_ENABLED(reg) (((DMA_ARCH_TYPE *)(reg))->ctrl_bit.chen & DMA_CCR_EN)
260 #elif defined(APM32F4)
261 #define IS_DMA_ENABLED(reg) (((DMA_ARCH_TYPE *)(reg))->SCFG & DMA_SCFGx_EN)
262 #define REG_NDTR NDATA
263 #else
264 #define IS_DMA_ENABLED(reg) (((DMA_ARCH_TYPE *)(reg))->CCR & DMA_CCR_EN)
265 #define DMAx_SetMemoryAddress(reg, address) ((DMA_ARCH_TYPE *)(reg))->CMAR = (uint32_t)&s->port.txBuffer[s->port.txBufferTail]
266 #endif
268 dmaIdentifier_e dmaAllocate(dmaIdentifier_e identifier, resourceOwner_e owner, uint8_t resourceIndex);
269 void dmaEnable(dmaIdentifier_e identifier);
270 void dmaSetHandler(dmaIdentifier_e identifier, dmaCallbackHandlerFuncPtr callback, uint32_t priority, uint32_t userParam);
272 dmaIdentifier_e dmaGetIdentifier(const dmaResource_t* channel);
273 const resourceOwner_t *dmaGetOwner(dmaIdentifier_e identifier);
274 dmaChannelDescriptor_t* dmaGetDescriptorByIdentifier(const dmaIdentifier_e identifier);
275 uint32_t dmaGetChannel(const uint8_t channel);
278 // Wrapper macros to cast dmaResource_t back into DMA_ARCH_TYPE
281 #if defined(USE_HAL_DRIVER)
283 // We actually need these LL case only
285 #define xLL_EX_DMA_DeInit(dmaResource) LL_EX_DMA_DeInit((DMA_ARCH_TYPE *)(dmaResource))
286 #define xLL_EX_DMA_Init(dmaResource, initstruct) LL_EX_DMA_Init((DMA_ARCH_TYPE *)(dmaResource), initstruct)
287 #define xLL_EX_DMA_DisableResource(dmaResource) LL_EX_DMA_DisableResource((DMA_ARCH_TYPE *)(dmaResource))
288 #define xLL_EX_DMA_EnableResource(dmaResource) LL_EX_DMA_EnableResource((DMA_ARCH_TYPE *)(dmaResource))
289 #define xLL_EX_DMA_GetDataLength(dmaResource) LL_EX_DMA_GetDataLength((DMA_ARCH_TYPE *)(dmaResource))
290 #define xLL_EX_DMA_SetDataLength(dmaResource, length) LL_EX_DMA_SetDataLength((DMA_ARCH_TYPE *)(dmaResource), length)
291 #define xLL_EX_DMA_EnableIT_TC(dmaResource) LL_EX_DMA_EnableIT_TC((DMA_ARCH_TYPE *)(dmaResource))
293 #elif defined(USE_ATBSP_DRIVER)
295 #else
297 #define xDMA_Init(dmaResource, initStruct) DMA_Init((DMA_ARCH_TYPE *)(dmaResource), initStruct)
298 #define xDMA_DeInit(dmaResource) DMA_DeInit((DMA_ARCH_TYPE *)(dmaResource))
299 #define xDMA_Cmd(dmaResource, newState) DMA_Cmd((DMA_ARCH_TYPE *)(dmaResource), newState)
300 #define xDMA_ITConfig(dmaResource, flags, newState) DMA_ITConfig((DMA_ARCH_TYPE *)(dmaResource), flags, newState)
301 #define xDMA_GetCurrDataCounter(dmaResource) DMA_GetCurrDataCounter((DMA_ARCH_TYPE *)(dmaResource))
302 #define xDMA_SetCurrDataCounter(dmaResource, count) DMA_SetCurrDataCounter((DMA_ARCH_TYPE *)(dmaResource), count)
303 #define xDMA_GetFlagStatus(dmaResource, flags) DMA_GetFlagStatus((DMA_ARCH_TYPE *)(dmaResource), flags)
304 #define xDMA_ClearFlag(dmaResource, flags) DMA_ClearFlag((DMA_ARCH_TYPE *)(dmaResource), flags)
305 #define xDMA_MemoryTargetConfig(dmaResource, address, target) DMA_MemoryTargetConfig((DMA_ARCH_TYPE *)(dmaResource), address, target)
307 #endif