在使用单片机搬运大量数据时,DMA是一个得力的助手,不需要占用 CPU。
瑞萨MCU中有两类DMA,DMAC和DTC
DMAC(Direct Memory Access Controller)为直接存储器访问控制器或者直接内存访问控制器, 可以在不占用 CPU 的情况下将数据从一个内存位置传输到另一个内存位置。
DTC(Data Transfer Controller)为数据传输控制器,用于在被中断请求激活时传输数据。 DTC 也可以在不占用 CPU 的情况下将数据传输,它的功能与 DMAC 的功能其实是相似的。
这里我们简单介绍下DMAC怎么配置以及使用


传输模式选择正常模式
数据大小一字节
目标地址和源地址选择自增
触发源选择 NO ELC,即使用软件触发
主要代码
uint8_t Destination[10];
uint8_t Source[10];
void hal_entry(void)
{
fsp_err_t err;
err = SysTick_Init();
assert(FSP_SUCCESS == err);
for(uint8_t i = 0;i < 10;i++)
{
Source[i] = i;
}
err = g_transfer0.p_api->open(g_transfer0.p_ctrl,g_transfer0.p_cfg);
assert(FSP_SUCCESS == err);
err = g_transfer0.p_api->reset(g_transfer0.p_ctrl,Source,Destination,10);
assert(FSP_SUCCESS == err);
err = g_transfer0.p_api->softwareStart(g_transfer0.p_ctrl,TRANSFER_START_MODE_REPEAT);
assert(FSP_SUCCESS == err);
while(1){}
}
void dmac_callback(dmac_callback_args_t *p_args)
{
(void)(p_args);
}
使用softwareStart这个API的时候,我踩了个坑,需要选择TRANSFER_START_MODE_REPEAT,如果选择TRANSFER_START_MODE_SINGLE将只传输一个数据
如果想要不通过RASC重新配置传输参数,可以用以下方式
transfer_info_t transfer_info =
{
.transfer_settings_word_b.dest_addr_mode = TRANSFER_ADDR_MODE_FIXED,
.transfer_settings_word_b.repeat_area = TRANSFER_REPEAT_AREA_SOURCE,
.transfer_settings_word_b.irq = TRANSFER_IRQ_END,
.transfer_settings_word_b.chain_mode = TRANSFER_CHAIN_MODE_DISABLED,
.transfer_settings_word_b.src_addr_mode = TRANSFER_ADDR_MODE_FIXED,
.transfer_settings_word_b.size = TRANSFER_SIZE_2_BYTE,
.transfer_settings_word_b.mode = TRANSFER_MODE_NORMAL,
.p_dest = (void *)Destination,
.p_src = (void const *)Source,
.num_blocks = 0,
.length = 10,
};
err = g_transfer0.p_api->open(g_transfer0.p_ctrl,g_transfer0.p_cfg);
assert(FSP_SUCCESS == err);
API李还提供了一个enable函数,这里为什么没使用呢
fsp_err_t R_DMAC_Reset (transfer_ctrl_t * const p_api_ctrl,
void const * volatile p_src,
void * volatile p_dest,
uint16_t const num_transfers)
{
dmac_instance_ctrl_t * p_ctrl = (dmac_instance_ctrl_t *) p_api_ctrl;
fsp_err_t err = FSP_SUCCESS;
#if DMAC_CFG_PARAM_CHECKING_ENABLE
FSP_ASSERT(NULL != p_ctrl);
FSP_ERROR_RETURN(p_ctrl->open == DMAC_ID, FSP_ERR_NOT_OPEN);
#endif
r_dmac_prv_disable(p_ctrl);
if (NULL != p_src)
{
p_ctrl->p_reg->DMSAR = (uint32_t) p_src;
}
if (NULL != p_dest)
{
p_ctrl->p_reg->DMDAR = (uint32_t) p_dest;
}
if ((TRANSFER_MODE_NORMAL != (transfer_mode_t) p_ctrl->p_reg->DMTMD_b.MD))
{
p_ctrl->p_reg->DMCRB = num_transfers;
}
else
{
p_ctrl->p_reg->DMCRA = num_transfers;
}
err = r_dmac_prv_enable(p_ctrl);
FSP_ERROR_RETURN(FSP_SUCCESS == err, FSP_ERR_NOT_ENABLED);
return FSP_SUCCESS;
}
看reset这个函数内部,调用了enable函数,所以无需我们再次调用