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)
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/>.
23 #include "drivers/resource.h"
25 #define CACHE_LINE_SIZE 32
26 #define CACHE_LINE_MASK (CACHE_LINE_SIZE - 1)
28 // dmaResource_t is a opaque data type which represents a single DMA engine,
29 // called and implemented differently in different families of STM32s.
30 // The opaque data type provides uniform handling of the engine in source code.
31 // The engines are referenced by dmaResource_t through out the Betaflight code,
32 // and then converted back to DMA_ARCH_TYPE which is a native type for
33 // the particular MCU type when calling library functions.
35 typedef struct dmaResource_s dmaResource_t
;
37 #if defined(STM32F4) || defined(STM32F7)
38 #define DMA_ARCH_TYPE DMA_Stream_TypeDef
39 #elif defined(STM32H7)
40 // H7 has stream based DMA and channel based BDMA, but we ignore BDMA (for now).
41 #define DMA_ARCH_TYPE DMA_Stream_TypeDef
43 #define DMA_ARCH_TYPE DMA_Channel_TypeDef
46 struct dmaChannelDescriptor_s
;
47 typedef void (*dmaCallbackHandlerFuncPtr
)(struct dmaChannelDescriptor_s
*channelDescriptor
);
49 typedef struct dmaChannelDescriptor_s
{
52 #if defined(STM32F4) || defined(STM32F7) || defined(STM32H7) || defined(STM32G4)
55 dmaCallbackHandlerFuncPtr irqHandlerCallback
;
59 resourceOwner_t owner
;
60 uint8_t resourceIndex
;
61 uint32_t completeFlag
;
62 } dmaChannelDescriptor_t
;
65 //#define HAL_CLEANINVALIDATECACHE(addr, size) (SCB_CleanInvalidateDCache_by_Addr((uint32_t*)((uint32_t)addr & ~0x1f), ((uint32_t)(addr + size + 0x1f) & ~0x1f) - ((uint32_t)addr & ~0x1f)))
66 //#define HAL_CLEANCACHE(addr, size) (SCB_CleanDCache_by_Addr((uint32_t*)((uint32_t)addr & ~0x1f), ((uint32_t)(addr + size + 0x1f) & ~0x1f) - ((uint32_t)addr & ~0x1f)))
70 #define DMA_IDENTIFIER_TO_INDEX(x) ((x) - 1)
72 #if defined(STM32F4) || defined(STM32F7) || defined(STM32H7)
92 DMA_LAST_HANDLER
= DMA2_ST7_HANDLER
95 #define DMA_DEVICE_NO(x) ((((x)-1) / 8) + 1)
96 #define DMA_DEVICE_INDEX(x) ((((x)-1) % 8))
97 #define DMA_OUTPUT_INDEX 0
98 #define DMA_OUTPUT_STRING "DMA%d Stream %d:"
99 #define DMA_INPUT_STRING "DMA%d_ST%d"
101 #define DEFINE_DMA_CHANNEL(d, s, f) { \
103 .ref = (dmaResource_t *)d ## _Stream ## s, \
105 .irqHandlerCallback = NULL, \
107 .irqN = d ## _Stream ## s ## _IRQn, \
110 .owner.resourceIndex = 0 \
113 #define DEFINE_DMA_IRQ_HANDLER(d, s, i) void DMA ## d ## _Stream ## s ## _IRQHandler(void) {\
114 const uint8_t index = DMA_IDENTIFIER_TO_INDEX(i); \
115 dmaCallbackHandlerFuncPtr handler = dmaDescriptors[index].irqHandlerCallback; \
117 handler(&dmaDescriptors[index]); \
120 #define DMA_CLEAR_FLAG(d, flag) if (d->flagsShift > 31) d->dma->HIFCR = (flag << (d->flagsShift - 32)); else d->dma->LIFCR = (flag << d->flagsShift)
121 #define DMA_GET_FLAG_STATUS(d, flag) (d->flagsShift > 31 ? d->dma->HISR & (flag << (d->flagsShift - 32)): d->dma->LISR & (flag << d->flagsShift))
124 #define DMA_IT_TCIF ((uint32_t)0x00000020)
125 #define DMA_IT_HTIF ((uint32_t)0x00000010)
126 #define DMA_IT_TEIF ((uint32_t)0x00000008)
127 #define DMA_IT_DMEIF ((uint32_t)0x00000004)
128 #define DMA_IT_FEIF ((uint32_t)0x00000001)
130 dmaIdentifier_e
dmaGetIdentifier(const dmaResource_t
*stream
);
131 dmaChannelDescriptor_t
* dmaGetDmaDescriptor(const dmaResource_t
*stream
);
132 dmaResource_t
*dmaGetRefByIdentifier(const dmaIdentifier_e identifier
);
133 uint32_t dmaGetChannel(const uint8_t channel
);
141 DMA1_CH1_HANDLER
= 1,
157 DMA_LAST_HANDLER
= DMA2_CH8_HANDLER
160 #define DMA_DEVICE_NO(x) ((((x)-1) / 8) + 1)
161 #define DMA_DEVICE_INDEX(x) ((((x)-1) % 8) + 1)
163 uint32_t dmaGetChannel(const uint8_t channel
);
169 DMA1_CH1_HANDLER
= 1,
176 #if defined(STM32F3) || defined(STM32F10X_CL)
182 DMA_LAST_HANDLER
= DMA2_CH5_HANDLER
184 DMA_LAST_HANDLER
= DMA1_CH7_HANDLER
188 #define DMA_DEVICE_NO(x) ((((x)-1) / 7) + 1)
189 #define DMA_DEVICE_INDEX(x) ((((x)-1) % 7) + 1)
193 #define DMA_OUTPUT_INDEX 0
194 #define DMA_OUTPUT_STRING "DMA%d Channel %d:"
195 #define DMA_INPUT_STRING "DMA%d_CH%d"
197 #define DEFINE_DMA_CHANNEL(d, c, f) { \
199 .ref = (dmaResource_t *)d ## _Channel ## c, \
200 .irqHandlerCallback = NULL, \
202 .irqN = d ## _Channel ## c ## _IRQn, \
205 .owner.resourceIndex = 0 \
208 #if defined(USE_CCM_CODE) && defined(STM32F3)
209 #define DMA_HANDLER_CODE CCM_CODE
211 #define DMA_HANDLER_CODE
214 #define DEFINE_DMA_IRQ_HANDLER(d, c, i) DMA_HANDLER_CODE void DMA ## d ## _Channel ## c ## _IRQHandler(void) {\
215 const uint8_t index = DMA_IDENTIFIER_TO_INDEX(i); \
216 dmaCallbackHandlerFuncPtr handler = dmaDescriptors[index].irqHandlerCallback; \
218 handler(&dmaDescriptors[index]); \
221 #define DMA_CLEAR_FLAG(d, flag) d->dma->IFCR = (flag << d->flagsShift)
222 #define DMA_GET_FLAG_STATUS(d, flag) (d->dma->ISR & (flag << d->flagsShift))
224 #define DMA_IT_TCIF ((uint32_t)0x00000002)
225 #define DMA_IT_HTIF ((uint32_t)0x00000004)
226 #define DMA_IT_TEIF ((uint32_t)0x00000008)
228 dmaIdentifier_e
dmaGetIdentifier(const dmaResource_t
* channel
);
229 dmaResource_t
* dmaGetRefByIdentifier(const dmaIdentifier_e identifier
);
233 // Macros to avoid direct register and register bit access
235 #if defined(STM32F4) || defined(STM32F7)
236 #define IS_DMA_ENABLED(reg) (((DMA_ARCH_TYPE *)(reg))->CR & DMA_SxCR_EN)
237 #define REG_NDTR NDTR
238 #elif defined(STM32H7)
239 // For H7, we have to differenciate DMA1/2 and BDMA for access to the control register.
240 // HAL library has a macro for this, but it is extremely inefficient in that it compares
241 // the address against all possible values.
242 // Here, we just compare the address against regions of memory.
243 #if defined(STM32H7A3xx) || defined(STM32H7A3xxQ)
244 // For H7A3, if it's lower than CD_AHB2PERIPH_BASE, then it's DMA1/2 and it's stream based.
245 // If not, it's BDMA and it's channel based.
246 #define IS_DMA_ENABLED(reg) \
247 ((uint32_t)(reg) < CD_AHB2PERIPH_BASE) ? \
248 (((DMA_Stream_TypeDef *)(reg))->CR & DMA_SxCR_EN) : \
249 (((BDMA_Channel_TypeDef *)(reg))->CCR & BDMA_CCR_EN)
251 // For H743 and H750, if it's not in D3 peripheral area, then it's DMA1/2 and it's stream based.
252 // If not, it's BDMA and it's channel based.
253 #define IS_DMA_ENABLED(reg) \
254 ((uint32_t)(reg) < D3_AHB1PERIPH_BASE) ? \
255 (((DMA_Stream_TypeDef *)(reg))->CR & DMA_SxCR_EN) : \
256 (((BDMA_Channel_TypeDef *)(reg))->CCR & BDMA_CCR_EN)
258 #elif defined(STM32G4)
259 #define IS_DMA_ENABLED(reg) (((DMA_ARCH_TYPE *)(reg))->CCR & DMA_CCR_EN)
260 // Missing __HAL_DMA_SET_COUNTER in FW library V1.0.0
261 #define __HAL_DMA_SET_COUNTER(__HANDLE__, __COUNTER__) ((__HANDLE__)->Instance->CNDTR = (uint16_t)(__COUNTER__))
264 #define DMA_CCR_EN 1 // Not defined anywhere ...
266 #define IS_DMA_ENABLED(reg) (((DMA_ARCH_TYPE *)(reg))->CCR & DMA_CCR_EN)
267 #define DMAx_SetMemoryAddress(reg, address) ((DMA_ARCH_TYPE *)(reg))->CMAR = (uint32_t)&s->port.txBuffer[s->port.txBufferTail]
270 void dmaInit(dmaIdentifier_e identifier
, resourceOwner_e owner
, uint8_t resourceIndex
);
271 void dmaSetHandler(dmaIdentifier_e identifier
, dmaCallbackHandlerFuncPtr callback
, uint32_t priority
, uint32_t userParam
);
273 const resourceOwner_t
*dmaGetOwner(dmaIdentifier_e identifier
);
274 dmaChannelDescriptor_t
* dmaGetDescriptorByIdentifier(const dmaIdentifier_e identifier
);
277 // Wrapper macros to cast dmaResource_t back into DMA_ARCH_TYPE
280 #ifdef USE_HAL_DRIVER
282 // We actually need these LL case only
284 #define xLL_EX_DMA_DeInit(dmaResource) LL_EX_DMA_DeInit((DMA_ARCH_TYPE *)(dmaResource))
285 #define xLL_EX_DMA_Init(dmaResource, initstruct) LL_EX_DMA_Init((DMA_ARCH_TYPE *)(dmaResource), initstruct)
286 #define xLL_EX_DMA_DisableResource(dmaResource) LL_EX_DMA_DisableResource((DMA_ARCH_TYPE *)(dmaResource))
287 #define xLL_EX_DMA_EnableResource(dmaResource) LL_EX_DMA_EnableResource((DMA_ARCH_TYPE *)(dmaResource))
288 #define xLL_EX_DMA_GetDataLength(dmaResource) LL_EX_DMA_GetDataLength((DMA_ARCH_TYPE *)(dmaResource))
289 #define xLL_EX_DMA_SetDataLength(dmaResource, length) LL_EX_DMA_SetDataLength((DMA_ARCH_TYPE *)(dmaResource), length)
290 #define xLL_EX_DMA_EnableIT_TC(dmaResource) LL_EX_DMA_EnableIT_TC((DMA_ARCH_TYPE *)(dmaResource))
294 #define xDMA_Init(dmaResource, initStruct) DMA_Init((DMA_ARCH_TYPE *)(dmaResource), initStruct)
295 #define xDMA_DeInit(dmaResource) DMA_DeInit((DMA_ARCH_TYPE *)(dmaResource))
296 #define xDMA_Cmd(dmaResource, newState) DMA_Cmd((DMA_ARCH_TYPE *)(dmaResource), newState)
297 #define xDMA_ITConfig(dmaResource, flags, newState) DMA_ITConfig((DMA_ARCH_TYPE *)(dmaResource), flags, newState)
298 #define xDMA_GetCurrDataCounter(dmaResource) DMA_GetCurrDataCounter((DMA_ARCH_TYPE *)(dmaResource))
299 #define xDMA_SetCurrDataCounter(dmaResource, count) DMA_SetCurrDataCounter((DMA_ARCH_TYPE *)(dmaResource), count)
300 #define xDMA_GetFlagStatus(dmaResource, flags) DMA_GetFlagStatus((DMA_ARCH_TYPE *)(dmaResource), flags)
301 #define xDMA_ClearFlag(dmaResource, flags) DMA_ClearFlag((DMA_ARCH_TYPE *)(dmaResource), flags)
302 #define xDMA_MemoryTargetConfig(dmaResource, address, target) DMA_MemoryTargetConfig((DMA_ARCH_TYPE *)(dmaResource), address, target)