**前言:**RL78F24作为一款瑞萨的经典车规级应用的16bit的MCU,以其超低功耗而闻名。当有大量高频数据发送或接受的应用场景时,就需要用到其DTC,不同于32bitMCU的DMA,DTC属于轻量级的数据传输控制器。本篇博客就详细的介绍一下当有高频UART数据传输需求的时候,使用DTC的应用案例。
1,应用背景
使用两个UART,一个只负责接收数据,一个只负责发送数据。并且两者都使用对应的DTC进行数据的搬运以减轻CPU的负担。
使用的MCU与IDE工具
MCU:R7F124FGJ(48PIN、256KB Flash、24KB RAM)
CS+ for CC V8.13.00 [05 Dec 2024]
Renesas Smart Configurator for RL78 Version: 1.13.0
2,资源介绍
当然,要配置RL78F24的UART的DTC,我们首先得了解一下这款MCU的基本外设分布情况



此款MCU有两路UART,DTC有44种触发源可供选择,最多有38个IO口资源可供使用。并且DTC最多可以配置24通道。

3,实现原理
分别配置两个DTC为UART0发送结束触发和UART1接收完成触发,当对应的发送与接收数据缓冲寄存器被填充的时候触发DTC,DTC再将源地址的数据搬运到目标地址上面。宏观来看,对于UART的发送接收而言,其触发源为发送传输结束与接收传输结束。
由于DTC控制器可以直接访问RAM与外设寄存器,并且和CPU共享系统总线,其直接做了原本属于CPU要做的事情,所以在DTC承担数据搬运任务的时候,CPU也就是MCU的内核就可以腾出手来完成其他的更为重要的任务。所以加上DTC的UART无论发送接收多大的数据量都不会影响CPU的负载率。
RL78 DTC 特点
▪ 单次外设自动搬运
▪ 一般不支持内存 ↔ 内存
▪ 没有复杂链表
▪ 只在事件触发下执行
RL78 DTC 与 RH850 DMA的对比
Aspect RH850 DMA RL78 DTC 通道数量 多(具体看型号,如 8/12/16 通道) 少(通常 1~4 通道) 内存访问宽度 支持 8/16/32/64 位甚至更大块 一般 8/16/32 位 内存 ↔ 内存 支持 ✔ 支持 ✘ 通常不支持 外设 ↔ 内存 支持 ✔ 强 ✔ 支持(受限触发) 触发源数量 多路 主要外设中断触发
4,smart configurator配置
调整串口的时钟,使得波特率调为19200,数据长度为8位
UART0从mcu发送数据到上位机,因此DTCD0的激活源设置为UART0发送传输结束
UART1从上位机发送数据到MCU,因此DTCD1的激活源设置为UART1接收传输结束
UART0的缓存寄存器为SDR00,地址为0xFF10
UART1的缓存寄存器为SDR11,地址为0xFF4A
UART0的TXD0为P15管脚
UART1的RXD1为P11管脚
UART配置



DTC配置

