46 #if (! STM32_DMA_ADVANCED) && STM32_DMA_USE_DOUBLE_BUFFER
47 #error "STM32_DMA_USE_DOUBLE_BUFFER only available on DMAv2"
50 #if (STM32_DMA_USE_ASYNC_TIMOUT) && STM32_DMA_USE_DOUBLE_BUFFER
51 #error "STM32_DMA_USE_DOUBLE_BUFFER only not yet compatible with STM32_DMA_USE_ASYNC_TIMOUT"
63 #if STM32_DMA_ADVANCED
65 return (dmap->
dmastream->stream->FCR & DMA_SxFCR_FS_Msk);
71 osalDbgCheck(dmap != NULL);
76 #if STM32_DMA_USE_WAIT == TRUE
79 #if STM32_DMA_USE_MUTUAL_EXCLUSION == TRUE
80 osalMutexObjectInit(&dmap->mutex);
82 #if defined( STM32_DMA_DRIVER_EXT_INIT_HOOK)
83 STM32_DMA_DRIVER_EXT_INIT_HOOK(dmap);
85 #if CH_DBG_SYSTEM_STATE_CHECK == TRUE
86 dmap->nbTransferError = dmap->nbDirectModeError = dmap->nbFifoError = 0U;
89 #if STM32_DMA_USE_ASYNC_TIMOUT
90 chVTObjectInit(&dmap->vt);
107 osalDbgCheck((dmap != NULL) && (cfg != NULL));
108 #if STM32_DMA_USE_DOUBLE_BUFFER
109 osalDbgAssert((cfg->
op_mode != DMA_CONTINUOUS_DOUBLE_BUFFER) || (!STM32_DMA_USE_ASYNC_TIMOUT),
110 "STM32_DMA_USE_ASYNC_TIMOUT not yet implemented in DMA_CONTINUOUS_DOUBLE_BUFFER mode");
112 osalDbgAssert((cfg->
op_mode != DMA_CONTINUOUS_DOUBLE_BUFFER) || (cfg->next_cb != NULL),
113 "DMA_CONTINUOUS_DOUBLE_BUFFER mode implies next_cb not NULL");
121 #if STM32_DMA_USE_DOUBLE_BUFFER
122 dmap->next_cb_errors = 0U;
140 osalDbgCheck((dmap != NULL) && (cfg != NULL));
141 #if STM32_DMA_USE_DOUBLE_BUFFER
142 osalDbgAssert((cfg->
op_mode != DMA_CONTINUOUS_DOUBLE_BUFFER) || (!STM32_DMA_USE_ASYNC_TIMOUT),
143 "STM32_DMA_USE_ASYNC_TIMOUT not yet implemented in DMA_CONTINUOUS_DOUBLE_BUFFER mode");
145 osalDbgAssert((cfg->
op_mode != DMA_CONTINUOUS_DOUBLE_BUFFER) || (cfg->next_cb != NULL),
146 "DMA_CONTINUOUS_DOUBLE_BUFFER mode implies next_cb not NULL");
152 #if STM32_DMA_USE_DOUBLE_BUFFER
153 dmap->next_cb_errors = 0U;
169 osalDbgCheck(dmap != NULL);
228 osalDbgCheckClassI();
230 #if STM32_DMA_USE_DOUBLE_BUFFER
232 osalDbgAssert(mem0p == NULL,
233 "in double buffer mode memory pointer is dynamically completed by next_cb callback");
234 mem0p = dmap->
config->next_cb(dmap, size);
238 #if (CH_DBG_ENABLE_ASSERTS != FALSE)
239 if (size != dmap->
size) {
240 osalDbgCheck((dmap != NULL) && (mem0p != NULL) && (periphp != NULL) &&
241 (size > 0U) && ((size == 1U) ||
243 (((size & 1U) == 0U)))));
253 osalDbgAssert((
uint32_t) periphp % cfg->
psize == 0,
"peripheral address not aligned");
258 osalDbgAssert((
uint32_t) mem0p % cfg->
msize == 0,
"memory address not aligned");
274 # if STM32_DMA_ADVANCED
276 osalDbgAssert((size % (cfg->mburst * cfg->
msize / cfg->
psize)) == 0,
277 "mburst alignment rule not respected");
278 osalDbgAssert((size % (cfg->mburst * cfg->
msize)) == 0,
279 "mburst alignment rule not respected");
280 osalDbgAssert((((
uint32_t) mem0p) % cfg->mburst) == 0,
281 "memory address alignment rule not respected");
284 osalDbgAssert((size % (cfg->pburst * cfg->
psize)) == 0,
285 "pburst alignment rule not respected");
286 osalDbgAssert((((
uint32_t) periphp) % cfg->pburst) == 0,
287 "peripheral address alignment rule not respected");
289 if (cfg->periph_inc_size_4) {
291 "periph_inc_size_4 implies enabling inc_peripheral_addr");
292 osalDbgAssert(cfg->fifo,
293 "periph_inc_size_4 implies enabling fifo");
301 #if STM32_DMA_USE_ASYNC_TIMOUT
302 dmap->currPtr = mem0p;
303 if (dmap->
config->timeout != TIME_INFINITE) {
304 chVTSetI(&dmap->vt, dmap->
config->timeout,
305 &dma_lld_serve_timeout_interrupt, (
void *) dmap);
327 #ifndef DMA_request_TypeDef
330 DMA_Stream_TypeDef *registers)
332 #if STM32_DMA_USE_DOUBLE_BUFFER
334 osalDbgAssert(mem0p == NULL,
335 "in double buffer mode memory pointer is dynamically completed by next_cb callback");
336 mem0p = dmap->
config->next_cb(dmap, size);
340 #if (CH_DBG_ENABLE_ASSERTS != FALSE)
341 osalDbgCheck((dmap != NULL) && (mem0p != NULL) && (periphp != NULL) &&
342 (size > 0U) && ((size == 1U) ||
344 (((size & 1U) == 0U)))));
349 "peripheral address not aligned");
352 "memory address not aligned");
354 # if STM32_DMA_ADVANCED
356 osalDbgAssert((size % (cfg->mburst * cfg->
msize / cfg->
psize)) == 0,
357 "mburst alignment rule not respected");
358 osalDbgAssert((size % (cfg->mburst * cfg->
msize)) == 0,
359 "mburst alignment rule not respected");
360 osalDbgAssert((((
uint32_t) mem0p) % cfg->mburst) == 0,
361 "memory address alignment rule not respected");
364 osalDbgAssert((size % (cfg->pburst * cfg->
psize)) == 0,
365 "pburst alignment rule not respected");
366 osalDbgAssert((((
uint32_t) periphp) % cfg->pburst) == 0,
367 "peripheral address alignment rule not respected");
369 if (cfg->periph_inc_size_4) {
371 "periph_inc_size_4 implies enabling inc_peripheral_addr");
372 osalDbgAssert(cfg->fifo,
373 "periph_inc_size_4 implies enabling fifo");
396 osalDbgCheck(dmap != NULL);
423 osalDbgCheckClassI();
424 osalDbgCheck(dmap != NULL);
440 for(
uint8_t i = 0; i < 16; i++) {
441 if (dmap->
dmastream == STM32_DMA_STREAM(i))
447 #if (STM32_DMA_USE_WAIT == TRUE) || defined(__DOXYGEN__)
478 osalDbgAssert(dmap->thread == NULL,
"already waiting");
481 msg = osalThreadSuspendTimeoutS(&dmap->thread,
timeout);
490 #if (STM32_DMA_USE_MUTUAL_EXCLUSION == TRUE) || defined(__DOXYGEN__)
505 osalDbgCheck(dmap != NULL);
507 osalMutexLock(&dmap->mutex);
522 osalDbgCheck(dmap != NULL);
524 osalMutexUnlock(&dmap->mutex);
557 osalDbgAssert(PORT_IRQ_IS_VALID_KERNEL_PRIORITY(cfg->
irq_priority),
558 "illegal IRQ priority");
559 switch (cfg->
psize) {
560 case 1 : psize_msk = STM32_DMA_CR_PSIZE_BYTE;
break;
561 case 2 : psize_msk = STM32_DMA_CR_PSIZE_HWORD;
break;
562 case 4 : psize_msk = STM32_DMA_CR_PSIZE_WORD;
break;
563 default: osalSysHalt(
"psize should be 1 or 2 or 4");
566 switch (cfg->
msize) {
567 case 1 : msize_msk = STM32_DMA_CR_MSIZE_BYTE;
break;
568 case 2 : msize_msk = STM32_DMA_CR_MSIZE_HWORD;
break;
569 case 4 : msize_msk = STM32_DMA_CR_MSIZE_WORD;
break;
570 default: osalDbgAssert(
false,
"msize should be 1 or 2 or 4");
576 case DMA_DIR_P2M: dir_msk = STM32_DMA_CR_DIR_P2M;
break;
577 case DMA_DIR_M2P: dir_msk = STM32_DMA_CR_DIR_M2P;
break;
578 case DMA_DIR_M2M: dir_msk = STM32_DMA_CR_DIR_M2M;
break;
579 default: osalDbgAssert(
false,
"direction not set or incorrect");
587 isr_flags |= STM32_DMA_CR_TCIE;
590 isr_flags |= STM32_DMA_CR_HTIE;
595 isr_flags |= STM32_DMA_CR_DMEIE | STM32_DMA_CR_TCIE;
598 #if CH_KERNEL_MAJOR < 6
603 #if STM32_DMA_SUPPORTS_DMAMUX == 0
604 #if STM32_DMA_ADVANCED
612 dir_msk | psize_msk | msize_msk | isr_flags |
614 #
if STM32_DMA_USE_DOUBLE_BUFFER
615 (cfg->
op_mode == DMA_CONTINUOUS_DOUBLE_BUFFER ? STM32_DMA_CR_DBM : 0UL) |
620 #if STM32_DMA_SUPPORTS_CSELR
621 | STM32_DMA_CR_CHSEL(cfg->request)
622 #elif STM32_DMA_ADVANCED
623 #if STM32_DMA_SUPPORTS_DMAMUX == 0
624 | STM32_DMA_CR_CHSEL(cfg->
channel)
626 | (cfg->periph_inc_size_4 ? STM32_DMA_CR_PINCOS : 0UL) |
627 (cfg->transfert_end_ctrl_by_periph? STM32_DMA_CR_PFCTRL : 0UL)
632 #if STM32_DMA_ADVANCED
633 uint32_t pburst_msk, mburst_msk, fifo_msk;
634 switch (cfg->pburst) {
635 case 0 : pburst_msk = 0UL;
break;
636 case 4 : pburst_msk = STM32_DMA_CR_PBURST_INCR4;
break;
637 case 8 : pburst_msk = STM32_DMA_CR_PBURST_INCR8;
break;
638 case 16 : pburst_msk = STM32_DMA_CR_PBURST_INCR16;
break;
639 default: osalDbgAssert(
false,
"pburst size should be 0 or 4 or 8 or 16");
642 switch (cfg->mburst) {
643 case 0 : mburst_msk = 0UL;
break;
644 case 4 : mburst_msk = STM32_DMA_CR_MBURST_INCR4;
break;
645 case 8 : mburst_msk = STM32_DMA_CR_MBURST_INCR8;
break;
646 case 16 : mburst_msk = STM32_DMA_CR_MBURST_INCR16;
break;
647 default: osalDbgAssert(
false,
"mburst size should be 0 or 4 or 8 or 16");
651 case 0 : fifo_msk = 0UL;
break;
652 case 1 : fifo_msk = STM32_DMA_FCR_FTH_1Q;
break;
653 case 2 : fifo_msk = STM32_DMA_FCR_FTH_HALF;
break;
654 case 3 : fifo_msk = STM32_DMA_FCR_FTH_3Q;
break;
655 case 4 : fifo_msk = STM32_DMA_FCR_FTH_FULL;
break;
656 default: osalDbgAssert(
false,
"fifo threshold should be 1(/4) or 2(/4) or 3(/4) or 4(/4)");
661 # if (CH_DBG_ENABLE_ASSERTS != FALSE)
662 # if STM32_DMA_USE_ASYNC_TIMOUT
663 osalDbgAssert(dmap->
config->timeout != 0,
664 "timeout cannot be 0 if STM32_DMA_USE_ASYNC_TIMOUT is enabled");
665 osalDbgAssert(!((dmap->
config->timeout != TIME_INFINITE) && (dmap->
config->fifo != 0)),
666 "timeout should be dynamically disabled (dmap->config->timeout = TIME_INFINITE) "
667 "if STM32_DMA_USE_ASYNC_TIMOUT is enabled and fifo is enabled (fifo != 0)");
673 if (!cfg->mburst != !cfg->pburst) {
674 osalDbgAssert(
false,
"pburst and mburst should be enabled or disabled together");
679 if (cfg->fifo && cfg->mburst) {
680 const size_t fifo_level = cfg->fifo * 4U;
681 osalDbgAssert(fifo_level % (cfg->mburst * cfg->
msize) == 0,
"threshold combination forbidden");
770 dmap->
dmamode |= (pburst_msk | mburst_msk);
772 # if (CH_DBG_ENABLE_ASSERTS != FALSE)
781 if ( ((cfg->pburst * cfg->
psize) == STM32_DMA_FIFO_SIZE) && (cfg->fifo == 3)) {
782 goto forbiddenCombination;
789 #if STM32_DMA_SUPPORTS_DMAMUX == 0
791 osalDbgAssert(dmap->
controller == 2,
"M2M not available on DMA1");
798 #if STM32_DMA_ADVANCED
800 dmap->fifomode = STM32_DMA_FCR_DMDIS | STM32_DMA_FCR_FEIE | fifo_msk;
803 "msize == psize is mandatory when fifo is disabled");
808 if (allocate_stream ==
true) {
809 #if CH_KERNEL_MAJOR < 6
810 const bool error = dmaStreamAllocate( dmap->
dmastream,
815 dmap->dmastream = dmaStreamAllocI(dmap->config->stream,
819 const bool error = dmap->dmastream == NULL;
822 osalDbgAssert(
false,
"stream already allocated");
828 #if (CH_DBG_ENABLE_ASSERTS != FALSE)
829 #if STM32_DMA_ADVANCED
830 forbiddenCombination:
831 chSysHalt(
"forbidden combination of msize, mburst, fifo, see FIFO threshold "
832 "configuration in reference manuel");
846 #if defined CACHE_LINE_SIZE && CACHE_LINE_SIZE != 0
848 dsize % CACHE_LINE_SIZE );
849 return endp < CACHE_LINE_SIZE ? dsize + CACHE_LINE_SIZE :
850 dsize + CACHE_LINE_SIZE *2U;
864 #ifndef DMA_request_TypeDef
866 void *mem0p,
const size_t size,
867 DMA_Stream_TypeDef *registers)
869 dmaStreamSetPeripheral(dmap->
dmastream, periphp);
870 #if STM32_DMA_SUPPORTS_DMAMUX
874 dmaStreamSetMemory0(dmap->
dmastream, mem0p);
875 #if STM32_DMA_USE_DOUBLE_BUFFER
877 dmaStreamSetMemory1(dmap->
dmastream, dmap->
config->next_cb(dmap, size));
880 dmaStreamSetTransactionSize(dmap->
dmastream, size);
882 #if STM32_DMA_ADVANCED
883 dmaStreamSetFIFO(dmap->
dmastream, dmap->fifomode);
886 memcpy(registers, dmap->
dmastream->stream,
sizeof(DMA_Stream_TypeDef));
887 registers->CR |= STM32_DMA_CR_EN;
900 if (dmap->
config->activate_dcache_sync &&
904 cacheBufferFlush(mem0p, cacheSize);
909 dmap->periphp = periphp;
912 dmaStreamSetPeripheral(dmap->
dmastream, periphp);
913 #if STM32_DMA_SUPPORTS_DMAMUX
917 dmaStreamSetMemory0(dmap->
dmastream, mem0p);
918 #if STM32_DMA_USE_DOUBLE_BUFFER
920 dmaStreamSetMemory1(dmap->
dmastream, dmap->
config->next_cb(dmap, size));
923 dmaStreamSetTransactionSize(dmap->
dmastream, size);
925 #if STM32_DMA_ADVANCED
926 dmaStreamSetFIFO(dmap->
dmastream, dmap->fifomode);
954 #if CH_KERNEL_MAJOR < 6
976 #if CH_DBG_SYSTEM_STATE_CHECK && STM32_DMA_ADVANCED
977 const uint32_t feif_msk = dmap->
config->fifo != 0U ? STM32_DMA_ISR_FEIF : 0U;
982 if ((flags & (STM32_DMA_ISR_TEIF | STM32_DMA_ISR_DMEIF | feif_msk)) != 0U) {
989 if (dmap->
config->fifo != 0U) {
990 #if STM32_DMA_ADVANCED
1005 #if __DCACHE_PRESENT
1006 if (dmap->
config->activate_dcache_sync)
1010 const size_t cacheSize =
1013 cacheBufferInvalidate(dmap->
mem0p, cacheSize);
1017 case DMA_DIR_M2M :
if (dmap->periphp >= (
void *) 0x20000000) {
1018 const size_t cacheSize =
1021 cacheBufferInvalidate(dmap->periphp, cacheSize);
1027 if ((flags & STM32_DMA_ISR_TCIF) != 0) {
1030 }
else if ((flags & STM32_DMA_ISR_HTIF) != 0) {
1038 #if STM32_DMA_USE_ASYNC_TIMOUT
1044 void dma_lld_serve_timeout_interrupt(
void *arg)
1049 chVTSetI(&dmap->vt, dmap->
config->timeout,
1050 &dma_lld_serve_timeout_interrupt, (
void *) dmap);
1051 chSysUnlockFromISR();
1053 async_timout_enabled_call_end_cb(dmap, FROM_TIMOUT_CODE);
1057 #if STM32_DMA_USE_DOUBLE_BUFFER
1074 if (dmaStreamGetCurrentTarget(dmap->
dmastream)) {
1075 lastBuffer = (
void *) dmap->
dmastream->stream->M0AR;
1078 lastBuffer = (
void *) dmap->
dmastream->stream->M1AR;
void dmaObjectInit(DMADriver *dmap)
bool dmaStartTransfert(DMADriver *dmap, volatile void *periphp, void *mem0p, const size_t size)
Starts a DMA transaction.
bool dma_lld_start(DMADriver *dmap, bool allocate_stream)
Configures and activates the DMA peripheral.
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.
bool dmaStartTransfertI(DMADriver *dmap, volatile void *periphp, void *mem0p, const size_t size)
Starts a DMA transaction.
void dma_lld_stop(DMADriver *dmap)
Deactivates the DMA peripheral.
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.
static size_t getCrossCacheBoundaryAwareSize(const void *memp, const size_t dsize)
void dmaStopTransfert(DMADriver *dmap)
Stops an ongoing transaction.
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.
bool dmaReloadConf(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.
uint8_t dmaGetStreamIndex(DMADriver *dmap)
STM32 DMA subsystem driver header.
uint8_t msize
DMA memory data granurality in bytes (1,2,4)
@ DMA_CONTINUOUS_HALF_BUFFER
Continuous mode to/from the same buffer.
@ DMA_ONESHOT
One transert then stop
@ 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.
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
void * dma_lld_set_next_double_buffer(DMADriver *dmap, void *nextBuffer)
dmaopmode_t op_mode
one shot, or circular half buffer, or circular double buffers
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.
unsigned char uint8_t
Typedef defining 8 bit unsigned char type.