本文目的
- 在实际的应用中,单独的空出一个串口做日志往往是奢侈的,使用非串口方式可靠的模拟串口输出日志是个很好的代替方法
- 有时候,因为主频设置,导致使用串口外设输出,往往不能得到比较理想的高波特率,如ch585主频跑到78M下,因为串口通常有一定的过采样, 而单纯的使用定时器直接模拟TX并不需要这样做
- 本文在ch5xx 系列蓝牙芯片上, 使用芯片的定时器配合DMA实现可靠的串口日志输出方式
适用芯片
- CH5xx 蓝牙芯片
- CH569/CH565(未验证)
实现
下面在ch585芯片上, 使用PB22引脚所在的TMR2输出作为示例
使用
//传入主频78M,传入波特率2M
ch5xx_t_uart_init(78000000,2000000);
while(1) {
ch5xx_t_uart_printf("check pb19 level:%u\r\n",GPIOB_ReadPortPin(GPIO_Pin_19)?1:0);
DelayMs(1000);
}
驱动代码
ch5xx_t_uart.h
#ifndef __CH5XX_T_UART_H__
#define __CH5XX_T_UART_H__
void ch5xx_t_uart_init(uint32_t sys_frq,uint32_t baudrate);
void ch5xx_t_uart_send_byte(uint8_t byte);
void ch5xx_t_uart_send(uint8_t *data,uint32_t len);
void ch5xx_t_uart_printf(char *fmt,...);
#endif //__CH5XX_T_UART_H__
ch5xx_t_uart.c
#include "CH58x_common.h"
#include <stdio.h>
#include <stdint.h>
#include <stdarg.h>
#include "ch5xx_t_uart.h"
static uint32_t timer_dma_buf[11];
static uint32_t bit_cnt;
void ch5xx_t_uart_init(uint32_t sys_frq,uint32_t baudrate)
{
bit_cnt = sys_frq/baudrate;
timer_dma_buf[0] = bit_cnt;
timer_dma_buf[9] = 0;
timer_dma_buf[10] = 0;
GPIOB_SetBits(GPIO_Pin_22);
GPIOB_ModeCfg(GPIO_Pin_22, GPIO_ModeOut_PP_5mA);
TMR3_PWMInit(Low_Level, PWM_Times_1);
TMR3_PWMCycleCfg(bit_cnt);
TMR3_Disable();
TMR3_PWMActDataWidth(0); //set default level
TMR3_PWMEnable();
TMR3_Enable();
TMR3_ITCfg(ENABLE, RB_TMR_IE_DMA_END);
R32_TMR3_DMA_BEG = (uint32_t)&timer_dma_buf[0];
R32_TMR3_DMA_END = (uint32_t)&timer_dma_buf[10];
ch5xx_t_uart_printf("ch5xx_timer uart init done\r\n");
}
__HIGH_CODE
void ch5xx_t_uart_send(uint8_t *data,uint32_t len)
{
while(len) {
ch5xx_t_uart_send_byte(*data);
data ++;
len --;
}
}
__HIGH_CODE
void ch5xx_t_uart_send_byte(uint8_t byte)
{
uint32_t *p = &timer_dma_buf[1];
for(uint8_t j=0;j<8;j++) {
if( byte & 0x01u) {
*p = 0;
}else {
*p = bit_cnt;
}
byte >>=1;
p++;
}
R32_TMR3_DMA_BEG = (uint32_t)&timer_dma_buf[0];
TMR3_ClearITFlag(RB_TMR_IE_DMA_END);
R8_TMR3_CTRL_DMA = RB_TMR_DMA_ENABLE;
//wait dma end
while(!TMR3_GetITFlag(RB_TMR_IF_DMA_END));
//stop dma
R8_TMR3_CTRL_DMA = 0;
}
void ch5xx_t_uart_printf(char *fmt,...)
{
char buffer[128];
va_list arg_ptr;
va_start(arg_ptr,fmt);
uint32_t len = vsnprintf(buffer,128,fmt,arg_ptr);
va_end(arg_ptr);
ch5xx_t_uart_send(buffer,len);
}