以上配置的是normal模式的时候,DTC搬运一次数据之后就会将计数值归零,要再次搬运就是需要重新设置地址与传输的数据大小。当设置成repeat模式的时候,再次传输的时候可以不用再重载设置地址与传输数据大小,除了对应的Repeat area setting项对应选择的地址的首8BIT是00之外,其他的均不变,不需要再次重载。
全部配置完成之后直接生成代码即可。
5,代码实现
定义数组buf:
UART0_tx_buf为通过UART0从MCU发送到上位机的数据,首地址为0xf9f0a
UART1_rx_buf为通过UART1 MCU接收到上位机的数据,首地址为0xf9f12
以下代码可以实现环形接收UART的数据,并且可以周期性的发送UART数据。
main.c
cpp
#include "r_cg_macrodriver.h"
#include "r_cg_userdefine.h"
#include "Config_DTC.h"
#include "Config_UART0.h"
#include "Config_UART1.h"
#include "Config_TAU0_1.h"
uint8_t UART0_tx_buf[8]={0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88};
uint8_t UART1_rx_buf[8]={0x00};
extern uint8_t t;
void main(void);
void main(void)
{
__DI();
R_Config_UART0_Start();//TXD0:P15
R_Config_UART1_Start();//RXD1:P11
R_Config_TAU0_1_Start();
R_DTCD0_Start();
R_DTCD1_Start();
__EI();
/* DTC UART0 TX Trigger */
SDR00 = UART0_tx_buf[0];
/* DTC UART1 RX Trigger */
UART1_rx_buf[0] = SDR11;
while(1)
{
if(t > 10)
{
/* DTC UART0 Continue Sent*/
user_DTC_UART0TX_reload();
SDR00 = UART0_tx_buf[0];
t = 0;
}
}
}
Config_DTC.c
cpp
#include "r_cg_macrodriver.h"
#include "r_cg_userdefine.h"
#include "Config_DTC.h"
/* Start user code for include. Do not edit comment generated here */
/* End user code. Do not edit comment generated here */
/***********************************************************************************************************************
Pragma directive
***********************************************************************************************************************/
/* Start user code for pragma. Do not edit comment generated here */
/* End user code. Do not edit comment generated here */
/***********************************************************************************************************************
Global variables and functions
***********************************************************************************************************************/
/* Start user code for global. Do not edit comment generated here */
extern uint8_t UART0_tx_buf[8];
/* End user code. Do not edit comment generated here */
#pragma address dtc_vectortable = 0x0FFD00U
uint8_t __near dtc_vectortable[46U];
#pragma address dtc_controldata_0 = 0x0FFD40U
st_dtc_data_t __near dtc_controldata_0;
#pragma address dtc_controldata_1 = 0x0FFD48U
st_dtc_data_t __near dtc_controldata_1;
/***********************************************************************************************************************
* Function Name: R_Config_DTC_Create
* Description : This function initializes the DTC module.
* Arguments : None
* Return Value : None
***********************************************************************************************************************/
void R_Config_DTC_Create(void)
{
/* Enable input clock supply */
DTCEN = 1U;
/* Disable all DTC channels operation */
DTCEN0 = 0x00U;
DTCEN1 = 0x00U;
DTCEN2 = 0x00U;
DTCEN3 = 0x00U;
DTCEN4 = 0x00U;
DTCEN5 = 0x00U;
/* Set base address */
DTCBAR = 0xFDU;
/* Set DTCD0 */
dtc_vectortable[11U] = 0x40U;
dtc_controldata_0.dtccr = _00_DTC_DATA_SIZE_8BITS | _00_DTC_CHAIN_TRANSFER_DISABLE | _00_DTC_DEST_ADDR_FIXED |
_04_DTC_SOURCE_ADDR_INCREMENTED | _00_DTC_TRANSFER_MODE_NORMAL;
dtc_controldata_0.dtbls = _01_DTCD0_TRANSFER_BLOCKSIZE;
dtc_controldata_0.dtcct = _08_DTCD0_TRANSFER_BYTE;
dtc_controldata_0.dtrld = 0x00U;
dtc_controldata_0.dtsar = _9F0A_DTCD0_SRC_ADDRESS;
dtc_controldata_0.dtdar = _FF10_DTCD0_DEST_ADDRESS;
/* Set DTCD1 */
dtc_vectortable[12U] = 0x48U;
dtc_controldata_1.dtccr = _00_DTC_DATA_SIZE_8BITS | _00_DTC_CHAIN_TRANSFER_DISABLE |
_08_DTC_DEST_ADDR_INCREMENTED | _00_DTC_SOURCE_ADDR_FIXED | _00_DTC_TRANSFER_MODE_NORMAL;
dtc_controldata_1.dtbls = _01_DTCD1_TRANSFER_BLOCKSIZE;
dtc_controldata_1.dtcct = _08_DTCD1_TRANSFER_BYTE;
dtc_controldata_1.dtrld = 0x00U;
dtc_controldata_1.dtsar = _FF4A_DTCD1_SRC_ADDRESS;
dtc_controldata_1.dtdar = _9F12_DTCD1_DEST_ADDRESS;
/* Set DTCH0 */
SELHS0 = 0x24U;
HDTCCR0 = _00_DTC_DATA_SIZE_8BITS | _00_DTC_CHAIN_TRANSFER_DISABLE | _00_DTC_DEST_ADDR_FIXED |
_00_DTC_SOURCE_ADDR_FIXED | _00_DTC_TRANSFER_MODE_NORMAL;
HDTCCT0 = _01_DTCH0_TRANSFER_BYTE;
HDTRLD0 = 0x00U;
HDTSAR0 = _0000_DTCH0_SRC_ADDRESS;
HDTDAR0 = _0000_DTCH0_DEST_ADDRESS;
R_Config_DTC_Create_UserInit();
}
/***********************************************************************************************************************
* Function Name: R_DTCD0_Start
* Description : This function starts DTCD0 module operation.
* Arguments : None
* Return Value : None
***********************************************************************************************************************/
void R_DTCD0_Start(void)
{
DTCEN1 |= _10_DTC_UART0T_ACTIVATION_ENABLE;
}
/***********************************************************************************************************************
* Function Name: R_DTCD0_Stop
* Description : This function stops DTCD0 module operation.
* Arguments : None
* Return Value : None
***********************************************************************************************************************/
void R_DTCD0_Stop(void)
{
DTCEN1 &= (uint8_t)~_10_DTC_UART0T_ACTIVATION_ENABLE;
}
/***********************************************************************************************************************
* Function Name: R_DTCD1_Start
* Description : This function starts DTCD1 module operation.
* Arguments : None
* Return Value : None
***********************************************************************************************************************/
void R_DTCD1_Start(void)
{
DTCEN1 |= _08_DTC_UART1R_ACTIVATION_ENABLE;
}
/***********************************************************************************************************************
* Function Name: R_DTCD1_Stop
* Description : This function stops DTCD1 module operation.
* Arguments : None
* Return Value : None
***********************************************************************************************************************/
void R_DTCD1_Stop(void)
{
DTCEN1 &= (uint8_t)~_08_DTC_UART1R_ACTIVATION_ENABLE;
}
/***********************************************************************************************************************
* Function Name: R_DTCH0_Start
* Description : This function starts DTCH0 module operation.
* Arguments : None
* Return Value : None
***********************************************************************************************************************/
void R_DTCH0_Start(void)
{
DTCEN4 |= _08_DTC_TAU10_ACTIVATION_ENABLE;
}
/***********************************************************************************************************************
* Function Name: R_DTCH0_Stop
* Description : This function stops DTCH0 module operation.
* Arguments : None
* Return Value : None
***********************************************************************************************************************/
void R_DTCH0_Stop(void)
{
DTCEN4 &= (uint8_t)~_08_DTC_TAU10_ACTIVATION_ENABLE;
}
/* Start user code for adding. Do not edit comment generated here */
void user_DTC_UART0TX_reload(void)
{
R_DTCD0_Start();
/* Set DTCD0 */
dtc_controldata_0.dtbls = _01_DTCD0_TRANSFER_BLOCKSIZE;
dtc_controldata_0.dtcct = _08_DTCD0_TRANSFER_BYTE;
dtc_controldata_0.dtsar = _9F0A_DTCD0_SRC_ADDRESS;
dtc_controldata_0.dtdar = _FF10_DTCD0_DEST_ADDRESS;
}
void user_DTC_UART1RX_reload(void)
{
R_DTCD1_Start();
/* Set DTCD1 */
dtc_controldata_1.dtbls = _01_DTCD1_TRANSFER_BLOCKSIZE;
dtc_controldata_1.dtcct = _08_DTCD1_TRANSFER_BYTE;
dtc_controldata_1.dtsar = _FF4A_DTCD1_SRC_ADDRESS;
dtc_controldata_1.dtdar = _9F12_DTCD1_DEST_ADDRESS;
}
/* End user code. Do not edit comment generated here */
Config_UART1_user.c
cpp
#include "r_cg_macrodriver.h"
#include "r_cg_userdefine.h"
#include "Config_UART1.h"
/* Start user code for include. Do not edit comment generated here */
/* End user code. Do not edit comment generated here */
/***********************************************************************************************************************
Pragma directive
***********************************************************************************************************************/
#pragma interrupt r_Config_UART1_interrupt_receive(vect=INTSR1)
/* Start user code for pragma. Do not edit comment generated here */
/* End user code. Do not edit comment generated here */
/***********************************************************************************************************************
Global variables and functions
***********************************************************************************************************************/
extern volatile uint8_t * gp_uart1_rx_address; /* uart1 receive buffer address */
extern volatile uint16_t g_uart1_rx_count; /* uart1 receive data number */
extern uint16_t g_uart1_rx_length; /* uart1 receive data length */
/* Start user code for global. Do not edit comment generated here */
/* End user code. Do not edit comment generated here */
/***********************************************************************************************************************
* Function Name: R_Config_UART1_Create_UserInit
* Description : This function adds user code after initializing UART1.
* Arguments : None
* Return Value : None
***********************************************************************************************************************/
void R_Config_UART1_Create_UserInit(void)
{
/* Start user code for user init. Do not edit comment generated here */
/* End user code. Do not edit comment generated here */
}
/***********************************************************************************************************************
* Function Name: r_Config_UART1_callback_receiveend
* Description : This function is a callback function when UART1 finishes reception.
* Arguments : None
* Return Value : None
***********************************************************************************************************************/
static void r_Config_UART1_callback_receiveend(void)
{
/* Start user code for r_Config_UART1_callback_receiveend. Do not edit comment generated here */
/* End user code. Do not edit comment generated here */
}
/***********************************************************************************************************************
* Function Name: r_Config_UART1_callback_error
* Description : This function is a callback function when UART1 reception error occurs.
* Arguments : err_type -
* error type info
* Return Value : None
***********************************************************************************************************************/
static void r_Config_UART1_callback_error(uint8_t err_type)
{
/* Start user code for r_Config_UART1_callback_error. Do not edit comment generated here */
/* End user code. Do not edit comment generated here */
}
/***********************************************************************************************************************
* Function Name: r_Config_UART1_callback_softwareoverrun
* Description : This function is a callback when UART1 receives an overflow data.
* Arguments : rx_data -
* receive data
* Return Value : None
***********************************************************************************************************************/
static void r_Config_UART1_callback_softwareoverrun(uint16_t rx_data)
{
/* Start user code for r_Config_UART1_callback_softwareoverrun. Do not edit comment generated here */
// DTC continue RX TEST
user_DTC_UART1RX_reload();
/* End user code. Do not edit comment generated here */
}
/***********************************************************************************************************************
* Function Name: r_Config_UART1_interrupt_receive
* Description : This function is UART1 receive interrupt service routine.
* Arguments : None
* Return Value : None
***********************************************************************************************************************/
static void __near r_Config_UART1_interrupt_receive(void)
{
uint8_t rx_data;
uint8_t err_type;
err_type = (uint8_t)(SSR11 & 0x0007U);
SIR11 = (uint16_t)err_type;
if (0U != err_type)
{
r_Config_UART1_callback_error(err_type);
}
rx_data = SDR11L;
if (g_uart1_rx_length > g_uart1_rx_count)
{
*gp_uart1_rx_address = rx_data;
gp_uart1_rx_address++;
g_uart1_rx_count++;
if (g_uart1_rx_length == g_uart1_rx_count)
{
r_Config_UART1_callback_receiveend();
}
}
else
{
r_Config_UART1_callback_softwareoverrun(rx_data);
}
}
/* Start user code for adding. Do not edit comment generated here */
/* End user code. Do not edit comment generated here */
6,功能测试
无论是UART0的数据接收还是UART1的数据发送经过重加载之后均可以重复发送或者接收数据。
