hpw421初始版本
This commit is contained in:
@@ -0,0 +1,839 @@
|
||||
/*!
|
||||
* \file xc_drv_dma.c
|
||||
*
|
||||
* \brief Target xinchip dma driver implementation
|
||||
*
|
||||
* \copyright Revised BSD License, see section \ref LICENSE.
|
||||
*
|
||||
* \code
|
||||
*
|
||||
* _ __ _ ________ _
|
||||
* | |/ /(_)___ / ____/ /_ (_)___
|
||||
* | // / __ \/ / / __ \/ / __ \
|
||||
* / |/ / / / / /___/ / / / / /_/ /
|
||||
* /_/|_/_/_/ /_/\____/_/ /_/_/ .___/
|
||||
* /_/
|
||||
* (C) 2022-2025 XinChip
|
||||
*
|
||||
* \endcode
|
||||
*
|
||||
* \author ( XinChip ) Alex-J
|
||||
*
|
||||
* \author ( XinChip )
|
||||
*/
|
||||
|
||||
/*-----------------------------------------------------------------------------------
|
||||
INCLUDE HEADE FILES
|
||||
------------------------------------------------------------------------------------*/
|
||||
#include "xc_drv_dma.h"
|
||||
|
||||
/*------------------------------------------------------------------------------------
|
||||
Global Variables
|
||||
-------------------------------------------------------------------------------------*/
|
||||
DMA_Instance_t DMA_Instance;
|
||||
|
||||
/*------------------------------------------------------------------------------------
|
||||
Functions
|
||||
-------------------------------------------------------------------------------------*/
|
||||
/**
|
||||
* @brief xc_dma_set_test_mode
|
||||
* @details DMAC test mode set
|
||||
*
|
||||
* @param uint8_t - mode
|
||||
* @return void
|
||||
* @retval void
|
||||
* @retval void
|
||||
* @note
|
||||
*/
|
||||
__RAM_CODE void xc_dma_set_test_mode(uint8_t mode)
|
||||
{
|
||||
dma_test_reg_set(mode);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief xc_dma_set_channel_priority_order
|
||||
* @details
|
||||
*
|
||||
* @param
|
||||
* @param
|
||||
* @return void
|
||||
* @retval void
|
||||
* @retval void
|
||||
* @note
|
||||
*/
|
||||
__RAM_CODE void xc_dma_set_channel_priority_order(DMA_Instance_t *inst)
|
||||
{
|
||||
uint8_t priority[DMA_MAX_CHANNELS];
|
||||
uint8_t i, ch_priority, order;
|
||||
|
||||
for (i = 0; i < DMA_MAX_CHANNELS; i++) {
|
||||
priority[i] = 0;
|
||||
inst->Ch_Order[i] = i;
|
||||
}
|
||||
|
||||
for (uint8_t ch_num = 0; ch_num < DMA_MAX_CHANNELS; ch_num++) {
|
||||
// read the priority of the current channel
|
||||
ch_priority = dma_cfg_l__ch_prior__getf(ch_num);
|
||||
|
||||
// Check the channel order array to see what position
|
||||
// this channel comes in the priority list.
|
||||
for (i = 0; i <= DMA_MAX_CHANNELS; i++) {
|
||||
if (A_MAXEQ_B(ch_priority, priority[i]) || i == DMA_MAX_CHANNELS) {
|
||||
order = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Now we know the order for this channel insert in the correct
|
||||
// array position and shift current priority ordering to suite.
|
||||
for (i = ch_num; i > order; i--) {
|
||||
priority[i] = priority[i - 1];
|
||||
inst->Ch_Order[i] = inst->Ch_Order[i - 1];
|
||||
}
|
||||
priority[order] = ch_priority;
|
||||
inst->Ch_Order[order] = ch_num;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief xc_dma_reset_instance
|
||||
* @details
|
||||
*
|
||||
* @param
|
||||
* @param
|
||||
* @return void
|
||||
* @retval void
|
||||
* @retval void
|
||||
* @note
|
||||
*/
|
||||
__RAM_CODE void xc_dma_reset_instance(DMA_Instance_t *inst)
|
||||
{
|
||||
for (uint8_t i = 0; i < DMA_MAX_CHANNELS; i++) {
|
||||
switch (i) {
|
||||
case 0:
|
||||
inst->Ch[i].ch_num = DMA_CHANNEL0;
|
||||
break;
|
||||
case 1:
|
||||
inst->Ch[i].ch_num = DMA_CHANNEL1;
|
||||
break;
|
||||
// case 2:
|
||||
// inst->Ch[i].ch_num = DMA_CHANNEL2;
|
||||
// break;
|
||||
// case 3:
|
||||
// inst->Ch[i].ch_num = DMA_CHANNEL3;
|
||||
// break;
|
||||
}
|
||||
|
||||
inst->Ch[i].userCallback = NULL;
|
||||
inst->Ch[i].userListener = NULL;
|
||||
}
|
||||
|
||||
// Set the channel priority order
|
||||
xc_dma_set_channel_priority_order(inst);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief xc_dma_check_channel_range
|
||||
* @details
|
||||
*
|
||||
* @param
|
||||
* @param
|
||||
* @return void
|
||||
* @retval void
|
||||
* @retval void
|
||||
* @note
|
||||
*/
|
||||
__RAM_CODE uint8_t xc_dma_check_channel_range(eDMA_Ch_Num ch_num)
|
||||
{
|
||||
uint8_t errorCode = DMA_OK;
|
||||
|
||||
if (ch_num == DMA_NO_CHANNEL || ch_num > DMA_ALL_CHANNELS) {
|
||||
errorCode = DMA_ECHRNG;
|
||||
}
|
||||
|
||||
return errorCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief xc_dma_check_channel_busy
|
||||
* @details
|
||||
*
|
||||
* @param
|
||||
* @param
|
||||
* @return void
|
||||
* @retval void
|
||||
* @retval void
|
||||
* @note
|
||||
*/
|
||||
__RAM_CODE uint8_t xc_dma_check_channel_busy(eDMA_Ch_Num ch_num)
|
||||
{
|
||||
uint8_t errorCode = DMA_OK;
|
||||
|
||||
if (ch_num == DMA_NO_CHANNEL || ch_num & (~DMA_ALL_CHANNELS)) {
|
||||
errorCode = DMA_ECHRNG;
|
||||
} else {
|
||||
if (((uint16_t)dma_ch_en_reg_get( )) & ch_num) {
|
||||
errorCode = DMA_EBUSY;
|
||||
}
|
||||
}
|
||||
|
||||
return errorCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief xc_dma_get_channel_index
|
||||
* @details
|
||||
*
|
||||
* @param
|
||||
* @param
|
||||
* @return void
|
||||
* @retval void
|
||||
* @retval void
|
||||
* @note
|
||||
*/
|
||||
__RAM_CODE uint8_t xc_dma_get_channel_index(eDMA_Ch_Num ch_num)
|
||||
{
|
||||
uint8_t ch_enum = 1;
|
||||
uint8_t ch_index = 0;
|
||||
|
||||
ch_num &= (DMA_ALL_CHANNELS >> 8);
|
||||
while (ch_index < DMA_MAX_CHANNELS) {
|
||||
if (ch_enum == ch_num) {
|
||||
break;
|
||||
}
|
||||
ch_enum *= 2;
|
||||
ch_index++;
|
||||
}
|
||||
|
||||
return ch_index;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief xc_dma_enable
|
||||
* @details
|
||||
*
|
||||
* @param
|
||||
* @param
|
||||
* @return void
|
||||
* @retval void
|
||||
* @retval void
|
||||
* @note
|
||||
*/
|
||||
__RAM_CODE void xc_dma_enable(void) { dma_cfg_reg_set(ENABLE); }
|
||||
|
||||
/**
|
||||
* @brief xc_dma_disable
|
||||
* @details
|
||||
*
|
||||
* @param
|
||||
* @param
|
||||
* @return void
|
||||
* @retval void
|
||||
* @retval void
|
||||
* @note
|
||||
*/
|
||||
__RAM_CODE uint8_t xc_dma_disable(void)
|
||||
{
|
||||
uint8_t errorCode = 0;
|
||||
uint8_t dma_en = dma_cfg_reg__dma_en__getf( );
|
||||
|
||||
if (dma_en != 0) {
|
||||
dma_cfg_reg_set(DISABLE);
|
||||
|
||||
// Ensure that the DMA was disabled
|
||||
// May not disable due to split response on one
|
||||
// of the DMA channels
|
||||
if (dma_cfg_reg_get( )) {
|
||||
errorCode = DMA_EBUSY;
|
||||
}
|
||||
}
|
||||
|
||||
return errorCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief xc_dma_is_enable
|
||||
* @details
|
||||
*
|
||||
* @param
|
||||
* @param
|
||||
* @return void
|
||||
* @retval void
|
||||
* @retval void
|
||||
* @note
|
||||
*/
|
||||
bool xc_dma_is_enable(void)
|
||||
{
|
||||
bool ret;
|
||||
|
||||
ret = (bool)dma_cfg_reg__dma_en__getf( );
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief xc_dma_enable_channel
|
||||
* @details
|
||||
*
|
||||
* @param
|
||||
* @param
|
||||
* @return void
|
||||
* @retval void
|
||||
* @retval void
|
||||
* @note
|
||||
*/
|
||||
__RAM_CODE uint8_t xc_dma_enable_channel(eDMA_Ch_Num ch_num)
|
||||
{
|
||||
uint8_t errorCode = 0;
|
||||
|
||||
// Check for valid channel number and not busy
|
||||
errorCode = xc_dma_check_channel_busy(ch_num);
|
||||
if (errorCode == 0) {
|
||||
// The dw_dmac_channel_number enum is declared such that
|
||||
// the enumerated value maps exactly to the value that
|
||||
// needs to be written into the ChEnReg for enabling.
|
||||
dma_ch_en_reg_set(ch_num);
|
||||
}
|
||||
|
||||
return errorCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief xc_dma_disable_channel
|
||||
* @details
|
||||
*
|
||||
* @param
|
||||
* @param
|
||||
* @return void
|
||||
* @retval void
|
||||
* @retval void
|
||||
* @note
|
||||
*/
|
||||
__RAM_CODE uint8_t xc_dma_disable_channel(eDMA_Ch_Num ch_num)
|
||||
{
|
||||
uint8_t errorCode = 0;
|
||||
uint32_t enabled_ch;
|
||||
|
||||
// Check for valid channel number
|
||||
errorCode = xc_dma_check_channel_range(ch_num);
|
||||
|
||||
if (errorCode == 0) {
|
||||
enabled_ch = (dma_ch_en_reg_get( ) & ch_num);
|
||||
if (enabled_ch != 0) {
|
||||
dma_ch_en_reg_set((ch_num & (DMA_ALL_CHANNELS << 8)));
|
||||
|
||||
// Ensure that the channel(s) was disabled.
|
||||
// Channel may not disable due to a split response.
|
||||
if (dma_ch_en_reg_get( ) & ch_num) {
|
||||
errorCode = DMA_EBUSY;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return errorCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief xc_dma_is_channel_enabled
|
||||
* @details
|
||||
*
|
||||
* @param
|
||||
* @param
|
||||
* @return void
|
||||
* @retval void
|
||||
* @retval void
|
||||
* @note
|
||||
*/
|
||||
bool xc_dma_is_channel_enabled(eDMA_Ch_Num ch_num)
|
||||
{
|
||||
uint8_t ch_index;
|
||||
bool ret;
|
||||
|
||||
ch_index = xc_dma_get_channel_index(ch_num);
|
||||
|
||||
// Allow only ONE channel to be specified
|
||||
if (ch_index == DMA_MAX_CHANNELS)
|
||||
return false;
|
||||
|
||||
// Check that the specified channel is in range
|
||||
if (ch_num & (~DMA_ALL_CHANNELS))
|
||||
return false;
|
||||
|
||||
ret = (bool)REG_BIT_VAL_GET(dma_ch_en_reg__ch_en__getf( ), 1 << ch_index, ch_index);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief xc_dma_enable_channel_irq
|
||||
* @details
|
||||
*
|
||||
* @param
|
||||
* @param
|
||||
* @return void
|
||||
* @retval void
|
||||
* @retval void
|
||||
* @note
|
||||
*/
|
||||
__RAM_CODE uint8_t xc_dma_enable_channel_irq(eDMA_Ch_Num ch_num)
|
||||
{
|
||||
uint8_t errorCode = DMA_OK;
|
||||
|
||||
// Check for valid channel number and not busy
|
||||
errorCode = xc_dma_check_channel_busy(ch_num);
|
||||
|
||||
if (errorCode == 0) {
|
||||
// Loop through each channel in turn and disable
|
||||
// the channel Irq for the selected channels.
|
||||
for (uint8_t x = 0; x < DMA_MAX_CHANNELS; x++) {
|
||||
if (ch_num & (1 << x)) {
|
||||
if (dma_ctl_l__int_en__getf(x) != 0x1) {
|
||||
dma_ctl_l__int_en__setf(x, ENABLE);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return errorCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief xc_dma_disable_channel_irq
|
||||
* @details
|
||||
*
|
||||
* @param
|
||||
* @param
|
||||
* @return void
|
||||
* @retval void
|
||||
* @retval void
|
||||
* @note
|
||||
*/
|
||||
__RAM_CODE uint8_t xc_dma_disable_channel_irq(eDMA_Ch_Num ch_num)
|
||||
{
|
||||
uint8_t errorCode = DMA_OK;
|
||||
|
||||
// Check for valid channel number and not busy
|
||||
errorCode = xc_dma_check_channel_busy(ch_num);
|
||||
|
||||
if (errorCode == 0) {
|
||||
// Loop through each channel in turn and disable
|
||||
// the channel Irq for the selected channels.
|
||||
for (uint8_t x = 0; x < DMA_MAX_CHANNELS; x++) {
|
||||
if (ch_num & (1 << x)) {
|
||||
if (dma_ctl_l__int_en__getf(x) != 0x0) {
|
||||
dma_ctl_l__int_en__setf(x, DISABLE);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return errorCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief xc_dma_mask_irq
|
||||
* @details
|
||||
*
|
||||
* @param
|
||||
* @param
|
||||
* @return void
|
||||
* @retval void
|
||||
* @retval void
|
||||
* @note
|
||||
*/
|
||||
__RAM_CODE uint8_t xc_dma_mask_irq(eDMA_Ch_Num ch_num, eDMA_Irq ch_irq)
|
||||
{
|
||||
uint8_t errorCode = DMA_OK;
|
||||
uint16_t reg;
|
||||
|
||||
// Check for valid channel number
|
||||
errorCode = xc_dma_check_channel_range(ch_num);
|
||||
if (errorCode == 0) {
|
||||
// Loop through and clear the selected channel Irq
|
||||
// for the targeted channels.
|
||||
reg = (ch_num & (DMA_ALL_CHANNELS << 8));
|
||||
for (uint8_t x = 0; x < DMA_MAX_INTERRUPTS; x++) {
|
||||
if (ch_irq & (1 << x)) {
|
||||
switch (x) {
|
||||
case 0:
|
||||
dma_mask_tfr_set(reg);
|
||||
break;
|
||||
case 1:
|
||||
dma_mask_block_set(reg);
|
||||
break;
|
||||
case 2:
|
||||
dma_mask_src_tran_set(reg);
|
||||
break;
|
||||
case 3:
|
||||
dma_mask_dst_tran_set(reg);
|
||||
break;
|
||||
case 4:
|
||||
dma_mask_err_set(reg);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return errorCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief xc_dma_unmask_irq
|
||||
* @details
|
||||
*
|
||||
* @param
|
||||
* @param
|
||||
* @return void
|
||||
* @retval void
|
||||
* @retval void
|
||||
* @note
|
||||
*/
|
||||
uint8_t xc_dma_unmask_irq(eDMA_Ch_Num ch_num, eDMA_Irq ch_irq)
|
||||
{
|
||||
uint8_t errorCode = DMA_OK;
|
||||
uint16_t reg;
|
||||
|
||||
// Check for valid channel number
|
||||
errorCode = xc_dma_check_channel_range(ch_num);
|
||||
if (errorCode == 0) {
|
||||
// Loop through and clear the selected channel Irq
|
||||
// for the targeted channels.
|
||||
reg = ch_num;
|
||||
for (uint8_t x = 0; x < DMA_MAX_INTERRUPTS; x++) {
|
||||
if (ch_irq & (1 << x)) {
|
||||
switch (x) {
|
||||
case 0:
|
||||
dma_mask_tfr_set(reg);
|
||||
break;
|
||||
case 1:
|
||||
dma_mask_block_set(reg);
|
||||
break;
|
||||
case 2:
|
||||
dma_mask_src_tran_set(reg);
|
||||
break;
|
||||
case 3:
|
||||
dma_mask_dst_tran_set(reg);
|
||||
break;
|
||||
case 4:
|
||||
dma_mask_err_set(reg);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return errorCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief xc_dma_clear_irq
|
||||
* @details
|
||||
*
|
||||
* @param
|
||||
* @param
|
||||
* @return void
|
||||
* @retval void
|
||||
* @retval void
|
||||
* @note
|
||||
*/
|
||||
__RAM_CODE uint8_t xc_dma_clear_irq(eDMA_Ch_Num ch_num, eDMA_Irq ch_irq)
|
||||
{
|
||||
uint8_t errorCode = DMA_OK;
|
||||
uint16_t reg;
|
||||
|
||||
// Check for valid channel number
|
||||
errorCode = xc_dma_check_channel_range(ch_num);
|
||||
if (errorCode == 0) {
|
||||
// Loop through and clear the selected channel Irq
|
||||
// for the targeted channels.
|
||||
reg = (ch_num & (DMA_ALL_CHANNELS >> 8));
|
||||
for (uint8_t x = 0; x < DMA_MAX_INTERRUPTS; x++) {
|
||||
if (ch_irq & (1 << x)) {
|
||||
switch (x) {
|
||||
case 0:
|
||||
dma_clear_tfr_set(reg);
|
||||
break;
|
||||
case 1:
|
||||
dma_clear_block_set(reg);
|
||||
break;
|
||||
case 2:
|
||||
dma_clear_src_tran_set(reg);
|
||||
break;
|
||||
case 3:
|
||||
dma_clear_dst_tran_set(reg);
|
||||
break;
|
||||
case 4:
|
||||
dma_clear_err_set(reg);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return errorCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief xc_dma_init
|
||||
* @details
|
||||
*
|
||||
* @param
|
||||
* @param
|
||||
* @return void
|
||||
* @retval void
|
||||
* @retval void
|
||||
* @note
|
||||
*/
|
||||
__RAM_CODE uint8_t xc_dma_init(void)
|
||||
{
|
||||
// Remove from test mode
|
||||
xc_dma_set_test_mode(DISABLE);
|
||||
// Reset the DMA instance structure
|
||||
xc_dma_reset_instance(&DMA_Instance);
|
||||
// Disable the DMA controller
|
||||
uint8_t errorCode = xc_dma_disable( );
|
||||
if (errorCode == 0) {
|
||||
// Disable all DMA channels
|
||||
errorCode = xc_dma_disable_channel(DMA_ALL_CHANNELS);
|
||||
}
|
||||
|
||||
if (errorCode == 0) {
|
||||
// Disable all channel interrupts
|
||||
errorCode = xc_dma_disable_channel_irq(DMA_ALL_CHANNELS);
|
||||
}
|
||||
|
||||
if (errorCode == 0) {
|
||||
// Mask all channel interrupts
|
||||
errorCode = xc_dma_mask_irq(DMA_ALL_CHANNELS, DMA_IRQ_ALL);
|
||||
}
|
||||
|
||||
if (errorCode == 0) {
|
||||
// Clear any pending interrupts
|
||||
errorCode = xc_dma_clear_irq(DMA_ALL_CHANNELS, DMA_IRQ_ALL);
|
||||
}
|
||||
|
||||
return errorCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief xc_dma_set_channel_config
|
||||
* @details
|
||||
*
|
||||
* @param
|
||||
* @param
|
||||
* @return void
|
||||
* @retval void
|
||||
* @retval void
|
||||
* @note
|
||||
*/
|
||||
__RAM_CODE uint8_t xc_dma_set_channel_config(eDMA_Ch_Num ch_num,
|
||||
DMA_Chx_Cfg_t *ch)
|
||||
{
|
||||
uint8_t errorCode;
|
||||
uint8_t ch_index;
|
||||
|
||||
ch_index = xc_dma_get_channel_index(ch_num);
|
||||
|
||||
// Check for valid channel number and not busy
|
||||
errorCode = xc_dma_check_channel_busy(ch_num);
|
||||
if (errorCode == 0) {
|
||||
// Set the control register
|
||||
dma_ctl_l_pack(ch_index, ch->ctl_tt_fc, ch->ctl_src_msize, ch->ctl_dst_msize,
|
||||
ch->ctl_sinc, ch->ctl_dinc, ch->ctl_src_tr_width, ch->ctl_dst_tr_width,
|
||||
0);
|
||||
|
||||
dma_ctl_h__block_ts__setf(ch_index, ch->ctl_block_ts);
|
||||
|
||||
// Set the config register
|
||||
dma_cfg_l__hs_sel_src__setf(ch_index, ch->cfg_hs_sel_src);
|
||||
dma_cfg_l__hs_sel_dst__setf(ch_index, ch->cfg_hs_sel_dst);
|
||||
|
||||
dma_cfg_h_pack(ch_index, (ch->cfg_dst_per & 0xf), (ch->cfg_src_per & 0xf), (ch->cfg_fifo_mode & 0x1));
|
||||
|
||||
// set the SAR/DAR registers
|
||||
dma_sar_set(ch_index, ch->sar);
|
||||
dma_dar_set(ch_index, ch->dar);
|
||||
};
|
||||
|
||||
return errorCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief xc_dma_set_listener
|
||||
* @details
|
||||
*
|
||||
* @param
|
||||
* @param
|
||||
* @return void
|
||||
* @retval void
|
||||
* @retval void
|
||||
* @note
|
||||
*/
|
||||
__RAM_CODE bool xc_dma_set_listener(eDMA_Ch_Num ch_num,
|
||||
DMA_Callback userFunction)
|
||||
{
|
||||
uint8_t ch_index;
|
||||
DMA_Instance_t *inst = &DMA_Instance;
|
||||
|
||||
ch_index = xc_dma_get_channel_index(ch_num);
|
||||
|
||||
// Allow only ONE channel to be specified
|
||||
if (ch_index == DMA_MAX_CHANNELS)
|
||||
return false;
|
||||
|
||||
// Check that the specified channel is in range
|
||||
if (ch_num & (~DMA_ALL_CHANNELS))
|
||||
return false;
|
||||
|
||||
inst->Ch[ch_index].userListener = userFunction;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief xc_dma_start_transfer
|
||||
* @details
|
||||
*
|
||||
* @param
|
||||
* @param
|
||||
* @return void
|
||||
* @retval void
|
||||
* @retval void
|
||||
* @note
|
||||
*/
|
||||
__RAM_CODE uint8_t xc_dma_start_transfer(eDMA_Ch_Num ch_num, DMA_Callback cb_func)
|
||||
{
|
||||
uint8_t errorCode;
|
||||
uint8_t ch_index;
|
||||
|
||||
DMA_Instance_t *inst = &DMA_Instance;
|
||||
// Update the channel instance
|
||||
ch_index = xc_dma_get_channel_index(ch_num);
|
||||
|
||||
// Allow only ONE channel to be specified
|
||||
if (ch_index == DMA_MAX_CHANNELS) {
|
||||
errorCode = DMA_ECHRNG;
|
||||
} else {
|
||||
// Check for valid channel number and not busy
|
||||
errorCode = xc_dma_check_channel_busy(ch_num);
|
||||
}
|
||||
|
||||
if (errorCode == 0) {
|
||||
// Disable the channels interrupts
|
||||
errorCode = xc_dma_disable_channel_irq(ch_num);
|
||||
}
|
||||
|
||||
if (errorCode == 0) {
|
||||
// set the call back function, the number of blocks
|
||||
// in the transfer and the source and destination states.
|
||||
inst->Ch[ch_index].userCallback = cb_func;
|
||||
|
||||
// always want to unmask the tfr, block and err interrupts
|
||||
xc_dma_unmask_irq(ch_num, DMA_IRQ_TRF);
|
||||
xc_dma_unmask_irq(ch_num, DMA_IRQ_ERR);
|
||||
|
||||
// Enable the channel interrupts for the type of transfer
|
||||
errorCode = xc_dma_enable_channel_irq(ch_num);
|
||||
|
||||
if (errorCode == 0) {
|
||||
// Enable the DMA channel
|
||||
errorCode = xc_dma_enable_channel(ch_num);
|
||||
}
|
||||
}
|
||||
|
||||
return errorCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief dma_irq_handler
|
||||
* @details
|
||||
*
|
||||
* @param
|
||||
* @param
|
||||
* @return void
|
||||
* @retval void
|
||||
* @retval void
|
||||
* @note
|
||||
*/
|
||||
__RAM_CODE bool dma_irq_handler(DMA_Instance_t *inst)
|
||||
{
|
||||
bool retval;
|
||||
uint8_t i, ch_index, callbackArg;
|
||||
uint32_t reg, mask;
|
||||
DMA_Callback userCallback;
|
||||
|
||||
// Assume an interrupt will be processed. The return value will be
|
||||
// set to false if an active interrupt is not found.
|
||||
retval = true;
|
||||
|
||||
// ERR INTERRUPT
|
||||
if (dma_status_int__err__getf( )) {
|
||||
reg = dma_status_err_get( );
|
||||
|
||||
// Loop through the channels until we find
|
||||
// active interrupt. We start at the highest priority
|
||||
// channel and work down to the lowest priority.
|
||||
for (i = 0; i < DMA_MAX_CHANNELS; i++) {
|
||||
mask = 1 << inst->Ch_Order[i];
|
||||
if (reg & mask) {
|
||||
ch_index = inst->Ch_Order[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// run the listener function
|
||||
if (inst->Ch[ch_index].userListener != NULL) {
|
||||
userCallback = inst->Ch[ch_index].userListener;
|
||||
callbackArg = DMA_IRQ_ERR;
|
||||
userCallback(callbackArg);
|
||||
}
|
||||
|
||||
// clear the interrupt
|
||||
dma_clear_err_set(mask);
|
||||
}
|
||||
// TFR INTERRUPT
|
||||
else if (dma_status_int__tfr__getf( )) {
|
||||
reg = dma_status_tfr_get( );
|
||||
|
||||
// Loop through the channels until we find
|
||||
// active interrupt. We start at the highest priority
|
||||
// channel and work down to the lowest priority.
|
||||
for (i = 0; i < DMA_MAX_CHANNELS; i++) {
|
||||
mask = 1 << inst->Ch_Order[i];
|
||||
if (reg & mask) {
|
||||
ch_index = inst->Ch_Order[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Disable all channel interrupts
|
||||
xc_dma_disable_channel_irq(inst->Ch[ch_index].ch_num);
|
||||
|
||||
// clear any pending block/srcTran/dstTran interrupts
|
||||
dma_clear_block_set(mask);
|
||||
dma_clear_src_tran_set(mask);
|
||||
dma_clear_dst_tran_set(mask);
|
||||
xc_dma_clear_irq(inst->Ch[ch_index].ch_num, DMA_IRQ_TRF);
|
||||
|
||||
// Mask all channel interrupts
|
||||
xc_dma_mask_irq(inst->Ch[ch_index].ch_num, DMA_IRQ_ALL);
|
||||
|
||||
// run the callback function
|
||||
if (inst->Ch[ch_index].userCallback != NULL) {
|
||||
userCallback = inst->Ch[ch_index].userCallback;
|
||||
callbackArg = 0;
|
||||
userCallback(callbackArg);
|
||||
}
|
||||
|
||||
} else {
|
||||
// If we've reached this point, either the enabling and
|
||||
// disabling of DW_ahb_dmac interrupts is not being handled
|
||||
// properly or this function is being called unnecessarily.
|
||||
retval = false;
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
__RAM_CODE void DMA_Handler(void) { dma_irq_handler(&DMA_Instance); }
|
||||
Reference in New Issue
Block a user