/* * Copyright (c) 2019 Song Qiang * * SPDX-License-Identifier: Apache-2.0 */ /** * @brief DMA low level driver implementation for F2/F4/F7 series SoCs. */ #include #include #define LOG_LEVEL CONFIG_DMA_LOG_LEVEL #include LOG_MODULE_REGISTER(dma_stm32_v1); /* DMA burst length */ #define BURST_TRANS_LENGTH_1 0 uint32_t table_ll_stream[] = { LL_DMA_STREAM_0, LL_DMA_STREAM_1, LL_DMA_STREAM_2, LL_DMA_STREAM_3, LL_DMA_STREAM_4, LL_DMA_STREAM_5, LL_DMA_STREAM_6, LL_DMA_STREAM_7, }; uint32_t table_ll_channel[] = { LL_DMA_CHANNEL_0, 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_HT0, 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_TC0, 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, }; uint32_t (*func_ll_is_active_ht[])(DMA_TypeDef *DMAx) = { LL_DMA_IsActiveFlag_HT0, 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, }; uint32_t (*func_ll_is_active_tc[])(DMA_TypeDef *DMAx) = { LL_DMA_IsActiveFlag_TC0, 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_TE0, 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_dme[])(DMA_TypeDef *DMAx) = { LL_DMA_ClearFlag_DME0, LL_DMA_ClearFlag_DME1, LL_DMA_ClearFlag_DME2, LL_DMA_ClearFlag_DME3, LL_DMA_ClearFlag_DME4, LL_DMA_ClearFlag_DME5, LL_DMA_ClearFlag_DME6, LL_DMA_ClearFlag_DME7, }; static void (*func_ll_clear_fe[])(DMA_TypeDef *DMAx) = { LL_DMA_ClearFlag_FE0, LL_DMA_ClearFlag_FE1, LL_DMA_ClearFlag_FE2, LL_DMA_ClearFlag_FE3, LL_DMA_ClearFlag_FE4, LL_DMA_ClearFlag_FE5, LL_DMA_ClearFlag_FE6, LL_DMA_ClearFlag_FE7, }; static uint32_t (*func_ll_is_active_te[])(DMA_TypeDef *DMAx) = { LL_DMA_IsActiveFlag_TE0, 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 uint32_t (*func_ll_is_active_dme[])(DMA_TypeDef *DMAx) = { LL_DMA_IsActiveFlag_DME0, LL_DMA_IsActiveFlag_DME1, LL_DMA_IsActiveFlag_DME2, LL_DMA_IsActiveFlag_DME3, LL_DMA_IsActiveFlag_DME4, LL_DMA_IsActiveFlag_DME5, LL_DMA_IsActiveFlag_DME6, LL_DMA_IsActiveFlag_DME7, }; static uint32_t (*func_ll_is_active_fe[])(DMA_TypeDef *DMAx) = { LL_DMA_IsActiveFlag_FE0, LL_DMA_IsActiveFlag_FE1, LL_DMA_IsActiveFlag_FE2, LL_DMA_IsActiveFlag_FE3, LL_DMA_IsActiveFlag_FE4, LL_DMA_IsActiveFlag_FE5, LL_DMA_IsActiveFlag_FE6, LL_DMA_IsActiveFlag_FE7, }; void stm32_dma_dump_stream_irq(DMA_TypeDef *dma, uint32_t id) { LOG_INF("tc: %d, ht: %d, te: %d, dme: %d, fe: %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_dme[id](dma), func_ll_is_active_fe[id](dma)); } void stm32_dma_clear_stream_irq(DMA_TypeDef *dma, uint32_t id) { func_ll_clear_te[id](dma); func_ll_clear_dme[id](dma); func_ll_clear_fe[id](dma); } bool stm32_dma_is_irq_happened(DMA_TypeDef *dma, uint32_t id) { if (func_ll_is_active_fe[id](dma) && LL_DMA_IsEnabledIT_FE(dma, id)) { return true; } return false; } bool stm32_dma_is_unexpected_irq_happened(DMA_TypeDef *dma, uint32_t id) { if (func_ll_is_active_fe[id](dma) && LL_DMA_IsEnabledIT_FE(dma, id)) { LOG_ERR("FiFo error."); stm32_dma_dump_stream_irq(dma, id); stm32_dma_clear_stream_irq(dma, id); return true; } return false; } void stm32_dma_enable_stream(DMA_TypeDef *dma, uint32_t id) { LL_DMA_EnableStream(dma, table_ll_stream[id]); } int stm32_dma_disable_stream(DMA_TypeDef *dma, uint32_t id) { if (!LL_DMA_IsEnabledStream(dma, table_ll_stream[id])) { return 0; } LL_DMA_DisableStream(dma, table_ll_stream[id]); return -EAGAIN; } void stm32_dma_disable_fifo_irq(DMA_TypeDef *dma, uint32_t id) { LL_DMA_DisableIT_FE(dma, table_ll_stream[id]); } void stm32_dma_config_channel_function(DMA_TypeDef *dma, uint32_t id, uint32_t slot) { LL_DMA_SetChannelSelection(dma, table_ll_stream[id], table_ll_channel[slot]); } uint32_t stm32_dma_get_mburst(struct dma_config *config, bool source_periph) { uint32_t memory_burst; if (source_periph) { memory_burst = config->dest_burst_length; } else { memory_burst = config->source_burst_length; } switch (memory_burst) { case 1: return LL_DMA_MBURST_SINGLE; case 4: return LL_DMA_MBURST_INC4; case 8: return LL_DMA_MBURST_INC8; case 16: return LL_DMA_MBURST_INC16; default: LOG_ERR("Memory burst size error," "using single burst as default"); return LL_DMA_MBURST_SINGLE; } } uint32_t stm32_dma_get_pburst(struct dma_config *config, bool source_periph) { uint32_t periph_burst; if (source_periph) { periph_burst = config->source_burst_length; } else { periph_burst = config->dest_burst_length; } switch (periph_burst) { case 1: return LL_DMA_PBURST_SINGLE; case 4: return LL_DMA_PBURST_INC4; case 8: return LL_DMA_PBURST_INC8; case 16: return LL_DMA_PBURST_INC16; default: LOG_ERR("Peripheral burst size error," "using single burst as default"); return LL_DMA_PBURST_SINGLE; } } /* * This function checks if the msize, mburst and fifo level is * compitable. If they are not compitable, refer to the 'FIFO' * section in the 'DMA' chapter in the Reference Manual for more * information. * break is emitted since every path of the code has 'return'. * This function does not have the obligation of checking the parameters. */ bool stm32_dma_check_fifo_mburst(LL_DMA_InitTypeDef *DMAx) { uint32_t msize = DMAx->MemoryOrM2MDstDataSize; uint32_t fifo_level = DMAx->FIFOThreshold; uint32_t mburst = DMAx->MemBurst; switch (msize) { case LL_DMA_MDATAALIGN_BYTE: switch (mburst) { case LL_DMA_MBURST_INC4: return true; case LL_DMA_MBURST_INC8: if (fifo_level == LL_DMA_FIFOTHRESHOLD_1_2 || fifo_level == LL_DMA_FIFOTHRESHOLD_FULL) { return true; } else { return false; } case LL_DMA_MBURST_INC16: if (fifo_level == LL_DMA_FIFOTHRESHOLD_FULL) { return true; } else { return false; } } case LL_DMA_MDATAALIGN_HALFWORD: switch (mburst) { case LL_DMA_MBURST_INC4: if (fifo_level == LL_DMA_FIFOTHRESHOLD_1_2 || fifo_level == LL_DMA_FIFOTHRESHOLD_FULL) { return true; } else { return false; } case LL_DMA_MBURST_INC8: if (fifo_level == LL_DMA_FIFOTHRESHOLD_FULL) { return true; } else { return false; } case LL_DMA_MBURST_INC16: return false; } case LL_DMA_MDATAALIGN_WORD: if (mburst == LL_DMA_MBURST_INC4 && fifo_level == LL_DMA_FIFOTHRESHOLD_FULL) { return true; } else { return false; } default: return false; } } uint32_t stm32_dma_get_fifo_threshold(uint16_t fifo_mode_control) { switch (fifo_mode_control) { case 0: return LL_DMA_FIFOTHRESHOLD_1_4; case 1: return LL_DMA_FIFOTHRESHOLD_1_2; case 2: return LL_DMA_FIFOTHRESHOLD_3_4; case 3: return LL_DMA_FIFOTHRESHOLD_FULL; default: LOG_WRN("FIFO threshold parameter error, reset to 1/4"); return LL_DMA_FIFOTHRESHOLD_1_4; } }