53 return (dmap->
dmastream->stream->FCR & DMA_SxFCR_FS_Msk);
58 osalDbgCheck(dmap != NULL);
63 #if STM32_DMA_USE_WAIT == TRUE
66 #if STM32_DMA_USE_MUTUAL_EXCLUSION == TRUE
67 osalMutexObjectInit(&dmap->mutex);
69 #if defined( STM32_DMA_DRIVER_EXT_INIT_HOOK)
70 STM32_DMA_DRIVER_EXT_INIT_HOOK(dmap);
72 #if CH_DBG_SYSTEM_STATE_CHECK == TRUE
73 dmap->nbTransferError = dmap->nbDirectModeError = dmap->nbFifoError = 0U;
76 #if STM32_DMA_USE_ASYNC_TIMOUT
77 chVTObjectInit(&dmap->vt);
94 osalDbgCheck((dmap != NULL) && (cfg != NULL));
116 osalDbgCheck(dmap != NULL);
176 osalDbgCheckClassI();
177 #if (CH_DBG_ENABLE_ASSERTS != FALSE)
178 if (size != dmap->
size) {
179 osalDbgCheck((dmap != NULL) && (mem0p != NULL) && (periphp != NULL) &&
180 (size > 0U) && ((size == 1U) || ((size & 1U) == 0U)));
190 osalDbgAssert((
uint32_t) periphp % cfg->
psize == 0,
"peripheral address not aligned");
195 osalDbgAssert((
uint32_t) mem0p % cfg->
msize == 0,
"memory address not aligned");
211 # if STM32_DMA_ADVANCED
213 osalDbgAssert((size % (cfg->mburst * cfg->
msize / cfg->
psize)) == 0,
214 "mburst alignment rule not respected");
215 osalDbgAssert((size % (cfg->mburst * cfg->
msize)) == 0,
216 "mburst alignment rule not respected");
217 osalDbgAssert((((
uint32_t) mem0p) % cfg->mburst) == 0,
218 "memory address alignment rule not respected");
221 osalDbgAssert((size % (cfg->pburst * cfg->
psize)) == 0,
222 "pburst alignment rule not respected");
223 osalDbgAssert((((
uint32_t) periphp) % cfg->pburst) == 0,
224 "peripheral address alignment rule not respected");
235 #if STM32_DMA_USE_ASYNC_TIMOUT
236 dmap->currPtr = mem0p;
237 if (dmap->
config->timeout != TIME_INFINITE) {
238 chVTSetI(&dmap->vt, dmap->
config->timeout,
239 &dma_lld_serve_timeout_interrupt, (
void *) dmap);
260 osalDbgCheck(dmap != NULL);
287 osalDbgCheckClassI();
288 osalDbgCheck(dmap != NULL);
303 #if (STM32_DMA_USE_WAIT == TRUE) || defined(__DOXYGEN__)
334 osalDbgAssert(dmap->thread == NULL,
"already waiting");
335 osalDbgAssert(dmap->
config->
circular ==
false,
"blocking API is incompatible with circular mode");
337 msg = osalThreadSuspendTimeoutS(&dmap->thread,
timeout);
346 #if (STM32_DMA_USE_MUTUAL_EXCLUSION == TRUE) || defined(__DOXYGEN__)
361 osalDbgCheck(dmap != NULL);
363 osalMutexLock(&dmap->mutex);
378 osalDbgCheck(dmap != NULL);
380 osalMutexUnlock(&dmap->mutex);
415 switch (cfg->
psize) {
416 case 1 : psize_msk = STM32_DMA_CR_PSIZE_BYTE;
break;
417 case 2 : psize_msk = STM32_DMA_CR_PSIZE_HWORD;
break;
418 case 4 : psize_msk = STM32_DMA_CR_PSIZE_WORD;
break;
419 default: osalSysHalt(
"psize should be 1 or 2 or 4");
422 switch (cfg->
msize) {
423 case 1 : msize_msk = STM32_DMA_CR_MSIZE_BYTE;
break;
424 case 2 : msize_msk = STM32_DMA_CR_MSIZE_HWORD;
break;
425 case 4 : msize_msk = STM32_DMA_CR_MSIZE_WORD;
break;
426 default: osalDbgAssert(
false,
"msize should be 1 or 2 or 4");
432 case DMA_DIR_P2M: dir_msk = STM32_DMA_CR_DIR_P2M;
break;
433 case DMA_DIR_M2P: dir_msk = STM32_DMA_CR_DIR_M2P;
break;
434 case DMA_DIR_M2M: dir_msk = STM32_DMA_CR_DIR_M2M;
break;
435 default: osalDbgAssert(
false,
"direction not set or incorrect");
442 isr_flags |= STM32_DMA_CR_TCIE;
444 isr_flags |= STM32_DMA_CR_HTIE;
450 isr_flags |= STM32_DMA_CR_DMEIE | STM32_DMA_CR_TCIE;
453 #if CH_KERNEL_MAJOR < 6
458 #if STM32_DMA_ADVANCED
465 dir_msk | psize_msk | msize_msk | isr_flags |
466 (cfg->
circular ? STM32_DMA_CR_CIRC : 0UL) |
471 | STM32_DMA_CR_CHSEL(cfg->request)
472 #elif STM32_DMA_ADVANCED
473 | STM32_DMA_CR_CHSEL(cfg->channel)
474 | (cfg->periph_inc_size_4 ? STM32_DMA_CR_PINCOS : 0UL) |
475 (cfg->transfert_end_ctrl_by_periph ? STM32_DMA_CR_PFCTRL : 0UL)
480 #if STM32_DMA_ADVANCED
481 uint32_t pburst_msk, mburst_msk, fifo_msk;
482 switch (cfg->pburst) {
483 case 0 : pburst_msk = 0UL;
break;
484 case 4 : pburst_msk = STM32_DMA_CR_PBURST_INCR4;
break;
485 case 8 : pburst_msk = STM32_DMA_CR_PBURST_INCR8;
break;
486 case 16 : pburst_msk = STM32_DMA_CR_PBURST_INCR16;
break;
487 default: osalDbgAssert(
false,
"pburst size should be 0 or 4 or 8 or 16");
490 switch (cfg->mburst) {
491 case 0 : mburst_msk = 0UL;
break;
492 case 4 : mburst_msk = STM32_DMA_CR_MBURST_INCR4;
break;
493 case 8 : mburst_msk = STM32_DMA_CR_MBURST_INCR8;
break;
494 case 16 : mburst_msk = STM32_DMA_CR_MBURST_INCR16;
break;
495 default: osalDbgAssert(
false,
"mburst size should be 0 or 4 or 8 or 16");
499 case 0 : fifo_msk = 0UL;
break;
500 case 1 : fifo_msk = STM32_DMA_FCR_FTH_1Q;
break;
501 case 2 : fifo_msk = STM32_DMA_FCR_FTH_HALF;
break;
502 case 3 : fifo_msk = STM32_DMA_FCR_FTH_3Q;
break;
503 case 4 : fifo_msk = STM32_DMA_FCR_FTH_FULL; ;
break;
504 default: osalDbgAssert(
false,
"fifo threshold should be 1(/4) or 2(/4) or 3(/4) or 4(/4)");
509 # if (CH_DBG_ENABLE_ASSERTS != FALSE)
510 # if STM32_DMA_USE_ASYNC_TIMOUT
511 osalDbgAssert(dmap->
config->timeout != 0,
512 "timeout cannot be 0 if STM32_DMA_USE_ASYNC_TIMOUT is enabled");
513 osalDbgAssert(!((dmap->
config->timeout != TIME_INFINITE) && (dmap->
config->fifo != 0)),
514 "timeout should be dynamicly disabled (dmap->config->timeout = TIME_INFINITE) "
515 "if STM32_DMA_USE_ASYNC_TIMOUT is enabled and fifo is enabled (fifo != 0)");
522 osalDbgAssert(
false,
"psize and msize should be enabled or disabled together");
527 switch (cfg->
msize) {
529 switch (cfg->mburst) {
540 case 1:
goto forbiddenCombination;
542 case 3:
goto forbiddenCombination;
548 case 1:
goto forbiddenCombination;
549 case 2:
goto forbiddenCombination;
550 case 3:
goto forbiddenCombination;
557 switch (cfg->mburst) {
560 case 1:
goto forbiddenCombination;
562 case 3:
goto forbiddenCombination;
568 case 1:
goto forbiddenCombination;
569 case 2:
goto forbiddenCombination;
570 case 3:
goto forbiddenCombination;
576 case 1:
goto forbiddenCombination;
577 case 2:
goto forbiddenCombination;
578 case 3:
goto forbiddenCombination;
579 case 4:
goto forbiddenCombination;
584 switch (cfg->mburst) {
587 case 1:
goto forbiddenCombination;
588 case 2:
goto forbiddenCombination;
589 case 3:
goto forbiddenCombination;
595 case 1:
goto forbiddenCombination;
596 case 2:
goto forbiddenCombination;
597 case 3:
goto forbiddenCombination;
598 case 4:
goto forbiddenCombination;
603 case 1:
goto forbiddenCombination;
604 case 2:
goto forbiddenCombination;
605 case 3:
goto forbiddenCombination;
606 case 4:
goto forbiddenCombination;
613 dmap->
dmamode |= (pburst_msk | mburst_msk);
615 # if (CH_DBG_ENABLE_ASSERTS != FALSE)
625 if (((cfg->pburst * cfg->
psize) == STM32_DMA_FIFO_SIZE) && (cfg->fifo == 3)) {
626 goto forbiddenCombination;
635 osalDbgAssert(dmap->
controller == 2,
"M2M not available on DMA1");
636 osalDbgAssert(cfg->
circular ==
false,
"M2M not available in circular mode");
643 #if STM32_DMA_ADVANCED
645 dmap->fifomode = STM32_DMA_FCR_DMDIS | STM32_DMA_FCR_FEIE | fifo_msk;
649 "msize == psize is mandatory when fifo is disabled");
654 #if CH_KERNEL_MAJOR < 6
655 const bool error = dmaStreamAllocate( dmap->
dmastream,
667 osalDbgAssert(
false,
"stream already allocated");
673 #if (CH_DBG_ENABLE_ASSERTS != FALSE)
674 #if STM32_DMA_ADVANCED
675 forbiddenCombination:
676 chSysHalt(
"forbidden combination of msize, mburst, fifo, see FIFO threshold "
677 "configuration in reference manuel");
694 osalDbgAssert(PORT_IRQ_IS_VALID_KERNEL_PRIORITY(cfg->
irq_priority),
"illegal IRQ priority");
696 if (dmap->
config->dcache_memory_in_use &&
698 cacheBufferFlush(mem0p, size * dmap->
config->
msize);
703 dmap->periphp = periphp;
706 dmaStreamSetPeripheral(dmap->
dmastream, periphp);
707 dmaStreamSetMemory0(dmap->
dmastream, mem0p);
708 dmaStreamSetTransactionSize(dmap->
dmastream, size);
710 #if STM32_DMA_ADVANCED
711 dmaStreamSetFIFO(dmap->
dmastream, dmap->fifomode);
739 #if CH_KERNEL_MAJOR < 6
761 #if CH_DBG_SYSTEM_STATE_CHECK
762 const uint32_t feif_msk = dmap->
config->fifo != 0U ? STM32_DMA_ISR_FEIF : 0U;
764 static const uint32_t feif_msk = 0U;
767 if ((flags & (STM32_DMA_ISR_TEIF | STM32_DMA_ISR_DMEIF | feif_msk)) != 0U) {
783 if (dmap->
config->dcache_memory_in_use)
787 cacheBufferInvalidate(dmap->
mem0p,
791 cacheBufferInvalidate(dmap->periphp,
797 if ((flags & STM32_DMA_ISR_TCIF) != 0) {
800 }
else if ((flags & STM32_DMA_ISR_HTIF) != 0) {
808 #if STM32_DMA_USE_ASYNC_TIMOUT
814 void dma_lld_serve_timeout_interrupt(
void *arg)
819 chVTSetI(&dmap->vt, dmap->
config->timeout,
820 &dma_lld_serve_timeout_interrupt, (
void *) dmap);
821 chSysUnlockFromISR();
823 async_timout_enabled_call_end_cb(dmap, FROM_TIMOUT_CODE);
void dmaObjectInit(DMADriver *dmap)
bool dmaStartTransfert(DMADriver *dmap, volatile void *periphp, void *mem0p, const size_t size)
Starts a DMA transaction.
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.
bool dmaStartTransfertI(DMADriver *dmap, volatile void *periphp, void *mem0p, const size_t size)
Starts a DMA transaction.
static uint32_t getFCR_FS(const DMADriver *dmap)
void dma_lld_stop(DMADriver *dmap)
Deactivates the DMA peripheral.
void dmaStopTransfert(DMADriver *dmap)
Stops an ongoing transaction.
bool dma_lld_start(DMADriver *dmap)
Configures and activates the DMA peripheral.
void dmaAcquireBus(DMADriver *dmap)
Gains exclusive access to the DMA peripheral.
void dmaReleaseBus(DMADriver *dmap)
Releases exclusive access to the DMA peripheral.
void dma_lld_stop_transfert(DMADriver *dmap)
Stops an ongoing transaction.
void dmaStopTransfertI(DMADriver *dmap)
Stops an ongoing transaction.
bool dma_lld_start_transfert(DMADriver *dmap, volatile void *periphp, void *mem0p, const size_t size)
Starts a DMA transaction.
bool dmaStart(DMADriver *dmap, const DMAConfig *cfg)
Configures and activates the DMA peripheral.
static void dma_lld_serve_interrupt(DMADriver *dmap, uint32_t flags)
DMA ISR service routine.
STM32 DMA subsystem driver header.
uint8_t msize
DMA memory data granurality in bytes (1,2,4)
@ 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
bool inc_peripheral_addr
Enable increment of peripheral address after each transfert.
#define _dma_reset_i(dmap)
Resumes a thread waiting for a dma transfert completion.
#define _dma_reset_s(dmap)
Resumes a thread waiting for a dma transfert completion.
uint8_t irq_priority
DMA IRQ priority (2 .
uint8_t dma_priority
DMA priority (1 .
const DMAConfig * config
Current configuration data.
bool circular
Enables the circular buffer mode for the stream.
static void _dma_isr_error_code(DMADriver *dmap, dmaerrormask_t err)
Common ISR code, error event.
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
#define STM32_DMA_SUPPORTS_CSELR
uint8_t controller
controller associated with stream
static void _dma_isr_full_code(DMADriver *dmap)
Common ISR code, full buffer event.
uint32_t dmamode
hold DMA CR register for the stream
@ DMA_ERROR
Transfert error.
@ DMA_COMPLETE
Transfert complete.
dmacallback_t end_cb
Callback function associated to the stream or NULL.
static void _dma_isr_half_code(DMADriver *dmap)
Common ISR code, half buffer event.
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 inc_memory_addr
Enable increment of memory address after each transfert.
DMA stream configuration structure.
Structure representing a DMA driver.
uint8_t msg[10]
Buffer used for general comunication over SPI (out buffer)
unsigned int uint32_t
Typedef defining 32 bit unsigned int type.