zephyr/drivers/dma/dma_stm32_v2.c
Song Qiang 749d2d21bf drivers: dma: add generic driver support for some series of stm32
This commit adds driver support for DMA on f0/f1/f2/f3/f4/l0/l4
series stm32.

Notice due to some bugs, this is currently not working with f7.

There are two kinds of IP blocks are used across these stm32, one is the
one that has been used on F2/F4/F7 series, and the other one is the one
that has been used on F0/F1/F3/L0/L4 series.

Memory to memory transfer is only supported on the second DMA on
F2/F4 with 'st,mem2mem' to be declared in dts.

This driver depends on k_malloc to allocate memory for stream instances,
so CONFIG_HEAP_MEM_POOL_SIZE must be big enough to hold them.

Common parts of the driver are in dma_stm32.c and SoC related parts are
implemented in dma_stm32_v*.c.

This driver has been tested on multiple nucleo boards, including
NUCLEO_F091RC/F103RB/F207ZG/F302R8/F401RE/L073RZ/L476RG with the
loop_transfer and chan_blen_transfer test cases.

Signed-off-by: Song Qiang <songqiang1304521@gmail.com>
2019-11-06 14:14:39 +01:00

154 lines
3.2 KiB
C

/*
* Copyright (c) 2019 Song Qiang <songqiang1304521@gmail.com>
*
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @brief DMA low level driver implementation for F0/F1/F3/L0/L4 series SoCs.
*/
#include <drivers/dma.h>
#include <soc.h>
#define LOG_LEVEL CONFIG_DMA_LOG_LEVEL
#include <logging/log.h>
LOG_MODULE_REGISTER(dma_stm32_v2);
u32_t table_ll_stream[] = {
LL_DMA_CHANNEL_1,
LL_DMA_CHANNEL_2,
LL_DMA_CHANNEL_3,
LL_DMA_CHANNEL_4,
LL_DMA_CHANNEL_5,
LL_DMA_CHANNEL_6,
LL_DMA_CHANNEL_7,
};
void (*func_ll_clear_ht[])(DMA_TypeDef *DMAx) = {
LL_DMA_ClearFlag_HT1,
LL_DMA_ClearFlag_HT2,
LL_DMA_ClearFlag_HT3,
LL_DMA_ClearFlag_HT4,
LL_DMA_ClearFlag_HT5,
LL_DMA_ClearFlag_HT6,
LL_DMA_ClearFlag_HT7,
};
void (*func_ll_clear_tc[])(DMA_TypeDef *DMAx) = {
LL_DMA_ClearFlag_TC1,
LL_DMA_ClearFlag_TC2,
LL_DMA_ClearFlag_TC3,
LL_DMA_ClearFlag_TC4,
LL_DMA_ClearFlag_TC5,
LL_DMA_ClearFlag_TC6,
LL_DMA_ClearFlag_TC7,
};
u32_t (*func_ll_is_active_ht[])(DMA_TypeDef *DMAx) = {
LL_DMA_IsActiveFlag_HT1,
LL_DMA_IsActiveFlag_HT2,
LL_DMA_IsActiveFlag_HT3,
LL_DMA_IsActiveFlag_HT4,
LL_DMA_IsActiveFlag_HT5,
LL_DMA_IsActiveFlag_HT6,
LL_DMA_IsActiveFlag_HT7,
};
u32_t (*func_ll_is_active_tc[])(DMA_TypeDef *DMAx) = {
LL_DMA_IsActiveFlag_TC1,
LL_DMA_IsActiveFlag_TC2,
LL_DMA_IsActiveFlag_TC3,
LL_DMA_IsActiveFlag_TC4,
LL_DMA_IsActiveFlag_TC5,
LL_DMA_IsActiveFlag_TC6,
LL_DMA_IsActiveFlag_TC7,
};
static void (*func_ll_clear_te[])(DMA_TypeDef *DMAx) = {
LL_DMA_ClearFlag_TE1,
LL_DMA_ClearFlag_TE2,
LL_DMA_ClearFlag_TE3,
LL_DMA_ClearFlag_TE4,
LL_DMA_ClearFlag_TE5,
LL_DMA_ClearFlag_TE6,
LL_DMA_ClearFlag_TE7,
};
static void (*func_ll_clear_gi[])(DMA_TypeDef *DMAx) = {
LL_DMA_ClearFlag_GI1,
LL_DMA_ClearFlag_GI2,
LL_DMA_ClearFlag_GI3,
LL_DMA_ClearFlag_GI4,
LL_DMA_ClearFlag_GI5,
LL_DMA_ClearFlag_GI6,
LL_DMA_ClearFlag_GI7,
};
static u32_t (*func_ll_is_active_te[])(DMA_TypeDef *DMAx) = {
LL_DMA_IsActiveFlag_TE1,
LL_DMA_IsActiveFlag_TE2,
LL_DMA_IsActiveFlag_TE3,
LL_DMA_IsActiveFlag_TE4,
LL_DMA_IsActiveFlag_TE5,
LL_DMA_IsActiveFlag_TE6,
LL_DMA_IsActiveFlag_TE7,
};
static u32_t (*func_ll_is_active_gi[])(DMA_TypeDef *DMAx) = {
LL_DMA_IsActiveFlag_GI1,
LL_DMA_IsActiveFlag_GI2,
LL_DMA_IsActiveFlag_GI3,
LL_DMA_IsActiveFlag_GI4,
LL_DMA_IsActiveFlag_GI5,
LL_DMA_IsActiveFlag_GI6,
LL_DMA_IsActiveFlag_GI7,
};
void stm32_dma_dump_stream_irq(DMA_TypeDef *dma, u32_t id)
{
LOG_INF("tc: %d, ht: %d, te: %d, gi: %d",
func_ll_is_active_tc[id](dma),
func_ll_is_active_ht[id](dma),
func_ll_is_active_te[id](dma),
func_ll_is_active_gi[id](dma));
}
void stm32_dma_clear_stream_irq(DMA_TypeDef *dma, u32_t id)
{
func_ll_clear_te[id](dma);
func_ll_clear_gi[id](dma);
}
bool stm32_dma_is_irq_happened(DMA_TypeDef *dma, u32_t id)
{
if (func_ll_is_active_te[id](dma)) {
return true;
}
return false;
}
bool stm32_dma_is_unexpected_irq_happened(DMA_TypeDef *dma, u32_t id)
{
/* Preserve for future amending. */
return false;
}
void stm32_dma_enable_stream(DMA_TypeDef *dma, u32_t id)
{
LL_DMA_EnableChannel(dma, table_ll_stream[id]);
}
int stm32_dma_disable_stream(DMA_TypeDef *dma, u32_t id)
{
if (!LL_DMA_IsEnabledChannel(dma, table_ll_stream[id])) {
return 0;
}
LL_DMA_DisableChannel(dma, table_ll_stream[id]);
return -EAGAIN;
}