Paparazzi UAS  v6.0_unstable-53-gfe8bbd3-dirty
Paparazzi is a free software Unmanned Aircraft System.
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Modules Pages
hal_stm32_dma.c
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 #include "hal_stm32_dma.h"
30 
31 /*
32 TODO :
33 
34 ° split lld and hardware independant code : hal_stm32_dma et hal_lld_stm32_dma
35 
36 ° port to H7,L4+ : bdma, dmav3, mdma+dmamux
37 
38 ° allow fifo burst when STM32_DMA_USE_ASYNC_TIMOUT is true by forcing a flush of the fifo : could be
39  done disabling stream : should flush fifo and trig full code ISR. full code ISR should re-enable stream
40  after a timout.
41 
42 */
43 
44 
51 static void dma_lld_serve_interrupt(DMADriver *dmap, uint32_t flags);
52 static inline uint32_t getFCR_FS(const DMADriver *dmap) {
53  return (dmap->dmastream->stream->FCR & DMA_SxFCR_FS_Msk);
54 }
55 
57 {
58  osalDbgCheck(dmap != NULL);
59 
60  dmap->state = DMA_STOP;
61  dmap->config = NULL;
62  dmap->mem0p = NULL;
63 #if STM32_DMA_USE_WAIT == TRUE
64  dmap->thread = NULL;
65 #endif
66 #if STM32_DMA_USE_MUTUAL_EXCLUSION == TRUE
67  osalMutexObjectInit(&dmap->mutex);
68 #endif
69 #if defined( STM32_DMA_DRIVER_EXT_INIT_HOOK)
70  STM32_DMA_DRIVER_EXT_INIT_HOOK(dmap);
71 #endif
72 #if CH_DBG_SYSTEM_STATE_CHECK == TRUE
73  dmap->nbTransferError = dmap->nbDirectModeError = dmap->nbFifoError = 0U;
74  dmap->lastError = 0U;
75 #endif
76 #if STM32_DMA_USE_ASYNC_TIMOUT
77  chVTObjectInit(&dmap->vt);
78 #endif
79 }
80 
81 
92 bool dmaStart(DMADriver *dmap, const DMAConfig *cfg)
93 {
94  osalDbgCheck((dmap != NULL) && (cfg != NULL));
95 
96  osalSysLock();
97  osalDbgAssert((dmap->state == DMA_STOP) || (dmap->state == DMA_READY),
98  "invalid state");
99  dmap->config = cfg;
100  const bool statusOk = dma_lld_start(dmap);
101  dmap->state = DMA_READY;
102  osalSysUnlock();
103  return statusOk;
104 }
105 
106 
114 void dmaStop(DMADriver *dmap)
115 {
116  osalDbgCheck(dmap != NULL);
117 
118  osalSysLock();
119 
120  osalDbgAssert((dmap->state == DMA_STOP) || (dmap->state == DMA_READY),
121  "invalid state");
122 
123  dma_lld_stop(dmap);
124  dmap->config = NULL;
125  dmap->state = DMA_STOP;
126  dmap->mem0p = NULL;
127 
128  osalSysUnlock();
129 }
130 
131 
149 bool dmaStartTransfert(DMADriver *dmap, volatile void *periphp, void * mem0p, const size_t size)
150 {
151  osalSysLock();
152  const bool statusOk = dmaStartTransfertI(dmap, periphp, mem0p, size);
153  osalSysUnlock();
154  return statusOk;
155 }
156 
174 bool dmaStartTransfertI(DMADriver *dmap, volatile void *periphp, void * mem0p, const size_t size)
175 {
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)));
181 
182  const DMAConfig *cfg = dmap->config;
183  osalDbgAssert((dmap->state == DMA_READY) ||
184  (dmap->state == DMA_COMPLETE) ||
185  (dmap->state == DMA_ERROR),
186  "not ready");
187  /* if (cfg->pburst) */
188  /* osalDbgAssert((uint32_t) periphp % (cfg->pburst * cfg->psize) == 0, "peripheral address not aligned"); */
189  /* else */
190  osalDbgAssert((uint32_t) periphp % cfg->psize == 0, "peripheral address not aligned");
191 
192  /* if (cfg->mburst) */
193  /* osalDbgAssert((uint32_t) mem0p % (cfg->mburst * cfg->msize) == 0, "memory address not aligned"); */
194  /* else */
195  osalDbgAssert((uint32_t) mem0p % cfg->msize == 0, "memory address not aligned");
196 
197  /*
198  In the circular mode, it is mandatory to respect the following rule in case of a burst mode
199  configured for memory:
200  DMA_SxNDTR = Multiple of ((Mburst beat) × (Msize)/(Psize)), where:
201  – (Mburst beat) = 4, 8 or 16 (depending on the MBURST bits in the DMA_SxCR
202  register)
203  – ((Msize)/(Psize)) = 1, 2, 4, 1/2 or 1/4 (Msize and Psize represent the MSIZE and
204  PSIZE bits in the DMA_SxCR register. They are byte dependent)
205  – DMA_SxNDTR = Number of data items to transfer on the AHB peripheral port
206 
207  NDTR must also be a multiple of the Peripheral burst size multiplied by the peripheral data
208  size, otherwise this could result in a bad DMA behavior.
209 
210  */
211 # if STM32_DMA_ADVANCED
212  if (cfg->mburst) {
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");
219  }
220  if (cfg->pburst) {
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");
225  }
226 
227 
228 
229 # endif // STM32_DMA_ADVANCED
230  }
231 
232 #endif // CH_DBG_ENABLE_ASSERTS != FALSE
233  dmap->state = DMA_ACTIVE;
234 
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);
240  }
241 #endif
242 
243  return dma_lld_start_transfert(dmap, periphp, mem0p, size);
244 }
245 
246 
258 {
259 
260  osalDbgCheck(dmap != NULL);
261 
262  osalSysLock();
263  osalDbgAssert((dmap->state == DMA_READY) || (dmap->state == DMA_ACTIVE),
264  "invalid state");
265  if (dmap->state != DMA_READY) {
267  dmap->state = DMA_READY;
268  _dma_reset_s(dmap);
269  }
270  osalSysUnlock();
271 }
272 
273 
274 
286 {
287  osalDbgCheckClassI();
288  osalDbgCheck(dmap != NULL);
289  osalDbgAssert((dmap->state == DMA_READY) ||
290  (dmap->state == DMA_ACTIVE) ||
291  (dmap->state == DMA_COMPLETE),
292  "invalid state");
293 
294 
295  if (dmap->state != DMA_READY) {
297  dmap->state = DMA_READY;
298  _dma_reset_i(dmap);
299  }
300 
301 }
302 
303 #if (STM32_DMA_USE_WAIT == TRUE) || defined(__DOXYGEN__)
304 
328 msg_t dmaTransfertTimeout(DMADriver *dmap, volatile void *periphp, void *mem0p, const size_t size,
329  sysinterval_t timeout)
330 {
331  msg_t msg;
332 
333  osalSysLock();
334  osalDbgAssert(dmap->thread == NULL, "already waiting");
335  osalDbgAssert(dmap->config->circular == false, "blocking API is incompatible with circular mode");
336  dmaStartTransfertI(dmap, periphp, mem0p, size);
337  msg = osalThreadSuspendTimeoutS(&dmap->thread, timeout);
338  if (msg != MSG_OK) {
339  dmaStopTransfertI(dmap);
340  }
341  osalSysUnlock();
342  return msg;
343 }
344 #endif
345 
346 #if (STM32_DMA_USE_MUTUAL_EXCLUSION == TRUE) || defined(__DOXYGEN__)
347 
359 {
360 
361  osalDbgCheck(dmap != NULL);
362 
363  osalMutexLock(&dmap->mutex);
364 }
365 
376 {
377 
378  osalDbgCheck(dmap != NULL);
379 
380  osalMutexUnlock(&dmap->mutex);
381 }
382 #endif /* DMA_USE_MUTUAL_EXCLUSION == TRUE */
383 
384 
385 
386 /*
387 # _ _ _
388 # | | | | | |
389 # | | ___ __ __ | | ___ __ __ ___ | |
390 # | | / _ \ \ \ /\ / / | | / _ \ \ \ / / / _ \ | |
391 # | |____ | (_) | \ V V / | |____ | __/ \ V / | __/ | |
392 # |______| \___/ \_/\_/ |______| \___| \_/ \___| |_|
393 # _____ _
394 # | __ \ (_)
395 # | | | | _ __ _ __ __ ___ _ __
396 # | | | | | '__| | | \ \ / / / _ \ | '__|
397 # | |__| | | | | | \ V / | __/ | |
398 # |_____/ |_| |_| \_/ \___| |_|
399 */
400 
401 
410 {
411  uint32_t psize_msk, msize_msk;
412 
413  const DMAConfig *cfg = dmap->config;
414 
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");
420  return false;
421  }
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");
427  return false;
428  }
429 
430  uint32_t dir_msk = 0UL;
431  switch (cfg->direction) {
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");
436  }
437 
438  uint32_t isr_flags = cfg->circular ? 0UL : STM32_DMA_CR_TCIE;
439 
440  if (cfg->direction != DMA_DIR_M2M) {
441  if (cfg->end_cb) {
442  isr_flags |= STM32_DMA_CR_TCIE;
443  if (cfg->circular) {
444  isr_flags |= STM32_DMA_CR_HTIE;
445  }
446  }
447  }
448 
449  if (cfg->error_cb) {
450  isr_flags |= STM32_DMA_CR_DMEIE | STM32_DMA_CR_TCIE;
451  }
452 
453 #if CH_KERNEL_MAJOR < 6
454  dmap->dmastream = STM32_DMA_STREAM(cfg->stream);
455 #endif
456 
457  // portable way (V1, V2) to retreive controler number
458 #if STM32_DMA_ADVANCED
459  dmap->controller = 1 + (cfg->stream / STM32_DMA_STREAM_ID(2, 0));
460 #else
461  dmap->controller = 1 + (cfg->stream / STM32_DMA_STREAM_ID(2, 1));
462 #endif
463 
464  dmap->dmamode = STM32_DMA_CR_PL(cfg->dma_priority) |
465  dir_msk | psize_msk | msize_msk | isr_flags |
466  (cfg->circular ? STM32_DMA_CR_CIRC : 0UL) |
467  (cfg->inc_peripheral_addr ? STM32_DMA_CR_PINC : 0UL) |
468  (cfg->inc_memory_addr ? STM32_DMA_CR_MINC : 0UL)
469 
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)
476 # endif
477  ;
478 
479 
480 #if STM32_DMA_ADVANCED
481  uint32_t pburst_msk, mburst_msk, fifo_msk; // STM32_DMA_CR_PBURST_INCRx, STM32_DMA_CR_MBURST_INCRx
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");
488  return false;
489  }
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");
496  return false;
497  }
498  switch (cfg->fifo) {
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)");
505  return false;
506  }
507 
508 
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)");
516 
517 # endif
518 
519 
520  // lot of combination of parameters are forbiden, and some conditions must be meet
521  if (!cfg->msize != !cfg->psize) {
522  osalDbgAssert(false, "psize and msize should be enabled or disabled together");
523  return false;
524  }
525 
526  if (cfg->fifo) {
527  switch (cfg->msize) {
528  case 1: // msize 1
529  switch (cfg->mburst) {
530  case 4 : // msize 1 mburst 4
531  switch (cfg->fifo) {
532  case 1: break; // msize 1 mburst 4 fifo 1/4
533  case 2: break; // msize 1 mburst 4 fifo 2/4
534  case 3: break; // msize 1 mburst 4 fifo 3/4
535  case 4: break; // msize 1 mburst 4 fifo 4/4
536  }
537  break;
538  case 8 : // msize 1 mburst 8
539  switch (cfg->fifo) {
540  case 1: goto forbiddenCombination; // msize 1 mburst 8 fifo 1/4
541  case 2: break; // msize 1 mburst 8 fifo 2/4
542  case 3: goto forbiddenCombination; // msize 1 mburst 8 fifo 3/4
543  case 4: break; // msize 1 mburst 8 fifo 4/4
544  }
545  break;
546  case 16 : // msize 1 mburst 16
547  switch (cfg->fifo) {
548  case 1: goto forbiddenCombination; // msize 1 mburst 16 fifo 1/4
549  case 2: goto forbiddenCombination; // msize 1 mburst 16 fifo 2/4
550  case 3: goto forbiddenCombination; // msize 1 mburst 16 fifo 3/4
551  case 4: break; // msize 1 mburst 16 fifo 4/4
552  }
553  break;
554  }
555  break;
556  case 2: // msize 2
557  switch (cfg->mburst) {
558  case 4 : // msize 2 mburst 4
559  switch (cfg->fifo) {
560  case 1: goto forbiddenCombination; // msize 2 mburst 4 fifo 1/4
561  case 2: break; // msize 2 mburst 4 fifo 2/4
562  case 3: goto forbiddenCombination; // msize 2 mburst 4 fifo 3/4
563  case 4: break; // msize 2 mburst 4 fifo 4/4
564  }
565  break;
566  case 8 :
567  switch (cfg->fifo) {
568  case 1: goto forbiddenCombination; // msize 2 mburst 8 fifo 1/4
569  case 2: goto forbiddenCombination; // msize 2 mburst 8 fifo 2/4
570  case 3: goto forbiddenCombination; // msize 2 mburst 8 fifo 3/4
571  case 4: break; // msize 2 mburst 8 fifo 4/4
572  }
573  break;
574  case 16 :
575  switch (cfg->fifo) {
576  case 1: goto forbiddenCombination; // msize 2 mburst 16 fifo 1/4
577  case 2: goto forbiddenCombination; // msize 2 mburst 16 fifo 2/4
578  case 3: goto forbiddenCombination; // msize 2 mburst 16 fifo 3/4
579  case 4: goto forbiddenCombination; // msize 2 mburst 16 fifo 4/4
580  }
581  }
582  break;
583  case 4:
584  switch (cfg->mburst) {
585  case 4 :
586  switch (cfg->fifo) {
587  case 1: goto forbiddenCombination; // msize 4 mburst 4 fifo 1/4
588  case 2: goto forbiddenCombination; // msize 4 mburst 4 fifo 2/4
589  case 3: goto forbiddenCombination; // msize 4 mburst 4 fifo 3/4
590  case 4: break; // msize 4 mburst 4 fifo 4/4
591  }
592  break;
593  case 8 :
594  switch (cfg->fifo) {
595  case 1: goto forbiddenCombination; // msize 4 mburst 8 fifo 1/4
596  case 2: goto forbiddenCombination; // msize 4 mburst 8 fifo 2/4
597  case 3: goto forbiddenCombination; // msize 4 mburst 8 fifo 3/4
598  case 4: goto forbiddenCombination; // msize 4 mburst 8 fifo 4/4
599  }
600  break;
601  case 16 :
602  switch (cfg->fifo) {
603  case 1: goto forbiddenCombination; // msize 4 mburst 16 fifo 1/4
604  case 2: goto forbiddenCombination; // msize 4 mburst 16 fifo 2/4
605  case 3: goto forbiddenCombination; // msize 4 mburst 16 fifo 3/4
606  case 4: goto forbiddenCombination; // msize 4 mburst 16 fifo 4/4
607  }
608  }
609  }
610  }
611 # endif
612 
613  dmap->dmamode |= (pburst_msk | mburst_msk);
614 
615 # if (CH_DBG_ENABLE_ASSERTS != FALSE)
616 
617 
618  /*
619  When burst transfers are requested on the peripheral AHB port and the FIFO is used
620  (DMDIS = 1 in the DMA_SxCR register), it is mandatory to respect the following rule to
621  avoid permanent underrun or overrun conditions, depending on the DMA stream direction:
622  If (PBURST × PSIZE) = FIFO_SIZE (4 words), FIFO_Threshold = 3/4 is forbidden
623  */
624 
625  if (((cfg->pburst * cfg->psize) == STM32_DMA_FIFO_SIZE) && (cfg->fifo == 3)) {
626  goto forbiddenCombination;
627  }
628 
629  /*
630  When memory-to-memory mode is used, the Circular and direct modes are not allowed.
631  Only the DMA2 controller is able to perform memory-to-memory transfers.
632  */
633 
634  if (cfg->direction == DMA_DIR_M2M) {
635  osalDbgAssert(dmap->controller == 2, "M2M not available on DMA1");
636  osalDbgAssert(cfg->circular == false, "M2M not available in circular mode");
637  }
638 
639 
640 # endif
641 #endif
642 
643 #if STM32_DMA_ADVANCED
644  if (cfg->fifo) {
645  dmap->fifomode = STM32_DMA_FCR_DMDIS | STM32_DMA_FCR_FEIE | fifo_msk;
646  } else {
647  osalDbgAssert(cfg->direction != DMA_DIR_M2M, "fifo mode mandatory for M2M");
648  osalDbgAssert(cfg->psize == cfg->msize,
649  "msize == psize is mandatory when fifo is disabled");
650  dmap->fifomode = 0U;
651  }
652 #endif
653 
654 #if CH_KERNEL_MAJOR < 6
655  const bool error = dmaStreamAllocate( dmap->dmastream,
656  cfg->irq_priority,
657  (stm32_dmaisr_t) &dma_lld_serve_interrupt,
658  (void *) dmap );
659 #else
660  dmap->dmastream = dmaStreamAllocI(dmap->config->stream,
661  cfg->irq_priority,
662  (stm32_dmaisr_t) &dma_lld_serve_interrupt,
663  (void *) dmap );
664  bool error = dmap->dmastream == NULL;
665 #endif
666  if (error) {
667  osalDbgAssert(false, "stream already allocated");
668  return false;
669  }
670 
671  return true;
672 
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");
678  return false;
679 # endif
680 #endif
681 }
682 
683 
691 bool dma_lld_start_transfert(DMADriver *dmap, volatile void *periphp, void *mem0p, const size_t size)
692 {
693 #if __DCACHE_PRESENT
694  if (dmap->config->dcache_memory_in_use &&
695  (dmap->config->direction != DMA_DIR_P2M)) {
696  cacheBufferFlush(mem0p, size * dmap->config->msize);
697  }
698 #endif
699  dmap->mem0p = mem0p;
700 #if __DCACHE_PRESENT
701  dmap->periphp = periphp;
702 #endif
703  dmap->size = size;
704  dmaStreamSetPeripheral(dmap->dmastream, periphp);
705  dmaStreamSetMemory0(dmap->dmastream, mem0p);
706  dmaStreamSetTransactionSize(dmap->dmastream, size);
707  dmaStreamSetMode(dmap->dmastream, dmap->dmamode);
708 #if STM32_DMA_ADVANCED
709  dmaStreamSetFIFO(dmap->dmastream, dmap->fifomode);
710 #endif
711  dmaStreamEnable(dmap->dmastream);
712 
713  return true;
714 }
715 
724 {
725  dmaStreamDisable(dmap->dmastream);
726 }
727 
736 {
737 #if CH_KERNEL_MAJOR < 6
738  dmaStreamRelease(dmap->dmastream);
739 #else
740  dmaStreamFree(dmap->dmastream);
741 #endif
742 }
743 
744 
745 /*===========================================================================*/
746 /* Driver local functions. */
747 /*===========================================================================*/
748 
755 static void dma_lld_serve_interrupt(DMADriver *dmap, uint32_t flags)
756 {
757 
758  /* DMA errors handling.*/
759 #if CH_DBG_SYSTEM_STATE_CHECK
760  const uint32_t feif_msk = dmap->config->fifo != 0U ? STM32_DMA_ISR_FEIF : 0U;
761 #else
762  static const uint32_t feif_msk = 0U;
763 #endif
764  //const uint32_t feif_msk = STM32_DMA_ISR_FEIF;
765  if ((flags & (STM32_DMA_ISR_TEIF | STM32_DMA_ISR_DMEIF | feif_msk)) != 0U) {
766  /* DMA, this could help only if the DMA tries to access an unmapped
767  address space or violates alignment rules.*/
768  const dmaerrormask_t err =
769  ( (flags & STM32_DMA_ISR_TEIF) ? DMA_ERR_TRANSFER_ERROR : 0UL) |
770  ( (flags & STM32_DMA_ISR_DMEIF) ? DMA_ERR_DIRECTMODE_ERROR : 0UL) |
771  ( (flags & feif_msk) ? DMA_ERR_FIFO_ERROR : 0UL) |
772  ( getFCR_FS(dmap) == (0b100 << DMA_SxFCR_FS_Pos) ? DMA_ERR_FIFO_EMPTY: 0UL) |
773  ( getFCR_FS(dmap) == (0b101 << DMA_SxFCR_FS_Pos) ? DMA_ERR_FIFO_FULL: 0UL);
774 
775  _dma_isr_error_code(dmap, err);
776  } else {
777  /* It is possible that the transaction has already be reset by the
778  DMA error handler, in this case this interrupt is spurious.*/
779  if (dmap->state == DMA_ACTIVE) {
780 #if __DCACHE_PRESENT
781  if (dmap->config->dcache_memory_in_use)
782  switch (dmap->config->direction) {
783  case DMA_DIR_M2P : break;
784  case DMA_DIR_P2M :
785  cacheBufferInvalidate(dmap->mem0p,
786  dmap->size * dmap->config->msize);
787  break;
788  case DMA_DIR_M2M :
789  cacheBufferInvalidate(dmap->periphp,
790  dmap->size * dmap->config->msize);
791  break;
792  }
793 #endif
794 
795  if ((flags & STM32_DMA_ISR_TCIF) != 0) {
796  /* Transfer complete processing.*/
797  _dma_isr_full_code(dmap);
798  } else if ((flags & STM32_DMA_ISR_HTIF) != 0) {
799  /* Half transfer processing.*/
800  _dma_isr_half_code(dmap);
801  }
802  }
803  }
804 }
805 
806 #if STM32_DMA_USE_ASYNC_TIMOUT
807 
812 void dma_lld_serve_timeout_interrupt(void *arg)
813 {
814  DMADriver *dmap = (DMADriver *) arg;
815  if (dmap->config->circular) {
816  chSysLockFromISR();
817  chVTSetI(&dmap->vt, dmap->config->timeout,
818  &dma_lld_serve_timeout_interrupt, (void *) dmap);
819  chSysUnlockFromISR();
820  }
821  async_timout_enabled_call_end_cb(dmap, FROM_TIMOUT_CODE);
822 }
823 #endif
Ready.
Definition: hal_stm32_dma.h:65
static float timeout
static void dma_lld_serve_interrupt(DMADriver *dmap, uint32_t flags)
DMA ISR service routine.
msg_t dmaTransfertTimeout(DMADriver *dmap, volatile void *periphp, void *mem0p, const size_t size, sysinterval_t timeout)
Performs a DMA transaction.
void dmaStop(DMADriver *dmap)
Deactivates the DMA peripheral.
STM32 DMA subsystem driver header.
void dmaStopTransfertI(DMADriver *dmap)
Stops an ongoing transaction.
static void _dma_isr_full_code(DMADriver *dmap)
Common ISR code, full buffer event.
bool inc_peripheral_addr
Enable increment of peripheral address after each transfert.
bool dmaStart(DMADriver *dmap, const DMAConfig *cfg)
Configures and activates the DMA peripheral.
Definition: hal_stm32_dma.c:92
void dmaReleaseBus(DMADriver *dmap)
Releases exclusive access to the DMA peripheral.
dmaerrormask_t
Possible DMA failure causes.
Definition: hal_stm32_dma.h:76
Transfert error.
Definition: hal_stm32_dma.h:68
DMA FIFO error.
Definition: hal_stm32_dma.h:79
uint32_t dmamode
hold DMA CR register for the stream
uint32_t stream
stream associated with transaction
bool inc_memory_addr
Enable increment of memory address after each transfert.
Transfert complete.
Definition: hal_stm32_dma.h:67
dmaerrorcallback_t error_cb
Error callback or NULL.
bool dma_lld_start(DMADriver *dmap)
Configures and activates the DMA peripheral.
dmadirection_t direction
DMA transaction direction.
DMA transfer failure.
Definition: hal_stm32_dma.h:77
dmacallback_t end_cb
Callback function associated to the stream or NULL.
void dma_lld_stop(DMADriver *dmap)
Deactivates the DMA peripheral.
DMA FIFO overrun.
Definition: hal_stm32_dma.h:80
MEMORY to MEMORY.
Definition: hal_stm32_dma.h:90
uint8_t psize
DMA peripheral data granurality in bytes (1,2,4)
PERIPHERAL to MEMORY.
Definition: hal_stm32_dma.h:88
bool circular
Enables the circular buffer mode for the stream.
DMA stream configuration structure.
static void _dma_isr_half_code(DMADriver *dmap)
Common ISR code, half buffer event.
uint8_t dma_priority
DMA priority (1 .
DMA FIFO underrun.
Definition: hal_stm32_dma.h:81
DMA Direct Mode failure.
Definition: hal_stm32_dma.h:78
Stopped.
Definition: hal_stm32_dma.h:64
static uint32_t getFCR_FS(const DMADriver *dmap)
Definition: hal_stm32_dma.c:52
#define STM32_DMA_SUPPORTS_CSELR
Definition: hal_stm32_dma.h:55
void dmaStopTransfert(DMADriver *dmap)
Stops an ongoing transaction.
MEMORY to PERIPHERAL.
Definition: hal_stm32_dma.h:89
size_t size
hold size of current transaction
void dmaAcquireBus(DMADriver *dmap)
Gains exclusive access to the DMA peripheral.
bool dmaStartTransfert(DMADriver *dmap, volatile void *periphp, void *mem0p, const size_t size)
Starts a DMA transaction.
const stm32_dma_stream_t * dmastream
DMA stream associated with peripheral or memory.
void dma_lld_stop_transfert(DMADriver *dmap)
Stops an ongoing transaction.
uint8_t irq_priority
DMA IRQ priority (2 .
void dmaObjectInit(DMADriver *dmap)
Definition: hal_stm32_dma.c:56
#define _dma_reset_i(dmap)
Resumes a thread waiting for a dma transfert completion.
Transfering.
Definition: hal_stm32_dma.h:66
volatile dmastate_t state
Driver state.
uint8_t msize
DMA memory data granurality in bytes (1,2,4)
uint8_t controller
controller associated with stream
bool dmaStartTransfertI(DMADriver *dmap, volatile void *periphp, void *mem0p, const size_t size)
Starts a DMA transaction.
uint8_t msg[10]
Buffer used for general comunication over SPI (out buffer)
bool dma_lld_start_transfert(DMADriver *dmap, volatile void *periphp, void *mem0p, const size_t size)
Starts a DMA transaction.
static void _dma_isr_error_code(DMADriver *dmap, dmaerrormask_t err)
Common ISR code, error event.
#define _dma_reset_s(dmap)
Resumes a thread waiting for a dma transfert completion.
void * mem0p
memory address
const DMAConfig * config
Current configuration data.
Structure representing a DMA driver.
unsigned int uint32_t
Typedef defining 32 bit unsigned int type.
Definition: vl53l1_types.h:78