You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
627 lines
15 KiB
627 lines
15 KiB
2 months ago
|
/** @addtogroup dma_file DMA peripheral API
|
||
|
* @ingroup peripheral_apis
|
||
|
*/
|
||
|
/*
|
||
|
* This file is part of the libopencm3 project.
|
||
|
*
|
||
|
* Copyright (C) 2015 Kuldeep Singh Dhaka <kuldeepdhaka9@gmail.com>
|
||
|
*
|
||
|
* This library is free software: you can redistribute it and/or modify
|
||
|
* it under the terms of the GNU Lesser General Public License as published by
|
||
|
* the Free Software Foundation, either version 3 of the License, or
|
||
|
* (at your option) any later version.
|
||
|
*
|
||
|
* This library is distributed in the hope that it will be useful,
|
||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
|
* GNU Lesser General Public License for more details.
|
||
|
*
|
||
|
* You should have received a copy of the GNU Lesser General Public License
|
||
|
* along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||
|
*/
|
||
|
|
||
|
#include <libopencm3/efm32/dma.h>
|
||
|
|
||
|
/**@{*/
|
||
|
|
||
|
#define CHANNEL_SUPPORT_LOOP(ch) (((ch) == DMA_CH0) || ((ch) == DMA_CH1))
|
||
|
|
||
|
/**
|
||
|
* Enable DMA with privileged access
|
||
|
* @see dma_enable_with_unprivileged_access()
|
||
|
*/
|
||
|
void dma_enable_with_privileged_access(void)
|
||
|
{
|
||
|
DMA_CONFIG = DMA_CONFIG_EN | DMA_CONFIG_CHPROT;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Enable DMA with un-privileged access
|
||
|
* @see dma_enable_with_privileged_access()
|
||
|
*/
|
||
|
void dma_enable_with_unprivileged_access(void)
|
||
|
{
|
||
|
DMA_CONFIG = DMA_CONFIG_EN;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* same as @a dma_enable_with_unprivileged_access()
|
||
|
* @see dma_enable_with_unprivileged_access()
|
||
|
*/
|
||
|
void dma_enable(void)
|
||
|
{
|
||
|
dma_enable_with_unprivileged_access();
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Disable DMA
|
||
|
*/
|
||
|
void dma_disable(void)
|
||
|
{
|
||
|
DMA_CONFIG = 0;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Set channel's descriptor address
|
||
|
* @param[in] desc_base Address of channel's descriptor address
|
||
|
* @note @a desc_base 8LSB's should be 0x00
|
||
|
*/
|
||
|
void dma_set_desc_address(uint32_t desc_base)
|
||
|
{
|
||
|
if (desc_base & 0xFF) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
DMA_CTRLBASE = desc_base;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Get channel wait on request status flag
|
||
|
* @retval true if flag is set
|
||
|
* @retval false if flag is not set
|
||
|
*/
|
||
|
bool dma_get_wait_on_request_flag(enum dma_ch ch)
|
||
|
{
|
||
|
uint32_t mask = DMA_CHWAITSTATUS_CHxWAITSTATUS(ch);
|
||
|
return (DMA_CHWAITSTATUS & mask) != 0;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Generate a software request on channel
|
||
|
* @param[in] ch Channel (use DMA_CHx)
|
||
|
*/
|
||
|
void dma_generate_software_request(enum dma_ch ch)
|
||
|
{
|
||
|
DMA_CHSWREQ = DMA_CHSWREQ_CHxSWREQ(ch);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Enable channel burst only
|
||
|
* @param[in] ch Channel (use DMA_CHx)
|
||
|
*/
|
||
|
void dma_enable_burst_only(enum dma_ch ch)
|
||
|
{
|
||
|
DMA_CHUSEBURSTS = DMA_CHUSEBURSTS_CHxSUSEBURSTS(ch);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Enable channel single and burst
|
||
|
* @param[in] ch Channel (use DMA_CHx)
|
||
|
*/
|
||
|
void dma_enable_single_and_burst(enum dma_ch ch)
|
||
|
{
|
||
|
DMA_CHUSEBURSTC = DMA_CHUSEBURSTC_CHxSUSEBURSTC(ch);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Enable channel peripherial request
|
||
|
* @param[in] ch Channel (use DMA_CHx)
|
||
|
*/
|
||
|
void dma_enable_periph_request(enum dma_ch ch)
|
||
|
{
|
||
|
DMA_CHREQMASKC = DMA_CHREQMASKC_CHxSREQMASKC(ch);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Disable channel peripherial request
|
||
|
* @param[in] ch Channel (use DMA_CHx)
|
||
|
*/
|
||
|
void dma_disable_periph_request(enum dma_ch ch)
|
||
|
{
|
||
|
DMA_CHREQMASKS = DMA_CHREQMASKS_CHxSREQMASKS(ch);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Enable channel
|
||
|
* @param[in] ch Channel (use DMA_CHx)
|
||
|
*/
|
||
|
void dma_enable_channel(enum dma_ch ch)
|
||
|
{
|
||
|
DMA_CHENS = DMA_CHENS_CHxSENS(ch);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Disable channel
|
||
|
* @param[in] ch Channel (use DMA_CHx)
|
||
|
*/
|
||
|
void dma_disable_channel(enum dma_ch ch)
|
||
|
{
|
||
|
DMA_CHENC = DMA_CHENC_CHxSENC(ch);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Disable channel alternate structure
|
||
|
* @param[in] ch Channel (use DMA_CHx)
|
||
|
*/
|
||
|
void dma_disable_alternate_structure(enum dma_ch ch)
|
||
|
{
|
||
|
DMA_CHALTC = DMA_CHALTC_CHxSALTC(ch);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Enable channel alternate structure
|
||
|
* @param[in] ch Channel (use DMA_CHx)
|
||
|
*/
|
||
|
void dma_enable_alternate_structure(enum dma_ch ch)
|
||
|
{
|
||
|
DMA_CHALTS = DMA_CHALTS_CHxSALTS(ch);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Enable channel high priority
|
||
|
* @param[in] ch Channel (use DMA_CHx)
|
||
|
*/
|
||
|
void dma_enable_priority(enum dma_ch ch)
|
||
|
{
|
||
|
DMA_CHPRIS = DMA_CHPRIS_CHxSPRIC(ch);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Disable channel high priority
|
||
|
* @param[in] ch Channel (use DMA_CHx)
|
||
|
*/
|
||
|
void dma_disable_priority(enum dma_ch ch)
|
||
|
{
|
||
|
DMA_CHPRIC = DMA_CHPRIC_CHxSPRIC(ch);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Get bus error flag
|
||
|
* @retval true if flag is set
|
||
|
* @retval false if flag is not set
|
||
|
*/
|
||
|
bool dma_get_bus_error_flag(void)
|
||
|
{
|
||
|
return (DMA_ERRORC & DMA_ERRORC_ERRORC) != 0;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Clear bus error flag
|
||
|
*/
|
||
|
void dma_clear_bus_error_flag(void)
|
||
|
{
|
||
|
DMA_ERRORC = DMA_ERRORC_ERRORC;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Get channel request flag
|
||
|
* @param[in] ch Channel (use DMA_CHx)
|
||
|
* @retval true if flag is set
|
||
|
* @retval false if flag is not set
|
||
|
*/
|
||
|
bool dma_get_request_flag(enum dma_ch ch)
|
||
|
{
|
||
|
uint32_t mask = DMA_CHREQSTATUS_CHxSREQSTATUS(ch);
|
||
|
return (DMA_CHREQSTATUS & mask) != 0;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Get bus error interrupt flag
|
||
|
* @retval true if flag is set
|
||
|
* @retval false if flag is not set
|
||
|
*/
|
||
|
bool dma_get_bus_error_interrupt_flag(void)
|
||
|
{
|
||
|
return (DMA_IF & DMA_IF_ERR) != 0;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Get channel done interrupt flag
|
||
|
* @param[in] ch Channel (use DMA_CHx)
|
||
|
* @retval true if flag is set
|
||
|
* @retval false if flag is not set
|
||
|
*
|
||
|
*/
|
||
|
bool dma_get_done_interrupt_flag(enum dma_ch ch)
|
||
|
{
|
||
|
return (DMA_IF & DMA_IF_CHxDONE(ch)) != 0;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Set bus error interrupt flag
|
||
|
*/
|
||
|
void dma_set_bus_error_interrupt_flag(void)
|
||
|
{
|
||
|
DMA_IFS = DMA_IFS_ERR;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Set channel done interrupt flag
|
||
|
* @param[in] ch Channel (use DMA_CHx)
|
||
|
*/
|
||
|
void dma_set_done_interrupt_flag(enum dma_ch ch)
|
||
|
{
|
||
|
DMA_IFS = DMA_IFS_CHxDONE(ch);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Clear bus error interrupt flag
|
||
|
*/
|
||
|
void dma_clear_bus_error_interrupt_flag(void)
|
||
|
{
|
||
|
DMA_IFC = DMA_IFC_ERR;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Clear channel done interrupt flag
|
||
|
* @param[in] ch Channel (use DMA_CHx)
|
||
|
*/
|
||
|
void dma_clear_done_interrupt_flag(enum dma_ch ch)
|
||
|
{
|
||
|
DMA_IFC = DMA_IFC_CHxDONE(ch);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Enable bus error interrupt
|
||
|
*/
|
||
|
void dma_enable_bus_error_interrupt(void)
|
||
|
{
|
||
|
DMA_IEN |= DMA_IEN_ERR;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Disable bus error interrupt
|
||
|
*/
|
||
|
void dma_disable_bus_error_interrupt(void)
|
||
|
{
|
||
|
DMA_IEN &= ~DMA_IEN_ERR;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Enable channel done interrupt
|
||
|
* @param[in] ch Channel (use DMA_CHx)
|
||
|
*/
|
||
|
void dma_enable_done_interrupt(enum dma_ch ch)
|
||
|
{
|
||
|
DMA_IEN |= DMA_IEN_CHxDONE(ch);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Disable channel done interrupt
|
||
|
* @param[in] ch Channel (use DMA_CHx)
|
||
|
*/
|
||
|
void dma_disable_done_interrupt(enum dma_ch ch)
|
||
|
{
|
||
|
DMA_IEN &= ~DMA_IEN_CHxDONE(ch);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Set channel source
|
||
|
* @param[in] ch Channel (use DMA_CHx)
|
||
|
* @param[in] source Source (use DMA_CH_CTRL_SOURCESEL_*)
|
||
|
*/
|
||
|
void dma_set_source(enum dma_ch ch, uint32_t source)
|
||
|
{
|
||
|
DMA_CHx_CTRL(ch) = (DMA_CHx_CTRL(ch) & ~DMA_CH_CTRL_SOURCESEL_MASK)
|
||
|
| source;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Set channel source signal
|
||
|
* @param[in] ch Channel (use DMA_CHx)
|
||
|
* @param[in] signal Signal (use DMA_CH_CTRL_SIGSEL_*)
|
||
|
*/
|
||
|
void dma_set_signal(enum dma_ch ch, uint32_t signal)
|
||
|
{
|
||
|
DMA_CHx_CTRL(ch) = (DMA_CHx_CTRL(ch) & ~DMA_CH_CTRL_SIGSEL_MASK)
|
||
|
| signal;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Reset channel
|
||
|
* @param[in] ch Channel (use DMA_CHx)
|
||
|
*/
|
||
|
void dma_channel_reset(enum dma_ch ch)
|
||
|
{
|
||
|
/* Disable channel */
|
||
|
DMA_CHENC = DMA_CHENC_CHxSENC(ch);
|
||
|
/* reset channel alternate desc */
|
||
|
DMA_CHALTC = DMA_CHALTC_CHxSALTC(ch);
|
||
|
/* reset channel priority */
|
||
|
DMA_CHPRIC = DMA_CHPRIC_CHxSPRIC(ch);
|
||
|
/* clear channel interrupt */
|
||
|
DMA_IFC = DMA_IFC_CHxDONE(ch);
|
||
|
/* disable loop */
|
||
|
if (CHANNEL_SUPPORT_LOOP(ch)) {
|
||
|
DMA_LOOPx(ch) = 0;
|
||
|
}
|
||
|
/* reset signal {source, select} */
|
||
|
DMA_CHx_CTRL(ch) = 0;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Set channel loop width to ( @a count + 1)
|
||
|
* @param[in] ch Channel (use DMA_CHx)
|
||
|
* @param[in] count Count
|
||
|
* @note @a count is expected to be equal to (n_minus_1 + 1)
|
||
|
*/
|
||
|
void dma_set_loop_count(enum dma_ch ch, uint16_t count)
|
||
|
{
|
||
|
if (!CHANNEL_SUPPORT_LOOP(ch)) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
DMA_LOOPx(ch) = (DMA_LOOPx(ch) & ~DMA_LOOP_WIDTH_MASK)
|
||
|
| DMA_LOOP_WIDTH(count - 1);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Enable channel loop
|
||
|
* @param[in] ch Channel (use DMA_CHx)
|
||
|
*/
|
||
|
void dma_enable_loop(enum dma_ch ch)
|
||
|
{
|
||
|
if (!CHANNEL_SUPPORT_LOOP(ch)) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
DMA_LOOPx(ch) |= DMA_LOOP_EN;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Disable channel loop
|
||
|
* @param[in] ch Channel (use DMA_CHx)
|
||
|
*/
|
||
|
void dma_disable_loop(enum dma_ch ch)
|
||
|
{
|
||
|
if (!CHANNEL_SUPPORT_LOOP(ch)) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
DMA_LOOPx(ch) &= ~DMA_LOOP_EN;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Set desination size
|
||
|
* @param[in] desc_base start of memory location that contain channel
|
||
|
* descriptor
|
||
|
* @param[in] ch Channel (use DMA_CHx)
|
||
|
* @param[in] size Size (use DMA_MEM_*)
|
||
|
*/
|
||
|
void dma_desc_set_dest_size(uint32_t desc_base, enum dma_ch ch,
|
||
|
enum dma_mem size)
|
||
|
{
|
||
|
uint32_t cfg = DMA_DESC_CHx_CFG(desc_base, ch);
|
||
|
cfg &= ~DMA_DESC_CH_CFG_DEST_SIZE_MASK;
|
||
|
cfg |= DMA_DESC_CH_CFG_DEST_SIZE(size);
|
||
|
DMA_DESC_CHx_CFG(desc_base, ch) = cfg;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Set destination increment
|
||
|
* @param[in] desc_base start of memory location that contain channel
|
||
|
* descriptor
|
||
|
* @param[in] ch Channel (use DMA_CHx)
|
||
|
* @param[in] inc Increment (use DMA_MEM_*)
|
||
|
*/
|
||
|
void dma_desc_set_dest_inc(uint32_t desc_base, enum dma_ch ch,
|
||
|
enum dma_mem inc)
|
||
|
{
|
||
|
uint32_t cfg = DMA_DESC_CHx_CFG(desc_base, ch);
|
||
|
cfg &= ~DMA_DESC_CH_CFG_DEST_INC_MASK;
|
||
|
cfg |= DMA_DESC_CH_CFG_DEST_INC(inc);
|
||
|
DMA_DESC_CHx_CFG(desc_base, ch) = cfg;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Set source size
|
||
|
* @param[in] desc_base start of memory location that contain channel
|
||
|
* descriptor
|
||
|
* @param[in] ch Channel (use DMA_CHx)
|
||
|
* @param[in] size Size (use DMA_MEM_*)
|
||
|
*/
|
||
|
void dma_desc_set_src_size(uint32_t desc_base, enum dma_ch ch,
|
||
|
enum dma_mem size)
|
||
|
{
|
||
|
uint32_t cfg = DMA_DESC_CHx_CFG(desc_base, ch);
|
||
|
cfg &= ~DMA_DESC_CH_CFG_SRC_SIZE_MASK;
|
||
|
cfg |= DMA_DESC_CH_CFG_SRC_SIZE(size);
|
||
|
DMA_DESC_CHx_CFG(desc_base, ch) = cfg;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Set source increment
|
||
|
* @param[in] desc_base start of memory location that contain channel
|
||
|
* descriptor
|
||
|
* @param[in] ch Channel (use DMA_CHx)
|
||
|
* @param[in] inc Increment (use DMA_MEM_*)
|
||
|
*/
|
||
|
void dma_desc_set_src_inc(uint32_t desc_base, enum dma_ch ch, enum dma_mem inc)
|
||
|
{
|
||
|
|
||
|
uint32_t cfg = DMA_DESC_CHx_CFG(desc_base, ch);
|
||
|
cfg &= ~DMA_DESC_CH_CFG_SRC_INC_MASK;
|
||
|
cfg |= DMA_DESC_CH_CFG_SRC_INC(inc);
|
||
|
DMA_DESC_CHx_CFG(desc_base, ch) = cfg;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Set R Power
|
||
|
* @param[in] desc_base start of memory location that contain channel
|
||
|
* descriptor
|
||
|
* @param[in] ch Channel (use DMA_CHx)
|
||
|
* @param[in] r_power R Power (Use DMA_R_POWER_*)
|
||
|
*/
|
||
|
void dma_desc_set_r_power(uint32_t desc_base, enum dma_ch ch,
|
||
|
enum dma_r_power r_power)
|
||
|
{
|
||
|
uint32_t cfg = DMA_DESC_CHx_CFG(desc_base, ch);
|
||
|
cfg &= ~DMA_DESC_CH_CFG_R_POWER_MASK;
|
||
|
cfg |= DMA_DESC_CH_CFG_R_POWER(r_power);
|
||
|
DMA_DESC_CHx_CFG(desc_base, ch) = cfg;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Enable next useburst
|
||
|
* @param[in] desc_base start of memory location that contain channel
|
||
|
* descriptor
|
||
|
* @param[in] ch Channel (use DMA_CHx)
|
||
|
*/
|
||
|
void dma_desc_enable_next_useburst(uint32_t desc_base, enum dma_ch ch)
|
||
|
{
|
||
|
DMA_DESC_CHx_CFG(desc_base, ch) &= ~DMA_DESC_CH_CFG_NEXT_USEBURST;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Disable next useburst
|
||
|
* @param[in] desc_base start of memory location that contain channel
|
||
|
* descriptor
|
||
|
* @param[in] ch Channel (use DMA_CHx)
|
||
|
*/
|
||
|
void dma_desc_disable_next_useburst(uint32_t desc_base, enum dma_ch ch)
|
||
|
{
|
||
|
DMA_DESC_CHx_CFG(desc_base, ch) |= DMA_DESC_CH_CFG_NEXT_USEBURST;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Set number (count) of transfer to be performed
|
||
|
* @param[in] desc_base start of memory location that contain channel
|
||
|
* descriptor
|
||
|
* @param[in] ch Channel (use DMA_CHx)
|
||
|
* @param[in] count Count
|
||
|
*/
|
||
|
void dma_desc_set_count(uint32_t desc_base, enum dma_ch ch, uint16_t count)
|
||
|
{
|
||
|
uint32_t cfg = DMA_DESC_CHx_CFG(desc_base, ch);
|
||
|
cfg &= ~DMA_DESC_CH_CFG_N_MINUS_1_MASK;
|
||
|
cfg |= DMA_DESC_CH_CFG_N_MINUS_1(count - 1);
|
||
|
DMA_DESC_CHx_CFG(desc_base, ch) = cfg;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Store user data field in channel descriptor
|
||
|
* @param[in] desc_base start of memory location that contain channel
|
||
|
* descriptor
|
||
|
* @param[in] ch Channel (use DMA_CHx)
|
||
|
* @param[in] user_data User data
|
||
|
*/
|
||
|
void dma_desc_set_user_data(uint32_t desc_base, enum dma_ch ch,
|
||
|
uint32_t user_data)
|
||
|
{
|
||
|
DMA_DESC_CHx_USER_DATA(desc_base, ch) = user_data;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Extract user data field from channel descriptor
|
||
|
* @param[in] desc_base start of memory location that contain channel
|
||
|
* descriptor
|
||
|
* @param[in] ch Channel (use DMA_CHx)
|
||
|
* @return user data
|
||
|
*/
|
||
|
uint32_t dma_desc_get_user_data(uint32_t desc_base, enum dma_ch ch)
|
||
|
{
|
||
|
return DMA_DESC_CHx_USER_DATA(desc_base, ch);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Calculate end from start address.
|
||
|
*
|
||
|
* @details
|
||
|
* See "8.4.3.4 Address calculation" p68, EFM32LG-RM "d0183_Rev1.10"
|
||
|
*
|
||
|
* @param[in] start address to start of memory
|
||
|
* @param[in] inc Increment (use DMA_MEM_*)
|
||
|
* @param[in] n_minus_1 the number of transfers minus 1 (ie count - 1)
|
||
|
* @return the calculate end address
|
||
|
* @note can be used to calculate {source, destination} end address
|
||
|
*/
|
||
|
static inline uint32_t dma_calc_end_from_start(uint32_t start, uint8_t inc,
|
||
|
uint16_t n_minus_1)
|
||
|
{
|
||
|
switch (inc) {
|
||
|
case DMA_MEM_BYTE:
|
||
|
return start + n_minus_1;
|
||
|
case DMA_MEM_HALF_WORD:
|
||
|
return start + (n_minus_1 << 1);
|
||
|
case DMA_MEM_WORD:
|
||
|
return start + (n_minus_1 << 2);
|
||
|
case DMA_MEM_NONE:
|
||
|
return start;
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Assign Source address to DMA Channel
|
||
|
* @param[in] desc_base start of memory location that contain channel
|
||
|
* descriptor
|
||
|
* @param[in] ch Channel (use DMA_CHx)
|
||
|
* @param[in] src_start Source data start address
|
||
|
* this function uses @ref dma_calc_end_from_start to calculate the
|
||
|
* src data end address from @a src_start
|
||
|
* @note dma_desc_set_count() should be called first.
|
||
|
* @note dma_desc_set_src_inc() should be called first.
|
||
|
*/
|
||
|
void dma_desc_set_src_address(uint32_t desc_base, enum dma_ch ch,
|
||
|
uint32_t src_start)
|
||
|
{
|
||
|
uint32_t cfg = DMA_DESC_CHx_CFG(desc_base, ch);
|
||
|
uint8_t inc = (cfg & DMA_DESC_CH_CFG_SRC_INC_MASK)
|
||
|
>> DMA_DESC_CH_CFG_SRC_INC_SHIFT;
|
||
|
uint16_t n_minus_1 = (cfg & DMA_DESC_CH_CFG_N_MINUS_1_MASK)
|
||
|
>> DMA_DESC_CH_CFG_N_MINUS_1_SHIFT;
|
||
|
uint32_t src_end = dma_calc_end_from_start(src_start, inc, n_minus_1);
|
||
|
DMA_DESC_CHx_SRC_DATA_END_PTR(desc_base, ch) = src_end;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Assign Destination address to DMA Channel
|
||
|
* @param[in] desc_base start of memory location that contain channel
|
||
|
* descriptor
|
||
|
* @param[in] ch Channel (use DMA_CHx)
|
||
|
* @param[in] dest_start Destination data start address
|
||
|
* this function uses @ref dma_calc_end_from_start to calculate the
|
||
|
* dest data end address from @a dest_start
|
||
|
* @note dma_desc_set_count() should be called first.
|
||
|
* @note dma_desc_set_dest_inc() should be called first.
|
||
|
*/
|
||
|
void dma_desc_set_dest_address(uint32_t desc_base, enum dma_ch ch,
|
||
|
uint32_t dest_start)
|
||
|
{
|
||
|
uint32_t cfg = DMA_DESC_CHx_CFG(desc_base, ch);
|
||
|
uint8_t inc = (cfg & DMA_DESC_CH_CFG_DEST_INC_MASK)
|
||
|
>> DMA_DESC_CH_CFG_DEST_INC_SHIFT;
|
||
|
uint16_t n_minus_1 = (cfg & DMA_DESC_CH_CFG_N_MINUS_1_MASK)
|
||
|
>> DMA_DESC_CH_CFG_N_MINUS_1_SHIFT;
|
||
|
uint32_t dest_end = dma_calc_end_from_start(dest_start, inc,
|
||
|
n_minus_1);
|
||
|
DMA_DESC_CHx_DEST_DATA_END_PTR(desc_base, ch) = dest_end;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Set the channel mode ("Cycle control")
|
||
|
* @param[in] desc_base start of memory location that contain channel
|
||
|
* descriptor
|
||
|
* @param[in] ch Channel (use DMA_CHx)
|
||
|
* @param[in] mode Mode (use DMA_MODE_*)
|
||
|
*/
|
||
|
void dma_desc_set_mode(uint32_t desc_base, enum dma_ch ch, enum dma_mode mode)
|
||
|
{
|
||
|
uint32_t cfg = DMA_DESC_CHx_CFG(desc_base, ch);
|
||
|
cfg &= ~DMA_DESC_CH_CFG_CYCLE_CTRL_MASK;
|
||
|
cfg |= DMA_DESC_CH_CFG_CYCLE_CTRL(mode);
|
||
|
DMA_DESC_CHx_CFG(desc_base, ch) = cfg;
|
||
|
}
|
||
|
|
||
|
/**@}*/
|