mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2025-01-17 04:52:59 +01:00
cpu/stm32_common: adapt DMA driver for f0/1/3/l0/1/4
This commit is contained in:
parent
a9a30c0c0f
commit
021697ae94
@ -241,7 +241,29 @@ typedef enum {
|
||||
* @brief DMA configuration
|
||||
*/
|
||||
typedef struct {
|
||||
int stream; /**< DMA stream */
|
||||
/** DMA stream on stm32f2/4/7, channel on others
|
||||
* STM32F2/4/7:
|
||||
* - 0: DMA1 / Stream0
|
||||
* - 1: DMA1 / Stream1
|
||||
* - ...
|
||||
* - 7: DMA1 / Stream7
|
||||
* - 8: DAM2 / Stream0
|
||||
* - ...
|
||||
* - 15: DMA2 / Stream7
|
||||
* STM32F0/1/L0/1/4:
|
||||
* - 0: DMA1 / Channel1
|
||||
* - ...
|
||||
* - 4: DMA1 / Channel5
|
||||
* - ...
|
||||
* - 6: DMA1 / Channel7
|
||||
* - 7: Reserved
|
||||
* - 8: DMA2 / Channel1
|
||||
* - ...
|
||||
* - 12: DMA2 / Channel5
|
||||
* - ...
|
||||
* - 14: DMA2 / Channel7
|
||||
*/
|
||||
int stream;
|
||||
} dma_conf_t;
|
||||
|
||||
/**
|
||||
@ -536,7 +558,7 @@ void dma_init(void);
|
||||
* function which configure, start, wait and stop a DMA transfer.
|
||||
*
|
||||
* @param[in] dma logical DMA stream
|
||||
* @param[in] chan DMA channel
|
||||
* @param[in] chan DMA channel (on stm32f2/4/7, CxS or unused on others)
|
||||
* @param[in] src source buffer
|
||||
* @param[out] dst destination buffer
|
||||
* @param[in] len length to transfer
|
||||
@ -545,7 +567,7 @@ void dma_init(void);
|
||||
*
|
||||
* @return < 0 on error, the number of transfered bytes otherwise
|
||||
*/
|
||||
int dma_transfer(dma_t dma, int chan, const void *src, void *dst, size_t len,
|
||||
int dma_transfer(dma_t dma, int chan, const volatile void *src, volatile void *dst, size_t len,
|
||||
dma_mode_t mode, uint8_t flags);
|
||||
|
||||
/**
|
||||
@ -607,7 +629,7 @@ void dma_wait(dma_t dma);
|
||||
* @brief Configure a DMA stream for a new transfer
|
||||
*
|
||||
* @param[in] dma logical DMA stream
|
||||
* @param[in] chan DMA channel
|
||||
* @param[in] chan DMA channel (on stm32f2/4/7, CxS or unused on others)
|
||||
* @param[in] src source buffer
|
||||
* @param[out] dst destination buffer
|
||||
* @param[in] len length to transfer
|
||||
@ -616,147 +638,9 @@ void dma_wait(dma_t dma);
|
||||
*
|
||||
* @return < 0 on error, 0 on success
|
||||
*/
|
||||
int dma_configure(dma_t dma, int chan, const void *src, void *dst, size_t len,
|
||||
int dma_configure(dma_t dma, int chan, const volatile void *src, volatile void *dst, size_t len,
|
||||
dma_mode_t mode, uint8_t flags);
|
||||
|
||||
/**
|
||||
* @brief Get DMA base register
|
||||
*
|
||||
* For simplifying DMA stream handling, we map the DMA channels transparently to
|
||||
* one integer number, such that DMA1 stream0 equals 0, DMA2 stream0 equals 8,
|
||||
* DMA2 stream 7 equals 15 and so on.
|
||||
*
|
||||
* @param[in] stream physical DMA stream
|
||||
*/
|
||||
static inline DMA_TypeDef *dma_base(int stream)
|
||||
{
|
||||
return (stream < 8) ? DMA1 : DMA2;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Power on the DMA device the given stream belongs to
|
||||
*
|
||||
* @param[in] stream physical DMA stream
|
||||
*/
|
||||
static inline void dma_poweron(int stream)
|
||||
{
|
||||
if (stream < 8) {
|
||||
periph_clk_en(AHB1, RCC_AHB1ENR_DMA1EN);
|
||||
}
|
||||
else {
|
||||
periph_clk_en(AHB1, RCC_AHB1ENR_DMA2EN);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the DMA stream base address
|
||||
*
|
||||
* @param[in] stream physical DMA stream
|
||||
*
|
||||
* @return base address for the selected DMA stream
|
||||
*/
|
||||
static inline DMA_Stream_TypeDef *dma_stream(int stream)
|
||||
{
|
||||
uint32_t base = (uint32_t)dma_base(stream);
|
||||
|
||||
return (DMA_Stream_TypeDef *)(base + (0x10 + (0x18 * (stream & 0x7))));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Select high or low DMA interrupt register based on stream number
|
||||
*
|
||||
* @param[in] stream physical DMA stream
|
||||
*
|
||||
* @return 0 for streams 0-3, 1 for streams 3-7
|
||||
*/
|
||||
static inline int dma_hl(int stream)
|
||||
{
|
||||
return ((stream & 0x4) >> 2);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the interrupt flag clear bit position in the DMA LIFCR register
|
||||
*
|
||||
* @param[in] stream physical DMA stream
|
||||
*/
|
||||
static inline uint32_t dma_ifc(int stream)
|
||||
{
|
||||
switch (stream & 0x3) {
|
||||
case 0:
|
||||
return (1 << 5);
|
||||
case 1:
|
||||
return (1 << 11);
|
||||
case 2:
|
||||
return (1 << 21);
|
||||
case 3:
|
||||
return (1 << 27);
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enable the interrupt of a given stream
|
||||
*
|
||||
* @param[in] stream physical DMA stream
|
||||
*/
|
||||
static inline void dma_isr_enable(int stream)
|
||||
{
|
||||
if (stream < 7) {
|
||||
NVIC_EnableIRQ((IRQn_Type)((int)DMA1_Stream0_IRQn + stream));
|
||||
}
|
||||
else if (stream == 7) {
|
||||
NVIC_EnableIRQ(DMA1_Stream7_IRQn);
|
||||
}
|
||||
else if (stream < 13) {
|
||||
NVIC_EnableIRQ((IRQn_Type)((int)DMA2_Stream0_IRQn + (stream - 8)));
|
||||
}
|
||||
else if (stream < 16) {
|
||||
NVIC_EnableIRQ((IRQn_Type)((int)DMA2_Stream5_IRQn + (stream - 13)));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Disable the interrupt of a given stream
|
||||
*
|
||||
* @param[in] stream physical DMA stream
|
||||
*/
|
||||
static inline void dma_isr_disable(int stream)
|
||||
{
|
||||
if (stream < 7) {
|
||||
NVIC_DisableIRQ((IRQn_Type)((int)DMA1_Stream0_IRQn + stream));
|
||||
}
|
||||
else if (stream == 7) {
|
||||
NVIC_DisableIRQ(DMA1_Stream7_IRQn);
|
||||
}
|
||||
else if (stream < 13) {
|
||||
NVIC_DisableIRQ((IRQn_Type)((int)DMA2_Stream0_IRQn + (stream - 8)));
|
||||
}
|
||||
else if (stream < 16) {
|
||||
NVIC_DisableIRQ((IRQn_Type)((int)DMA2_Stream5_IRQn + (stream - 13)));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Clear the interrupt of a given stream
|
||||
*
|
||||
* @param[in] stream physical DMA stream
|
||||
*/
|
||||
static inline void dma_isr_clear(int stream)
|
||||
{
|
||||
if (stream < 7) {
|
||||
NVIC_ClearPendingIRQ((IRQn_Type)((int)DMA1_Stream0_IRQn + stream));
|
||||
}
|
||||
else if (stream == 7) {
|
||||
NVIC_ClearPendingIRQ((IRQn_Type)DMA1_Stream7_IRQn);
|
||||
}
|
||||
else if (stream < 13) {
|
||||
NVIC_ClearPendingIRQ((IRQn_Type)((int)DMA2_Stream0_IRQn + (stream - 8)));
|
||||
}
|
||||
else if (stream < 16) {
|
||||
NVIC_ClearPendingIRQ((IRQn_Type)((int)DMA2_Stream5_IRQn + (stream - 13)));
|
||||
}
|
||||
}
|
||||
#endif /* MODULE_PERIPH_DMA */
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
@ -24,14 +24,75 @@
|
||||
#include "periph_conf.h"
|
||||
#include "mutex.h"
|
||||
#include "assert.h"
|
||||
#include "pm_layered.h"
|
||||
|
||||
#if !(defined(CPU_FAM_STM32F2) || defined(CPU_FAM_STM32F4) || defined(CPU_FAM_STM32F7))
|
||||
#error "DMA is not supported for target CPU"
|
||||
#if CPU_FAM_STM32F3
|
||||
#error "DMA is not supported on STM32F3"
|
||||
#endif
|
||||
|
||||
#define DMA_STREAM_IT_MASK (DMA_LISR_FEIF0 | DMA_LISR_DMEIF0 | \
|
||||
DMA_LISR_TEIF0 | DMA_LISR_HTIF0 | \
|
||||
DMA_LISR_TCIF0)
|
||||
#if CPU_FAM_STM32F2 || CPU_FAM_STM32F4 || CPU_FAM_STM32F7
|
||||
#define STM32_DMA_Stream_Type DMA_Stream_TypeDef
|
||||
#define CLOCK AHB1
|
||||
#define PERIPH_ADDR PAR
|
||||
#define MEM_ADDR M0AR
|
||||
#define NDTR_REG NDTR
|
||||
#define CONTROL_REG CR
|
||||
#define RCC_MASK_DMA1 RCC_AHB1ENR_DMA1EN
|
||||
#define RCC_MASK_DMA2 RCC_AHB1ENR_DMA2EN
|
||||
#define DMA_STREAM_IT_MASK (DMA_LISR_FEIF0 | DMA_LISR_DMEIF0 | \
|
||||
DMA_LISR_TEIF0 | DMA_LISR_HTIF0 | \
|
||||
DMA_LISR_TCIF0)
|
||||
#define DMA_EN DMA_SxCR_EN
|
||||
#else /* CPU_FAM_STM32F2 || CPU_FAM_STM32F4 || CPU_FAM_STM32F7 */
|
||||
#define STM32_DMA_Stream_Type DMA_Channel_TypeDef
|
||||
#if CPU_FAM_STM32L4
|
||||
#define CLOCK AHB1
|
||||
#define RCC_MASK_DMA1 RCC_AHB1ENR_DMA1EN
|
||||
#define RCC_MASK_DMA2 RCC_AHB1ENR_DMA2EN
|
||||
#else /* CPU_FAM_STM32L4 */
|
||||
#define CLOCK AHB
|
||||
#if CPU_FAM_STM32F1 || CPU_FAM_STM32L1
|
||||
#define RCC_MASK_DMA1 RCC_AHBENR_DMA1EN
|
||||
#else /* CPU_FAM_STM32F1 || CPU_FAM_STM32L1 */
|
||||
#define RCC_MASK_DMA1 RCC_AHBENR_DMAEN
|
||||
#endif /* CPU_FAM_STM32F1 || CPU_FAM_STM32L1 */
|
||||
#define RCC_MASK_DMA2 RCC_AHBENR_DMA2EN
|
||||
#endif /* CPU_FAM_STM32L4 */
|
||||
#define PERIPH_ADDR CPAR
|
||||
#define MEM_ADDR CMAR
|
||||
#define NDTR_REG CNDTR
|
||||
#define CONTROL_REG CCR
|
||||
#if CPU_FAM_STM32L1
|
||||
#define DMA_CCR_TCIE DMA_CCR1_TCIE
|
||||
#define DMA_CCR_TEIE DMA_CCR1_TEIE
|
||||
#define DMA_EN DMA_CCR1_EN
|
||||
#else /* CPU_FAM_STM32L1 */
|
||||
#define DMA_EN DMA_CCR_EN
|
||||
#endif /* CPU_FAM_STM32L1 */
|
||||
#define DMA_STREAM_IT_MASK (DMA_IFCR_CGIF1 | DMA_IFCR_CTCIF1 | \
|
||||
DMA_IFCR_CHTIF1 | DMA_IFCR_CTEIF1)
|
||||
#ifndef DMA_CCR_MSIZE_Pos
|
||||
#define DMA_CCR_MSIZE_Pos (10)
|
||||
#endif
|
||||
#ifndef DMA_CCR_PSIZE_Pos
|
||||
#define DMA_CCR_PSIZE_Pos (8)
|
||||
#endif
|
||||
#ifndef DMA_CCR_MINC_Pos
|
||||
#define DMA_CCR_MINC_Pos (7)
|
||||
#endif
|
||||
#ifndef DMA_CCR_PINC_Pos
|
||||
#define DMA_CCR_PINC_Pos (6)
|
||||
#endif
|
||||
#ifndef DMA_CCR_DIR_Pos
|
||||
#define DMA_CCR_DIR_Pos (4)
|
||||
#endif
|
||||
#ifndef DMA_CCR_MEM2MEM_Pos
|
||||
#define DMA_CCR_MEM2MEM_Pos (14)
|
||||
#endif
|
||||
#if defined(CPU_FAM_STM32F0) && !defined(DMA1_Channel4_5_6_7_IRQn)
|
||||
#define DMA1_Channel4_5_6_7_IRQn DMA1_Channel4_5_IRQn
|
||||
#endif
|
||||
#endif /* CPU_FAM_STM32F2 || CPU_FAM_STM32F4 || CPU_FAM_STM32F7 */
|
||||
|
||||
struct dma_ctx {
|
||||
mutex_t conf_lock;
|
||||
@ -41,10 +102,161 @@ struct dma_ctx {
|
||||
|
||||
static struct dma_ctx dma_ctx[DMA_NUMOF];
|
||||
|
||||
/**
|
||||
* @brief Get DMA base register
|
||||
*
|
||||
* For simplifying DMA stream handling, we map the DMA channels transparently to
|
||||
* one integer number, such that DMA1 stream0 equals 0, DMA2 stream0 equals 8,
|
||||
* DMA2 stream 7 equals 15 and so on.
|
||||
*
|
||||
* @param[in] stream physical DMA stream
|
||||
*/
|
||||
static inline DMA_TypeDef *dma_base(int stream)
|
||||
{
|
||||
#if CPU_FAM_STM32F2 || CPU_FAM_STM32F4 || CPU_FAM_STM32F7
|
||||
return (stream < 8) ? DMA1 : DMA2;
|
||||
#elif defined(DMA2)
|
||||
return (stream < 7) ? DMA1 : DMA2;
|
||||
#else
|
||||
(void)stream;
|
||||
return DMA1;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef CPU_FAM_STM32F0
|
||||
static inline DMA_TypeDef *dma_req(int stream_n)
|
||||
{
|
||||
return dma_base(stream_n);
|
||||
}
|
||||
#elif CPU_FAM_STM32L0 || CPU_FAM_STM32L4
|
||||
static inline DMA_Request_TypeDef *dma_req(int stream_n)
|
||||
{
|
||||
#ifdef DMA2
|
||||
return (stream_n < 7) ? DMA1_CSELR : DMA2_CSELR;
|
||||
#else
|
||||
(void)stream_n;
|
||||
return DMA1_CSELR;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Get the DMA stream base address
|
||||
*
|
||||
* @param[in] stream physical DMA stream
|
||||
*
|
||||
* @return base address for the selected DMA stream
|
||||
*/
|
||||
static inline STM32_DMA_Stream_Type *dma_stream(int stream)
|
||||
{
|
||||
uint32_t base = (uint32_t)dma_base(stream);
|
||||
|
||||
#if CPU_FAM_STM32F2 || CPU_FAM_STM32F4 || CPU_FAM_STM32F7
|
||||
return (DMA_Stream_TypeDef *)(base + (0x10 + (0x18 * (stream & 0x7))));
|
||||
#else
|
||||
return (DMA_Channel_TypeDef *)(base + (0x08 + (0x14 * (stream & 0x7))));
|
||||
#endif
|
||||
}
|
||||
|
||||
#if CPU_FAM_STM32F2 || CPU_FAM_STM32F4 || CPU_FAM_STM32F7
|
||||
/**
|
||||
* @brief Select high or low DMA interrupt register based on stream number
|
||||
*
|
||||
* @param[in] stream physical DMA stream
|
||||
*
|
||||
* @return 0 for streams 0-3, 1 for streams 3-7
|
||||
*/
|
||||
static inline int dma_hl(int stream)
|
||||
{
|
||||
return ((stream & 0x4) >> 2);
|
||||
}
|
||||
#endif
|
||||
|
||||
static IRQn_Type dma_get_irqn(int stream)
|
||||
{
|
||||
#if CPU_FAM_STM32F2 || CPU_FAM_STM32F4 || CPU_FAM_STM32F7
|
||||
if (stream < 7) {
|
||||
return ((IRQn_Type)((int)DMA1_Stream0_IRQn + stream));
|
||||
}
|
||||
else if (stream == 7) {
|
||||
return DMA1_Stream7_IRQn;
|
||||
}
|
||||
else if (stream < 13) {
|
||||
return ((IRQn_Type)((int)DMA2_Stream0_IRQn + (stream - 8)));
|
||||
}
|
||||
else if (stream < 16) {
|
||||
return ((IRQn_Type)((int)DMA2_Stream5_IRQn + (stream - 13)));
|
||||
}
|
||||
#elif CPU_FAM_STM32F0 || CPU_FAM_STM32L0
|
||||
if (stream == 0) {
|
||||
return (DMA1_Channel1_IRQn);
|
||||
}
|
||||
else if (stream < 3 || (stream >= 8 && stream < 11)) {
|
||||
return (DMA1_Channel2_3_IRQn);
|
||||
}
|
||||
else if (stream < 7 || stream >= 11) {
|
||||
return (DMA1_Channel4_5_6_7_IRQn);
|
||||
}
|
||||
#else
|
||||
if (stream < 7) {
|
||||
return ((IRQn_Type)((int)DMA1_Channel1_IRQn + stream));
|
||||
}
|
||||
#if defined(CPU_FAM_STM32F1)
|
||||
else if (stream < 11) {
|
||||
#else
|
||||
else if (stream < 13 ) {
|
||||
#endif
|
||||
return ((IRQn_Type)((int)DMA2_Channel1_IRQn + stream));
|
||||
}
|
||||
#if !defined(CPU_FAM_STM32L1)
|
||||
else {
|
||||
#if defined(CPU_FAM_STM32F1)
|
||||
return (DMA2_Channel4_5_IRQn);
|
||||
#else
|
||||
return ((IRQn_Type)((int)DMA2_Channel6_IRQn + stream));
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Disable the interrupt of a given stream
|
||||
*
|
||||
* @param[in] stream physical DMA stream
|
||||
*/
|
||||
static inline void dma_isr_disable(int stream)
|
||||
{
|
||||
NVIC_DisableIRQ(dma_get_irqn(stream));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Clear the interrupt of a given stream
|
||||
*
|
||||
* @param[in] stream physical DMA stream
|
||||
*/
|
||||
static inline void dma_isr_clear(int stream)
|
||||
{
|
||||
NVIC_ClearPendingIRQ(dma_get_irqn(stream));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enable the interrupt of a given stream
|
||||
*
|
||||
* @param[in] stream physical DMA stream
|
||||
*/
|
||||
static inline void dma_isr_enable(int stream)
|
||||
{
|
||||
NVIC_EnableIRQ(dma_get_irqn(stream));
|
||||
}
|
||||
|
||||
static inline uint32_t dma_all_flags(dma_t dma)
|
||||
{
|
||||
assert(dma < DMA_NUMOF);
|
||||
|
||||
#if CPU_FAM_STM32F2 || CPU_FAM_STM32F4 || CPU_FAM_STM32F7
|
||||
switch (dma_config[dma].stream & 0x3) {
|
||||
case 0: /* 0 and 4 */
|
||||
return (DMA_STREAM_IT_MASK);
|
||||
@ -57,24 +269,30 @@ static inline uint32_t dma_all_flags(dma_t dma)
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
return DMA_STREAM_IT_MASK << ((dma_config[dma].stream & 0x7) * 4);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void dma_clear_all_flags(dma_t dma)
|
||||
{
|
||||
assert(dma < DMA_NUMOF);
|
||||
|
||||
DMA_TypeDef *stream = dma_base(dma_config[dma].stream);
|
||||
DMA_TypeDef *dma_dev = dma_base(dma_config[dma].stream);
|
||||
|
||||
#if CPU_FAM_STM32F2 || CPU_FAM_STM32F4 || CPU_FAM_STM32F7
|
||||
/* Clear all flags */
|
||||
if (dma_hl(dma_config[dma].stream) == 0) {
|
||||
stream->LIFCR = dma_all_flags(dma);
|
||||
dma_dev->LIFCR = dma_all_flags(dma);
|
||||
}
|
||||
else {
|
||||
stream->HIFCR = dma_all_flags(dma);
|
||||
dma_dev->HIFCR = dma_all_flags(dma);
|
||||
}
|
||||
#else
|
||||
dma_dev->IFCR = dma_all_flags(dma);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void dma_init(void)
|
||||
{
|
||||
for (unsigned i = 0; i < DMA_NUMOF; i++) {
|
||||
@ -84,7 +302,20 @@ void dma_init(void)
|
||||
}
|
||||
}
|
||||
|
||||
int dma_transfer(dma_t dma, int chan, const void *src, void *dst, size_t len,
|
||||
static void dma_poweron(int stream)
|
||||
{
|
||||
if (stream < 8) {
|
||||
periph_clk_en(CLOCK, RCC_MASK_DMA1);
|
||||
}
|
||||
#if defined(DMA2)
|
||||
else {
|
||||
periph_clk_en(CLOCK, RCC_MASK_DMA2);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
int dma_transfer(dma_t dma, int chan, const volatile void *src, volatile void *dst, size_t len,
|
||||
dma_mode_t mode, uint8_t flags)
|
||||
{
|
||||
int ret = dma_configure(dma, chan, src, dst, len, mode, flags);
|
||||
@ -103,16 +334,24 @@ void dma_acquire(dma_t dma)
|
||||
assert(dma < DMA_NUMOF);
|
||||
|
||||
mutex_lock(&dma_ctx[dma].conf_lock);
|
||||
#ifdef STM32_PM_STOP
|
||||
/* block STOP mode */
|
||||
pm_block(STM32_PM_STOP);
|
||||
#endif
|
||||
}
|
||||
|
||||
void dma_release(dma_t dma)
|
||||
{
|
||||
assert(dma < DMA_NUMOF);
|
||||
|
||||
#ifdef STM32_PM_STOP
|
||||
/* unblock STOP mode */
|
||||
pm_unblock(STM32_PM_STOP);
|
||||
#endif
|
||||
mutex_unlock(&dma_ctx[dma].conf_lock);
|
||||
}
|
||||
|
||||
int dma_configure(dma_t dma, int chan, const void *src, void *dst, size_t len,
|
||||
int dma_configure(dma_t dma, int chan, const volatile void *src, volatile void *dst, size_t len,
|
||||
dma_mode_t mode, uint8_t flags)
|
||||
{
|
||||
assert(src != NULL);
|
||||
@ -122,22 +361,22 @@ int dma_configure(dma_t dma, int chan, const void *src, void *dst, size_t len,
|
||||
int stream_n = dma_config[dma].stream;
|
||||
uint32_t inc_periph;
|
||||
uint32_t inc_mem;
|
||||
STM32_DMA_Stream_Type *stream = dma_stream(stream_n);
|
||||
|
||||
DMA_Stream_TypeDef *stream = dma_stream(stream_n);
|
||||
dma_poweron(stream_n);
|
||||
dma_clear_all_flags(dma);
|
||||
|
||||
switch (mode) {
|
||||
case DMA_MEM_TO_MEM:
|
||||
case DMA_PERIPH_TO_MEM:
|
||||
stream->PAR = (uint32_t)src;
|
||||
stream->M0AR = (uint32_t)dst;
|
||||
stream->PERIPH_ADDR = (uint32_t)src;
|
||||
stream->MEM_ADDR = (uint32_t)dst;
|
||||
inc_periph = (flags & DMA_INC_SRC_ADDR);
|
||||
inc_mem = (flags & DMA_INC_DST_ADDR) >> 1;
|
||||
break;
|
||||
case DMA_MEM_TO_PERIPH:
|
||||
stream->PAR = (uint32_t)dst;
|
||||
stream->M0AR = (uint32_t)src;
|
||||
stream->PERIPH_ADDR = (uint32_t)dst;
|
||||
stream->MEM_ADDR = (uint32_t)src;
|
||||
inc_periph = (flags & DMA_INC_DST_ADDR) >> 1;
|
||||
inc_mem = (flags & DMA_INC_SRC_ADDR);
|
||||
break;
|
||||
@ -146,6 +385,7 @@ int dma_configure(dma_t dma, int chan, const void *src, void *dst, size_t len,
|
||||
}
|
||||
|
||||
uint32_t width = (flags & DMA_DATA_WIDTH_MASK) >> DMA_DATA_WIDTH_SHIFT;
|
||||
#if CPU_FAM_STM32F2 || CPU_FAM_STM32F4 || CPU_FAM_STM32F7
|
||||
/* Set channel, data width, inc and mode */
|
||||
stream->CR = (chan & 0xF) << DMA_SxCR_CHSEL_Pos |
|
||||
width << DMA_SxCR_MSIZE_Pos | width << DMA_SxCR_PSIZE_Pos |
|
||||
@ -155,9 +395,20 @@ int dma_configure(dma_t dma, int chan, const void *src, void *dst, size_t len,
|
||||
stream->CR |= DMA_SxCR_TCIE | DMA_SxCR_TEIE;
|
||||
/* Configure FIFO */
|
||||
stream->FCR = 0;
|
||||
|
||||
#else
|
||||
#if defined(DMA_CSELR_C1S) || defined(DMA1_CSELR_DEFAULT)
|
||||
dma_req(stream_n)->CSELR &= ~((0xF) << ((stream_n & 0x7) << 2));
|
||||
dma_req(stream_n)->CSELR |= (chan & 0xF) << ((stream_n & 0x7) << 2);
|
||||
#else
|
||||
(void)chan;
|
||||
#endif
|
||||
stream->CONTROL_REG = width << DMA_CCR_MSIZE_Pos | width << DMA_CCR_PSIZE_Pos |
|
||||
inc_periph << DMA_CCR_PINC_Pos | inc_mem << DMA_CCR_MINC_Pos |
|
||||
(mode & 1) << DMA_CCR_DIR_Pos | ((mode & 2) >> 1) << DMA_CCR_MEM2MEM_Pos;
|
||||
stream->CONTROL_REG |= DMA_CCR_TCIE | DMA_CCR_TEIE;
|
||||
#endif
|
||||
/* Set length */
|
||||
stream->NDTR = len;
|
||||
stream->NDTR_REG = len;
|
||||
dma_ctx[dma].len = len;
|
||||
|
||||
dma_isr_enable(stream_n);
|
||||
@ -169,9 +420,9 @@ void dma_start(dma_t dma)
|
||||
{
|
||||
assert(dma < DMA_NUMOF);
|
||||
|
||||
DMA_Stream_TypeDef *stream = dma_stream(dma_config[dma].stream);
|
||||
STM32_DMA_Stream_Type *stream = dma_stream(dma_config[dma].stream);
|
||||
|
||||
stream->CR |= DMA_SxCR_EN;
|
||||
stream->CONTROL_REG |= DMA_EN;
|
||||
}
|
||||
|
||||
uint16_t dma_suspend(dma_t dma)
|
||||
@ -179,15 +430,15 @@ uint16_t dma_suspend(dma_t dma)
|
||||
assert(dma < DMA_NUMOF);
|
||||
|
||||
int stream_n = dma_config[dma].stream;
|
||||
DMA_Stream_TypeDef *stream = dma_stream(stream_n);
|
||||
STM32_DMA_Stream_Type *stream = dma_stream(stream_n);
|
||||
uint16_t left = 0;
|
||||
|
||||
if ((stream->CR & DMA_SxCR_EN) == DMA_SxCR_EN) {
|
||||
if ((stream->CONTROL_REG & DMA_EN) == DMA_EN) {
|
||||
dma_isr_disable(stream_n);
|
||||
stream->CR &= ~(uint32_t)DMA_SxCR_EN;
|
||||
while ((stream->CR & DMA_SxCR_EN) == DMA_SxCR_EN) {}
|
||||
stream->CONTROL_REG &= ~(uint32_t)DMA_EN;
|
||||
while ((stream->CONTROL_REG & DMA_EN) == DMA_EN) {}
|
||||
dma_clear_all_flags(dma);
|
||||
left = stream->NDTR;
|
||||
left = stream->NDTR_REG;
|
||||
dma_isr_clear(stream_n);
|
||||
}
|
||||
return left;
|
||||
@ -199,14 +450,14 @@ void dma_resume(dma_t dma, uint16_t remaining)
|
||||
assert(dma < DMA_NUMOF);
|
||||
|
||||
int stream_n = dma_config[dma].stream;
|
||||
DMA_Stream_TypeDef *stream = dma_stream(stream_n);
|
||||
STM32_DMA_Stream_Type *stream = dma_stream(stream_n);
|
||||
|
||||
if (remaining > 0) {
|
||||
dma_isr_enable(stream_n);
|
||||
stream->NDTR = remaining;
|
||||
stream->M0AR += dma_ctx[dma].len - remaining;
|
||||
stream->NDTR_REG = remaining;
|
||||
stream->MEM_ADDR += dma_ctx[dma].len - remaining;
|
||||
dma_ctx[dma].len = remaining;
|
||||
stream->CR |= (uint32_t)DMA_SxCR_EN;
|
||||
stream->CONTROL_REG |= DMA_EN;
|
||||
}
|
||||
}
|
||||
|
||||
@ -214,9 +465,9 @@ void dma_stop(dma_t dma)
|
||||
{
|
||||
assert(dma < DMA_NUMOF);
|
||||
|
||||
DMA_Stream_TypeDef *stream = dma_stream(dma_config[dma].stream);
|
||||
STM32_DMA_Stream_Type *stream = dma_stream(dma_config[dma].stream);
|
||||
|
||||
stream->CR &= ~(uint32_t)DMA_SxCR_EN;
|
||||
stream->CONTROL_REG &= ~(uint32_t)DMA_EN;
|
||||
}
|
||||
|
||||
void dma_wait(dma_t dma)
|
||||
@ -304,3 +555,51 @@ void DMA_9_ISR(void)
|
||||
dma_isr_handler(9);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(DMA_SHARED_ISR_0) || defined(DMA_SHARED_ISR_1)
|
||||
static int dma_is_isr(dma_t dma)
|
||||
{
|
||||
DMA_TypeDef *dma_dev = dma_base(dma_config[dma].stream);
|
||||
|
||||
#if CPU_FAM_STM32F2 || CPU_FAM_STM32F4 || CPU_FAM_STM32F7
|
||||
/* Clear all flags */
|
||||
if (dma_hl(dma_config[dma].stream) == 0) {
|
||||
return dma_dev->LISR & dma_all_flags(dma);
|
||||
}
|
||||
else {
|
||||
return dma_dev->HISR & dma_all_flags(dma);
|
||||
}
|
||||
#else
|
||||
return dma_dev->ISR & dma_all_flags(dma);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void shared_isr(uint8_t *streams, size_t nb)
|
||||
{
|
||||
for (size_t i = 0; i < nb; i++) {
|
||||
dma_t dma = streams[i];
|
||||
if (dma_is_isr(dma)) {
|
||||
dma_clear_all_flags(dma);
|
||||
mutex_unlock(&dma_ctx[dma].sync_lock);
|
||||
}
|
||||
}
|
||||
|
||||
cortexm_isr_end();
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef DMA_SHARED_ISR_0
|
||||
void DMA_SHARED_ISR_0(void)
|
||||
{
|
||||
uint8_t streams[] = DMA_SHARED_ISR_0_STREAMS;
|
||||
shared_isr(streams, sizeof(streams) / sizeof(streams[0]));
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef DMA_SHARED_ISR_1
|
||||
void DMA_SHARED_ISR_1(void)
|
||||
{
|
||||
uint8_t streams[] = DMA_SHARED_ISR_1_STREAMS;
|
||||
shared_isr(streams, sizeof(streams) / sizeof(streams[0]));
|
||||
}
|
||||
#endif
|
||||
|
@ -169,19 +169,19 @@ static void _transfer_dma(spi_t bus, const void *out, void *in, size_t len)
|
||||
|
||||
if (!out) {
|
||||
dma_configure(spi_config[bus].tx_dma, spi_config[bus].tx_dma_chan, &tmp,
|
||||
(void *)&(dev(bus)->DR), len, DMA_MEM_TO_PERIPH, 0);
|
||||
&(dev(bus)->DR), len, DMA_MEM_TO_PERIPH, 0);
|
||||
}
|
||||
else {
|
||||
dma_configure(spi_config[bus].tx_dma, spi_config[bus].tx_dma_chan, out,
|
||||
(void *)&(dev(bus)->DR), len, DMA_MEM_TO_PERIPH, DMA_INC_SRC_ADDR);
|
||||
&(dev(bus)->DR), len, DMA_MEM_TO_PERIPH, DMA_INC_SRC_ADDR);
|
||||
}
|
||||
if (!in) {
|
||||
dma_configure(spi_config[bus].rx_dma, spi_config[bus].rx_dma_chan,
|
||||
(void *)&(dev(bus)->DR), &tmp, len, DMA_PERIPH_TO_MEM, 0);
|
||||
&(dev(bus)->DR), &tmp, len, DMA_PERIPH_TO_MEM, 0);
|
||||
}
|
||||
else {
|
||||
dma_configure(spi_config[bus].rx_dma, spi_config[bus].rx_dma_chan,
|
||||
(void *)&(dev(bus)->DR), in, len, DMA_PERIPH_TO_MEM, DMA_INC_DST_ADDR);
|
||||
&(dev(bus)->DR), in, len, DMA_PERIPH_TO_MEM, DMA_INC_DST_ADDR);
|
||||
}
|
||||
dev(bus)->CR2 |= SPI_CR2_TXDMAEN | SPI_CR2_RXDMAEN;
|
||||
|
||||
|
@ -34,6 +34,21 @@
|
||||
#include "periph/gpio.h"
|
||||
#include "pm_layered.h"
|
||||
|
||||
#if defined(CPU_FAM_STM32F0) || defined(CPU_FAM_STM32L0) \
|
||||
|| defined(CPU_FAM_STM32F3) || defined(CPU_FAM_STM32L4) \
|
||||
|| defined(CPU_FAM_STM32F7)
|
||||
#define ISR_REG ISR
|
||||
#define ISR_TXE USART_ISR_TXE
|
||||
#define ISR_TC USART_ISR_TC
|
||||
#define TDR_REG TDR
|
||||
#else
|
||||
#define ISR_REG SR
|
||||
#define ISR_TXE USART_SR_TXE
|
||||
#define ISR_TC USART_SR_TC
|
||||
#define TDR_REG DR
|
||||
|
||||
#endif
|
||||
|
||||
#define RXENABLE (USART_CR1_RE | USART_CR1_RXNEIE)
|
||||
|
||||
/**
|
||||
@ -189,26 +204,13 @@ static inline void uart_init_lpuart(uart_t uart, uint32_t baudrate)
|
||||
|
||||
static inline void send_byte(uart_t uart, uint8_t byte)
|
||||
{
|
||||
#if defined(CPU_FAM_STM32F0) || defined(CPU_FAM_STM32L0) \
|
||||
|| defined(CPU_FAM_STM32F3) || defined(CPU_FAM_STM32L4) \
|
||||
|| defined(CPU_FAM_STM32F7)
|
||||
while (!(dev(uart)->ISR & USART_ISR_TXE)) {}
|
||||
dev(uart)->TDR = byte;
|
||||
#else
|
||||
while (!(dev(uart)->SR & USART_SR_TXE)) {}
|
||||
dev(uart)->DR = byte;
|
||||
#endif
|
||||
while (!(dev(uart)->ISR_REG & USART_ISR_TXE)) {}
|
||||
dev(uart)->TDR_REG = byte;
|
||||
}
|
||||
|
||||
static inline void wait_for_tx_complete(uart_t uart)
|
||||
{
|
||||
#if defined(CPU_FAM_STM32F0) || defined(CPU_FAM_STM32L0) \
|
||||
|| defined(CPU_FAM_STM32F3) || defined(CPU_FAM_STM32L4) \
|
||||
|| defined(CPU_FAM_STM32F7)
|
||||
while (!(dev(uart)->ISR & USART_ISR_TC)) {}
|
||||
#else
|
||||
while (!(dev(uart)->SR & USART_SR_TC)) {}
|
||||
#endif
|
||||
while (!(dev(uart)->ISR_REG & ISR_TC)) {}
|
||||
}
|
||||
|
||||
void uart_write(uart_t uart, const uint8_t *data, size_t len)
|
||||
@ -248,7 +250,7 @@ void uart_write(uart_t uart, const uint8_t *data, size_t len)
|
||||
dma_acquire(uart_config[uart].dma);
|
||||
dev(uart)->CR3 |= USART_CR3_DMAT;
|
||||
dma_transfer(uart_config[uart].dma, uart_config[uart].dma_chan, data,
|
||||
(void *)&dev(uart)->DR, len, DMA_MEM_TO_PERIPH, DMA_INC_SRC_ADDR);
|
||||
(void *)&dev(uart)->TDR_REG, len, DMA_MEM_TO_PERIPH, DMA_INC_SRC_ADDR);
|
||||
dma_release(uart_config[uart].dma);
|
||||
|
||||
/* make sure the function is synchronous by waiting for the transfer to
|
||||
|
Loading…
Reference in New Issue
Block a user