最近在开发瑞萨RA6M4单片机发现瑞萨系列不像ST系列方便配置串口空闲中断,在浏览大量资料与求助FAE实现了瑞萨串口DMA接受、DTC发送不定长数据的技术。鉴于互联网上相关技术帖较少,遂拿出与大家分享,一起进步,共同维护RA生态!
声明:一切权利归本人发帖所在公司所有,技术仅做交流使用,禁止商业行为!!!
配置部分
1. 使用瑞萨图形化配置串口
本例使用串口8,增加发送DTC配置,是能FIFO模式;
2.配置DMA接受
DMA接受是外设->内存,所以目标地址选择递增,触发方式串口的发送
3.配置DMA接受超时中断(空闲中断)
配置定时器的触发源为串口8的接受信号,原理:串口发送的时候一直触发/刷新定时器的计数值使其不超时,当发送完成时就停止刷新,超过设定时间(本例10ms)就会触发定时器中断。
4.配置elc
开启事件连接配置
代码实现
5.初始化串口、打开ELC、开启定时器
// open uart8
board_uart_open(BOARD_UART8);
R_IOPORT_PinWrite(&g_ioport_ctrl,BSP_IO_PORT_01_PIN_06, BSP_IO_LEVEL_LOW);
R_ELC_Open(&g_elc_ctrl,&g_elc_cfg);
R_ELC_Enable(&g_elc_ctrl);
dmac_open(DMAC_UART8_RX);
R_GPT_Open(&g_timer_uart8_idle_ctrl, &g_timer_uart8_idle_cfg);
R_GPT_Enable(&g_timer_uart8_idle_ctrl);
6.dma初始化,开启fifo要注意这里重新指向的源地址FRDRL
typedef struct{
uart_type utype;
dmac_type dtype;
const bsp_io_port_pin_t dir_pin;
transfer_ctrl_t *p_ctrl;
const transfer_cfg_t *p_cfg;
const volatile uint8_t * p_dest;
const volatile uint8_t * p_src;
uint16_t p_len;
volatile uint8_t * my_irq;
volatile bool* send_complete_flag;
}board_dmac_ctrl_t;
typedef struct{
timer_type type;
transfer_ctrl_t *p_ctrl;
// const timer_cfg_t *p_cfg;
//const bsp_io_port_pin_t dir_pin;
bool* recv_complete_flag;
// uint8_t *recv_buf;
uint32_t recv_buflen;
volatile uint32_t* uart_recv_idx;
volatile uint32_t* uart_recv_head;
}board_timer_ctrl_t;
typedef enum{
DMAC_UART4_RX = 0,
DMAC_UART4_TX,
DMAC_UART8_RX,
DMAC_UART8_TX,
DMAC_SPI0_RX,
DMAC_SPO0_TX,
}dmac_no;
board_timer_ctrl_t board_timer_ctrl[] =
{
{UART, &g_transfer_uart4_dmac_rx_ctrl, &uart_recv_complete_flag[BOARD_UART4], UART_RCVBUF_LEN, &recv_idx[BOARD_UART4], &recv_head[BOARD_UART4]},
{UART, &g_transfer_uart8_dmac_rx_ctrl, &uart_recv_complete_flag[BOARD_UART8], UART_RCVBUF_LEN, &recv_idx[BOARD_UART8], &recv_head[BOARD_UART8]},
};
transfer_properties_t dmainfo;
board_dmac_ctrl_t board_dmac_ctrl[] =
{
{RS485,UART_RX,BSP_IO_PORT_02_PIN_05,
&g_transfer_uart4_dmac_rx_ctrl,&g_transfer_uart4_dmac_rx_cfg,uart_receive_buffers[BOARD_UART4],
&R_SCI4->FRDRL,sizeof(uart_receive_buffers[BOARD_UART4]),NULL,NULL,
},
{RS485,UART_TX,BSP_IO_PORT_02_PIN_05,
&g_transfer_uart4_dmac_tx_ctrl,&g_transfer_uart4_dmac_tx_cfg,&R_SCI4->FTDRL,
NULL,0,&R_SCI4->SSR,&uart_send_complete_flag[BOARD_UART4], //FTDRL
},
{RS485,UART_RX,BSP_IO_PORT_01_PIN_06,
&g_transfer_uart8_dmac_rx_ctrl,&g_transfer_uart8_dmac_rx_cfg,uart_receive_buffers[BOARD_UART8],
&R_SCI8->FRDRL,sizeof(uart_receive_buffers[BOARD_UART8]),NULL,NULL,
},
{RS485,UART_TX,BSP_IO_PORT_01_PIN_06,
&g_transfer_uart8_dmac_tx_ctrl,&g_transfer_uart8_dmac_tx_cfg,&R_SCI8->TDR,
NULL,0,&R_SCI8->SSR,&uart_send_complete_flag[BOARD_UART8],
},
};
void dmac_open(dmac_no port)
{
fsp_err_t err = FSP_SUCCESS;
if(board_dmac_ctrl[port].dtype == UART_RX)
{
board_dmac_ctrl[port].p_cfg->p_info->p_dest = (void * volatile)board_dmac_ctrl[port].p_dest;
board_dmac_ctrl[port].p_cfg->p_info->p_src = (void const * volatile)board_dmac_ctrl[port].p_src;
board_dmac_ctrl[port].p_cfg->p_info->length = board_dmac_ctrl[port].p_len;
err = R_DMAC_Open(board_dmac_ctrl[port].p_ctrl, board_dmac_ctrl[port].p_cfg);
assert(FSP_SUCCESS == err);
err = R_DMAC_Enable(board_dmac_ctrl[port].p_ctrl);
assert(FSP_SUCCESS == err);
}
else
{
board_dmac_ctrl[port].p_cfg->p_info->p_dest = (void * volatile)board_dmac_ctrl[port].p_dest;
err = R_DMAC_Open(board_dmac_ctrl[port].p_ctrl, board_dmac_ctrl[port].p_cfg);
assert(FSP_SUCCESS == err);
}
}
void dmac_reset(dmac_no port)
{
// FSP_PARAMETER_NOT_USED (port);
dmac_close(port);
dmac_open(port);
}
7.接受处理函数
/*******************************************************************************************************************//**
* @brief g_timer_uart8_idle_callback
*
* @param[in] timer_callback_args_t Callback function parameter data
* @retval None
**********************************************************************************************************************/
void g_timer_uart8_idle_callback(timer_callback_args_t *p_args)
{
(void)p_args;
g_timer_uart_idle_process(TIME_UART8);
board_uart_put(BOARD_UART8, uart_receive_buffers[BOARD_UART8], *board_timer_ctrl[TIME_UART8].uart_recv_idx);
dmac_reset(DMAC_UART8_RX);
}
/*******************************************************************************************************************//**
* @brief g_timer_uart_idle_process
*
* @param[in] timer_callback_args_t Callback function parameter data
* @retval None
**********************************************************************************************************************/
void g_timer_uart_idle_process(timer_to_uart port)
{
R_DMAC_InfoGet(board_timer_ctrl[port].p_ctrl,&dmainfo);
*board_timer_ctrl[port].uart_recv_idx = board_timer_ctrl[port].recv_buflen - dmainfo.transfer_length_remaining;
*board_timer_ctrl[port].recv_complete_flag = true;
}
至此完成DMA方式接受不定长数据,DTC方式发送。