文章目录
一. 软件需求
1、RK2118需要与bt实现uart通信
2、实现自定义通信协议。
二. UART DMA软件实现
2.1 软件框架介绍
串口框架:
components/drivers/include/drivers/serial.h
components/drivers/serial/serial.c 设备驱动
components/libc/termios/posix_termios.c 类似linux的tty配置
components/libc/termios/posix_termios.h
串口驱动适配层:
bsp/rockchip-pisces/drivers/drv_uart.c
bsp/rockchip-pisces/drivers/drv_uart.h
串口测试命令,串口用户程序完全可以参照以下驱动:
bsp/rockchip-common/tests/termios_test.c
2.2 uart dma代码路径
Rk2118/Components/hifi4/rtt/app/rkplayer/userial_dma_app.c
2.2.1 DMA设备创建以及初始化
int uart_dma_device_init()
{
char uart_name[RT_NAME_MAX];
rt_strncpy(uart_name, DMA_UART_NAME, RT_NAME_MAX);
serial = rt_device_find(uart_name);
if (!serial){
rt_kprintf("find %s failed!\n", uart_name);
return -RT_ERROR;
}else {
RC_LOGD("find %s ok!\n", uart_name);
}
rt_device_open(serial, RT_DEVICE_FLAG_DMA_RX);
rt_device_set_rx_indicate(serial, uart_input);
return 0;
}
2.2.2 DMA线程创建(创建消息队列,阻塞等待rx消息)
int uart_dma_app_init()
{
rt_err_t ret = RT_EOK;
static char msg_pool[256];
rt_mq_init(&rx_mq, "rx_mq",msg_pool,sizeof(struct rx_msg),sizeof(msg_pool),RT_IPC_FLAG_FIFO);
int rets = uart_dma_device_init();
if (rets < 0){
return RT_ERROR;
}
RC_LOGD(" dma_serial thread create \n");
rt_thread_t thread = rt_thread_create("dma_serial", serial_thread_entry, RT_NULL, 1024, 21, 10);
if (thread != RT_NULL){
rt_thread_startup(thread);
}
else{
ret = RT_ERROR;
}
return ret;
}
2.2.3 阻塞等待线程实现
static void serial_thread_entry(void *parameter)
{
struct rx_msg msg;
rt_err_t result;
rt_uint32_t rx_length;
static char rx_buffer[RT_SERIAL_RB_BUFSZ + 1];
rt_kprintf(" serial_thread_entry \n");
while (1)
{
rt_memset(&msg, 0, sizeof(msg));
rt_memset(rx_buffer, 0, sizeof(rx_buffer));
result = rt_mq_recv(&rx_mq, &msg, sizeof(msg), RT_WAITING_FOREVER);
rt_kprintf(" recv message value = %d msg.size = %d\n",msg.value,msg.size);
if (result == RT_EOK)
{
rx_length = rt_device_read(msg.dev, 0, rx_buffer, msg.size);
rx_buffer[rx_length] = '\0';
rt_device_write(serial, 0, rx_buffer, rx_length);
RC_LOGI(" %s\n",rx_buffer);
RC_LOGI(" %d %d %d \n",rx_buffer[0],rx_buffer[1],rx_buffer[2]);
}
}
}
2.2.4 Send函数实现
void uart_send_data(uint8_t *data, uint32_t len)
{
if (!serial) {
return ;
}
rt_device_write(serial, 0, data, len);
uart_dma_data_dump(data,len);
}
三、rkplayer app流程介绍
1、IN1IT_APP_EXPORT(rkplayer_init);/注册app线程到init函数/
2、g_app_info.main_mq = rt_mq_create(“main”, sizeof(struct app_msg), 10, RT_IPC_FLAG_FIFO);/主消息队列/
3、uart_dma_app_init();/dma线程创建/
4、rt_mq_recv(g_app_info.main_mq, (void *)&rcv_msg, sizeof(struct app_msg), RT_WAITING_FOREVER);/阻塞式等待消息/
5、消息的分类转发到其他线程
for (int i = TYPE_PLAY; i < TYPE_REMOTE_CTL; i++) {
if (rcv_msg.msg_falg & (1<<i)) {
send_msg.press = rcv_msg.press;
send_msg.type = i;
rt_mq_send(g_app_info.msg_mq[i], (void *)&send_msg, sizeof(struct app_msg));
}
}
3.1按键下发流程
1、key_app线程等待adc按键消息
2、adc检测到不同的按键电压发送消息到主线程
3、主线程根据不同的按键消息实现对应功能
四、UART自定义协议
4.1、协议自定义格式
4.2 代码实现命令打包
4.2.1、命令打包函数
static uint8_t user_build_cmd(uint8_t opcode, uint8_t subcommand, uint8_t *src, uint8_t srclen, uint8_t *dst, uint8_t dstlen) {
uint8_t i = 0;
RT_ASSERT(dstlen >= (/HEAD/ 4 + srclen + 1/CHECKSUM_LEN/));
dst[i++] = 0x28; /start/
dst[i++] = 4 + srclen + 1; /len/
dst[i++] = opcode; /func/
dst[i++] = subcommand; /sub/
memcpy(&dst[i], src, srclen); /data/
i = i+ srclen;
dst[i] = calculate_checksum(dst, i);/crc/
return i;
}
4.2.2、校验函数
static uint8_t calculate_checksum(uint8_t *buf, uint8_t len)
{
uint8_t sum;
for(sum = 0; len > 0; len--)
sum += *buf++;
rt_kprintf("debug: sum = %d \n ",sum&0xff);
return sum&0xff;
}
4.2.3、功能函数实现
五、UART DEBUG
5.1 menuconfig配置
通过menuconfig打开串口配置,同时会生成/dev/uart0…3设备。
RT-Thread rockchip RKxxxx drivers —>
[] Enable UART
[] Enable UART0
[ ] Enable UART1
[*] Enable UART2
5.2 、uart test功能
RT-Thread Components —>
[] DFS: device virtual file system —>
[] Using devfs for device objects
C/C++ and POSIX layer —>
POSIX (Portable Operating System Interface) layer —>
[] Enable POSIX file system and I/O
[] Enable I/O Multiplexing select() <sys/select.h>
[*] Enable Terminal I/O <termios.h>
RT-Thread bsp test case —>
RT-Thread Common Test case —>
[] Enable BSP Common TEST
[] Enable BSP Common UART TEST
串口测试命令:
receive data:
termtest r /dev/uart4 115200
send data:
termtest s /dev/uart4 115200
receive then send:
termtest t /dev/uart4 115200
externel loopback:
termtest l /dev/uart4 115200
5.3 、uart send test
void uart_send_msg_test()
{
struct rx_msg msg;
rt_err_t result;
msg.dev = serial;
msg.value = 12;
msg.size = 1;
rt_kprintf("send message \n");
result = rt_mq_send(&rx_mq, &msg, sizeof(msg));
if ( result == -RT_EFULL){
rt_kprintf("message queue full!\n");
}
}
测试实例:
1、由于硬件环境限制;目前采用audio debug uart 作为调试口(uart2)
2、测试目前使用的是V+和V-按键操作如下:
/* 把相关测试函数放到按键下,接出对应uart口可以看到测试收发正常**/
Debug:uart0发送端打印如下:
Uart2接收端打印如下: