Paparazzi UAS v7.0_unstable
Paparazzi is a free software Unmanned Aircraft System.
Loading...
Searching...
No Matches
hal_stm32_dma.h
Go to the documentation of this file.
1/*
2 * Copyright (C) 2019 Alexandre Bustico, Gautier Hattenberger
3 *
4 * This file is part of paparazzi.
5 *
6 * paparazzi is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2, or (at your option)
9 * any later version.
10 *
11 * paparazzi is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with paparazzi; see the file COPYING. If not, see
18 * <http://www.gnu.org/licenses/>.
19 */
20
29#pragma once
30
31#include <ch.h>
32#include <hal.h>
33
34#ifdef __cplusplus
35extern "C" {
36#endif
37
42#if !defined(STM32_DMA_USE_WAIT) || defined(__DOXYGEN__)
43#define STM32_DMA_USE_WAIT TRUE
44#endif
45
50#if !defined(STM32_DMA_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__)
51#define STM32_DMA_USE_MUTUAL_EXCLUSION FALSE
52#endif
53
54#if !defined(STM32_DMA_SUPPORTS_CSELR) || defined(__DOXYGEN__)
55#define STM32_DMA_SUPPORTS_CSELR FALSE
56#endif
57
58#if !defined(STM32_DMA_SUPPORTS_DMAMUX) || defined(__DOXYGEN__)
59#define STM32_DMA_SUPPORTS_DMAMUX FALSE
60#endif
61
62#if !defined(STM32_DMA_DUMMY_MEMORY_AREA_ADDRESS) || defined(__DOXYGEN__)
63#define STM32_DMA_DUMMY_MEMORY_AREA_ADDRESS 0x80000000
64#endif
65
66#if !defined(__DCACHE_PRESENT)
67#define __DCACHE_PRESENT FALSE
68#endif
69
81
94
103
107typedef enum {
110#if STM32_DMA_USE_DOUBLE_BUFFER
112#endif
114
118typedef struct DMADriver DMADriver;
119
128typedef void (*dmacallback_t)(DMADriver *dmap, void *buffer, const size_t n);
129
138typedef void * (*dmanextcallback_t)(DMADriver *dmap, const size_t n);
139
140
149
150
151
152/*===========================================================================*/
153/* Driver macros. */
154/*===========================================================================*/
155#if (STM32_DMA_USE_WAIT == TRUE) || defined(__DOXYGEN__)
168#define _dma_reset_i(dmap) \
169 osalThreadResumeI(&(dmap)->thread, MSG_RESET)
170
178#define _dma_reset_s(dmap) \
179 osalThreadResumeS(&(dmap)->thread, MSG_RESET)
180
188#define _dma_wakeup_isr(dmap) { \
189 osalSysLockFromISR(); \
190 osalThreadResumeI(&(dmap)->thread, MSG_OK); \
191 osalSysUnlockFromISR(); \
192 }
193
201#define _dma_timeout_isr(dmap) { \
202 osalSysLockFromISR(); \
203 osalThreadResumeI(&(dmap)->thread, MSG_TIMEOUT); \
204 osalSysUnlockFromISR(); \
205 }
206#else /* !STM32_DMA_USE_WAIT */
207#define _dma_reset_i(dmap)
208#define _dma_reset_s(dmap)
209#define _dma_wakeup_isr(dmap)
210#define _dma_timeout_isr(dmap)
211#endif /* !STM32_DMA_USE_WAIT */
212
225static inline void _dma_isr_half_code(DMADriver *dmap);
226
227
242static inline void _dma_isr_full_code(DMADriver *dmap);
243
244
260static inline void _dma_isr_error_code(DMADriver *dmap, dmaerrormask_t err);
261
262
263
264
273typedef struct {
279
280#if STM32_DMA_SUPPORTS_DMAMUX
281 uint32_t dmamux; // 4 bytes wide for mdma use
282#else
283#if STM32_DMA_SUPPORTS_CSELR
288 union {
289 uint8_t request; // STM terminology for dmaV1
290 uint8_t channel; // ChibiOS terminology for both dmaV1 and dmaV2 (portability)
291 };
292#else
294#endif
295#endif
296
301
302
307
308
313
314
319
320#if STM32_DMA_USE_DOUBLE_BUFFER
326#endif
327
332#if STM32_DMA_USE_ASYNC_TIMOUT
338#endif
339
340
345
346
351
356
360 uint8_t psize; // 1,2,4
361
365 uint8_t msize; // 1,2,4
366#if __DCACHE_PRESENT
370 union {
371 bool dcache_memory_in_use; // this name was hardly meaningfull
373 };
374#endif
375#if STM32_DMA_ADVANCED
376#define STM32_DMA_FIFO_SIZE 16 // hardware specification for dma V2
377
381 uint8_t pburst; // 0(burst disabled), 4, 8, 16
382
386 uint8_t mburst; // 0(burst disabled), 4, 8, 16
387
391 uint8_t fifo; // 0(fifo disabled), 1, 2, 3, 4 : 25, 50, 75, 100%
392
396 bool periph_inc_size_4; // PINCOS bit
397
401 bool transfert_end_ctrl_by_periph; // PFCTRL bit
402#endif
403#if STM32_DMA_DRIVER_USER_DATA_FIELD
404 void *user_data;
405#endif
406} DMAConfig;
407
408
412struct DMADriver {
417
422
423#if STM32_DMA_USE_WAIT || defined(__DOXYGEN__)
427 thread_reference_t thread;
428#endif
429#if STM32_DMA_USE_MUTUAL_EXCLUSION || defined(__DOXYGEN__)
434#endif /* STM32_DMA_USE_MUTUAL_EXCLUSION */
435#if STM32_DMA_USE_ASYNC_TIMOUT
439 uint8_t *volatile currPtr;
440
445#endif
451 void *mem0p;
452
457
458#if __DCACHE_PRESENT
462 volatile void * periphp;
463#endif
464
465#if STM32_DMA_ADVANCED
470#endif
471
475 size_t size;
476
477#if STM32_DMA_USE_DOUBLE_BUFFER
478 volatile uint32_t next_cb_errors;
479#endif
480
481#if CH_DBG_SYSTEM_STATE_CHECK
482 volatile size_t nbTransferError;
483 volatile size_t nbDirectModeError;
484 volatile size_t nbFifoError;
485 volatile size_t nbFifoFull;
486 volatile size_t nbFifoEmpty;
487 volatile dmaerrormask_t lastError;
488#endif
493
494
498#if STM32_DMA_SUPPORTS_DMAMUX == 0
500#endif
501};
502
503
504
505void dmaObjectInit(DMADriver *dmap);
506bool dmaStart(DMADriver *dmap, const DMAConfig *cfg);
507bool dmaReloadConf(DMADriver *dmap, const DMAConfig *cfg);
508void dmaStop(DMADriver *dmap);
509
510#if STM32_DMA_USE_WAIT == TRUE
511msg_t dmaTransfertTimeout(DMADriver *dmap, volatile void *periphp, void * mem0p, const size_t size,
513// helper
514static inline msg_t dmaTransfert(DMADriver *dmap, volatile void *periphp, void * mem0p, const size_t size)
515{
516 return dmaTransfertTimeout(dmap, periphp, mem0p, size, TIME_INFINITE);
517}
518#endif
519#if STM32_DMA_USE_MUTUAL_EXCLUSION == TRUE
520void dmaAcquireBus(DMADriver *dmap);
521void dmaReleaseBus(DMADriver *dmap);
522#endif
523bool dmaStartTransfert(DMADriver *dmap, volatile void *periphp, void * mem0p, const size_t size);
524void dmaStopTransfert(DMADriver *dmap);
525
526bool dmaStartTransfertI(DMADriver *dmap, volatile void *periphp, void *mem0p, const size_t size);
527void dmaStopTransfertI(DMADriver *dmap);
529#ifndef DMA_request_TypeDef
530void dmaGetRegisters(DMADriver *dmap, volatile void *periphp, void *mem0p,
531 const size_t size,
533#endif
534static inline dmastate_t dmaGetState(DMADriver *dmap) {return dmap->state;}
536
537#if STM32_DMA_USE_DOUBLE_BUFFER
547static inline dmastate_t dmaGetNextErrors(DMADriver *dmap) {return dmap->next_cb_errors;}
554static inline void dmaClearNextErrors(DMADriver *dmap) {dmap->next_cb_errors = 0U;}
555#endif
556
557// low level driver
558
559bool dma_lld_start(DMADriver *dmap, bool allocate_stream);
560void dma_lld_stop(DMADriver *dmap);
561
562
563bool dma_lld_start_transfert(DMADriver *dmap, volatile void *periphp, void *mem0p, const size_t size);
564
565
567
568#if STM32_DMA_USE_ASYNC_TIMOUT
569void dma_lld_serve_timeout_interrupt(void *arg);
570#endif
571
573
574#if STM32_DMA_USE_ASYNC_TIMOUT
577{
578 uint8_t *const baseAddr = dmap->currPtr;
579 const size_t fullSize = dmap->size;
580 const size_t halfSize = fullSize / 2;
581 size_t rem = 0;
582 uint8_t *const basePtr = (uint8_t *) dmap->mem0p;
583 uint8_t *const midPtr = ((uint8_t *) dmap->mem0p) + (dmap->config->msize * halfSize);
584 uint8_t *const endPtr = ((uint8_t *) dmap->mem0p) + (dmap->config->msize * fullSize);
585
586
587 switch (context) {
588 case (FROM_HALF_CODE) :
589 if (midPtr > baseAddr) {
590 rem = (midPtr - baseAddr) / dmap->config->msize;
591 dmap->currPtr = midPtr;
592 }
593 break;
594
595 case (FROM_FULL_CODE) :
597 rem = (endPtr - baseAddr) / dmap->config->msize;
598 dmap->currPtr = basePtr;
599 break;
600
601 case (FROM_TIMOUT_CODE) : {
602 const size_t dmaCNT = dmaStreamGetTransactionSize(dmap->dmastream);
603 const size_t index = (baseAddr - basePtr) / dmap->config->msize;
604
605 // if following test fail, it's because DMACNT has rollover during the ISR,
606 // so that we can safely ignore this TIMOUT event since a fullcode ISR will follow
607 // briefly
608 if (fullSize >= (dmaCNT + index)) {
609 rem = (fullSize - dmaCNT - index);
610 dmap->currPtr = baseAddr + (rem * dmap->config->msize);
611 }
612 }
613 break;
614 }
615
616 if (dmap->config->end_cb != NULL && (rem > 0)) {
617 dmap->config->end_cb(dmap, baseAddr, rem);
618 }
619}
620#endif
621
622static inline void _dma_isr_half_code(DMADriver *dmap)
623{
624#if STM32_DMA_USE_ASYNC_TIMOUT
625 if (dmap->config->timeout != TIME_INFINITE) {
627 chVTSetI(&dmap->vt, dmap->config->timeout,
628 &dma_lld_serve_timeout_interrupt, (void *) dmap);
630 }
632#else
633 if (dmap->config->end_cb != NULL) {
634 dmap->config->end_cb(dmap, dmap->mem0p, dmap->size / 2);
635 }
636#endif
637}
638
639static inline void _dma_isr_full_code(DMADriver *dmap)
640{
642#if STM32_DMA_USE_ASYNC_TIMOUT
643 if (dmap->config->timeout != TIME_INFINITE) {
645 chVTSetI(&dmap->vt, dmap->config->timeout,
646 &dma_lld_serve_timeout_interrupt, (void *) dmap);
648 }
650#else
651 /* Callback handling.*/
652 if (dmap->config->end_cb != NULL) {
653 if (dmap->size > 1) {
654 /* Invokes the callback passing the 2nd half of the buffer.*/
655 const size_t half_index = dmap->size / 2;
656 const uint8_t *byte_array_p = ((uint8_t *) dmap->mem0p) +
657 dmap->config->msize * half_index;
658 dmap->config->end_cb(dmap, (void *) byte_array_p, half_index);
659 } else {
660 /* Invokes the callback passing the whole buffer.*/
661 dmap->config->end_cb(dmap, dmap->mem0p, dmap->size);
662 }
663 }
664#endif
665 }
666 else if (dmap->config->op_mode == DMA_ONESHOT) { // not circular
667 /* End transfert.*/
668#if STM32_DMA_USE_ASYNC_TIMOUT
669 if (dmap->config->timeout != TIME_INFINITE) {
671 chVTResetI(&dmap->vt);
673 }
674#endif
676 if (dmap->config->end_cb != NULL) {
677 dmap->state = DMA_COMPLETE;
678 /* Invoke the callback passing the whole buffer.*/
679#if STM32_DMA_USE_ASYNC_TIMOUT
681#else
682 dmap->config->end_cb(dmap, dmap->mem0p, dmap->size);
683#endif
684 if (dmap->state == DMA_COMPLETE) {
685 dmap->state = DMA_READY;
686 }
687 } else {
688 dmap->state = DMA_READY;
689 }
690 _dma_wakeup_isr(dmap);
691 }
692#if STM32_DMA_USE_DOUBLE_BUFFER
693 else { // CONTINUOUS_DOUBLE_BUFFER
694 /* Next buffer handling */
695 void* const rawNextBuff = dmap->config->next_cb(dmap, dmap->size);
696 if (rawNextBuff == NULL)
697 dmap->next_cb_errors++;
699 void* const memXp = dma_lld_set_next_double_buffer(dmap, nextBuff);
700 /* Callback handling.*/
701 if ((dmap->config->end_cb != NULL) &&
703 dmap->config->end_cb(dmap, memXp, dmap->size);
704 }
705 }
706#endif
707}
708
709static inline void _dma_isr_error_code(DMADriver *dmap, dmaerrormask_t err) {
710#if CH_DBG_SYSTEM_STATE_CHECK == TRUE
711 if (err & DMA_ERR_TRANSFER_ERROR)
712 dmap->nbTransferError++;
713 if (err & DMA_ERR_DIRECTMODE_ERROR)
714 dmap->nbDirectModeError++;
715 if (err & DMA_ERR_FIFO_ERROR) {
716 dmap->nbFifoError++;
717 if (err & DMA_ERR_FIFO_FULL)
718 dmap->nbFifoFull++;
719 if (err & DMA_ERR_FIFO_EMPTY)
720 dmap->nbFifoEmpty++;
721 }
722 dmap->lastError = err;
723#endif
726 else
727 return;
728
729 if (dmap->config->error_cb != NULL) {
730 dmap->state = DMA_ERROR;
731 dmap->config->error_cb(dmap, err);
732 if (dmap->state == DMA_ERROR)
733 dmap->state = DMA_READY;
734 } else {
735 dmap->state = DMA_READY;
736 }
737 _dma_timeout_isr(dmap);
738}
739#ifndef DMA_request_TypeDef
740void dma_lld_get_registers(DMADriver *dmap, volatile void *periphp,
741 void *mem0p, const size_t size,
743#endif
744#ifdef __cplusplus
745}
746#endif
static pthread_mutex_t mutex
uint8_t msize
DMA memory data granurality in bytes (1,2,4)
void dmaObjectInit(DMADriver *dmap)
void(* dmaerrorcallback_t)(DMADriver *dmap, dmaerrormask_t err)
DMA error callback type.
void *(* dmanextcallback_t)(DMADriver *dmap, const size_t n)
DMA next buffer query callback type.
dmaopmode_t
DMA transfert memory mode.
@ DMA_CONTINUOUS_HALF_BUFFER
Continuous mode to/from the same buffer.
@ DMA_ONESHOT
One transert then stop
dmadirection_t
DMA transfert direction.
@ DMA_DIR_M2P
MEMORY to PERIPHERAL
@ DMA_DIR_M2M
MEMORY to MEMORY
@ DMA_DIR_P2M
PERIPHERAL to MEMORY
size_t size
hold size of current transaction
void * dma_lld_set_next_double_buffer(DMADriver *dmap, void *nextBuffer)
bool dmaStartTransfert(DMADriver *dmap, volatile void *periphp, void *mem0p, const size_t size)
Starts a DMA transaction.
bool inc_peripheral_addr
Enable increment of peripheral address after each transfert.
bool dma_lld_start(DMADriver *dmap, bool allocate_stream)
Configures and activates the DMA peripheral.
#define STM32_DMA_DUMMY_MEMORY_AREA_ADDRESS
#define _dma_wakeup_isr(dmap)
Wakes up the waiting thread.
uint8_t irq_priority
DMA IRQ priority (2 .
void dmaStop(DMADriver *dmap)
Deactivates the DMA peripheral.
msg_t dmaTransfertTimeout(DMADriver *dmap, volatile void *periphp, void *mem0p, const size_t size, sysinterval_t timeout)
Performs a DMA transaction.
void dmaGetRegisters(DMADriver *dmap, volatile void *periphp, void *mem0p, const size_t size, DMA_Stream_TypeDef *registers)
copy the dma register to memory.
uint8_t dma_priority
DMA priority (1 .
void(* dmacallback_t)(DMADriver *dmap, void *buffer, const size_t n)
DMA notification callback type.
static dmastate_t dmaGetState(DMADriver *dmap)
bool dmaStartTransfertI(DMADriver *dmap, volatile void *periphp, void *mem0p, const size_t size)
Starts a DMA transaction.
const DMAConfig * config
Current configuration data.
static size_t dmaGetTransactionCounter(DMADriver *dmap)
void dma_lld_stop(DMADriver *dmap)
Deactivates the DMA peripheral.
static void _dma_isr_error_code(DMADriver *dmap, dmaerrormask_t err)
Common ISR code, error event.
#define _dma_timeout_isr(dmap)
Wakes up the waiting thread with a timeout message.
void dma_lld_get_registers(DMADriver *dmap, volatile void *periphp, void *mem0p, const size_t size, DMA_Stream_TypeDef *registers)
Copy the register of a ready stream.
dmaerrormask_t
Possible DMA failure causes.
@ DMA_ERR_FIFO_EMPTY
DMA FIFO underrun.
@ DMA_ERR_FIFO_FULL
DMA FIFO overrun.
@ DMA_ERR_TRANSFER_ERROR
DMA transfer failure.
@ DMA_ERR_DIRECTMODE_ERROR
DMA Direct Mode failure.
@ DMA_ERR_FIFO_ERROR
DMA FIFO error.
void * mem0p
memory address
dmaerrorcallback_t error_cb
Error callback or NULL.
uint32_t stream
stream associated with transaction
dmaopmode_t op_mode
one shot, or circular half buffer, or circular double buffers
void dmaStopTransfert(DMADriver *dmap)
Stops an ongoing transaction.
uint8_t controller
controller associated with stream
static msg_t dmaTransfert(DMADriver *dmap, volatile void *periphp, void *mem0p, const size_t size)
void dmaAcquireBus(DMADriver *dmap)
Gains exclusive access to the DMA peripheral.
static void _dma_isr_full_code(DMADriver *dmap)
Common ISR code, full buffer event.
void dmaReleaseBus(DMADriver *dmap)
Releases exclusive access to the DMA peripheral.
uint32_t dmamode
hold DMA CR register for the stream
dmastate_t
Driver state machine possible states.
@ DMA_STOP
Stopped.
@ DMA_ACTIVE
Transfering.
@ DMA_ERROR
Transfert error.
@ DMA_READY
Ready.
@ DMA_UNINIT
Not initialized.
@ DMA_COMPLETE
Transfert complete.
uint8_t channel
void dma_lld_stop_transfert(DMADriver *dmap)
Stops an ongoing transaction.
dmacallback_t end_cb
Callback function associated to the stream or NULL.
void dmaStopTransfertI(DMADriver *dmap)
Stops an ongoing transaction.
static void _dma_isr_half_code(DMADriver *dmap)
Common ISR code, half buffer event.
bool dma_lld_start_transfert(DMADriver *dmap, volatile void *periphp, void *mem0p, const size_t size)
Starts a DMA transaction.
dmadirection_t direction
DMA transaction direction.
const stm32_dma_stream_t * dmastream
DMA stream associated with peripheral or memory.
volatile dmastate_t state
Driver state.
uint8_t psize
DMA peripheral data granurality in bytes (1,2,4)
bool dmaStart(DMADriver *dmap, const DMAConfig *cfg)
Configures and activates the DMA peripheral.
bool dmaReloadConf(DMADriver *dmap, const DMAConfig *cfg)
Configures and activates the DMA peripheral.
bool inc_memory_addr
Enable increment of memory address after each transfert.
uint8_t dmaGetStreamIndex(DMADriver *dmap)
DMA stream configuration structure.
Structure representing a DMA driver.
uint16_t foo
Definition main_demo5.c:58
static float timeout
unsigned int uint32_t
Typedef defining 32 bit unsigned int type.
unsigned char uint8_t
Typedef defining 8 bit unsigned char type.