[RVB2601 Creative Application Development] Simulating UART 1
[Copy link]
[Preface] In the RVB2601 project, I originally considered that I would need three serial ports, one for receiving voltage, current, and power monitoring data, another for receiving temperature and humidity sent wirelessly, and the third for LOG input and output. Now LOG input occupies UART0, and the default port of UART1 is occupied by SPI. So I can only consider using IO to implement UART.
[Feasibility Analysis] I have never implemented UART simulation before, but I have heard of it. So there is nothing that cannot be done. In addition, @qq4988 in the recent trial report has already implemented it. His article gave me confidence. After consulting the information, many examples based on 51 and stm32 have successfully implemented serial port simulation using IO. I think this function should be realized.
【Knowledge Reserve】
1. I have carefully studied RISC-V RVB2601 First Experience - Section 3 - IO Simulation Serial Port Completion https://bbs.eeworld.com.cn/thread-1196608-1-1.html. I have read many articles on this article and also left a message. It may be that the author has no time to reply due to work reasons.
2. I have learned articles based on 51 and stm32 on the Internet. The most useful one is this one: Microcontroller IO port simulates UART serial communication_C language Chinese website (biancheng.net) . If you are interested, you can also read this post.
3. Study the timing diagram of serial port transmission. I only use 8 bits, 1 stop bit, no verification, and the baud rate is 9600.
4. Add your own N assumptions... Omit 10,000 words...
【Implement the required peripherals】
1. Two IOs. After carefully checking the schematic diagram, only three LEDs can be used. PA7, PA25, and PA4 are three IOs. In fact, two KEYs can also be used, but KEY may have other uses, so PA7 is used as TX and PA25 is used as RX.
2. Timer: Since the serial port requires precise delay to implement, we refer to the experience of netizens, especially @qq4988, and use timer 1 to implement it.
【Implementation ideas】
1. Initialize PA7 as TX, gpio output, and initialize PA25 as interrupt input.
2. Initialize the timer and set it to 0.104 for an interrupt trigger and a baud rate of 9600.
3. Create a timer interrupt callback function.
【Realize step gathering】
1. Define the sending and receiving structure for sending and receiving:
enum{
VM_SEND,
VM_REVC,
IDLE
};
typedef struct {
uint8_t vm_uart_dir;//send, receive
uint8_t vm_uart_tx_byte;//send data
uint8_t vm_uart_tx_bit;
uint8_t vm_uart_tx_flag; uint8_t vm_uart_rx_byte;
uint8_t vm_uart_rx_irq;
uint8_t vm_uart_rx_count;
uint8_t
vm_uart_tx_buf[UART_MAX_LEN];
uint8_t vm_uart_rx_buf[UART_MAX_LEN];
} _io_uart_para;
2. Initialize IO, interrupts, and timers:
/*模拟UART IO初始化*/
void io_uart_init(void)
{
csi_pin_set_mux(PA7, PIN_FUNC_GPIO);
csi_pin_set_mux(PA25, PIN_FUNC_GPIO);
csi_gpio_pin_init(&io_uart0_tx, PA7);
csi_gpio_pin_init(&io_uart0_rx,PA25);
csi_gpio_pin_dir(&io_uart0_tx,GPIO_DIRECTION_OUTPUT);
csi_gpio_pin_dir(&io_uart0_rx,GPIO_DIRECTION_INPUT);
csi_gpio_pin_mode(&io_uart0_tx,GPIO_MODE_OPEN_DRAIN);
csi_gpio_pin_mode(&io_uart0_rx,GPIO_MODE_PULLNONE);
csi_gpio_pin_attach_callback(&io_uart0_rx,io_uart0_rx_interrupt_handler,NULL);
csi_gpio_pin_irq_mode(&io_uart0_rx,GPIO_IRQ_MODE_FALLING_EDGE);
csi_gpio_pin_irq_enable(&io_uart0_rx,true);
io_uart_para.vm_uart_dir = IDLE;
io_uart_para.vm_uart_tx_bit = 0;
io_uart_para.vm_uart_rx_count = 0;
io_uart0_tx_write_High;
}
//定时器初始化
void timer1_init(void)
{
int ret = -1;
timer1.port = TIMER1_PORT_NUM;
//timer1.config.period = 1000000; //1s
timer1.config.period = 104;//0.104ms
timer1.config.reload_mode = TIMER_RELOAD_AUTO;
timer1.config.cb = timer1_handler;
ret = hal_timer_init(&timer1);
if(ret != 0)
{
printf("timer1 init error !\n");
}
else{
hal_timer_stop(&timer1);
}
}
3. Timer sending function:
//定时器回调函数
void timer1_handler(void *arg)
{
if(io_uart_para.vm_uart_dir == VM_SEND)//如果是发送
{
if(io_uart_para.vm_uart_tx_bit <=8 ) //如果发送不足8位
{
if((io_uart_para.vm_uart_tx_byte & 0x01) == 0x01 ){
io_uart0_tx_write_High;
}else{
io_uart0_tx_write_Low;
}
io_uart_para.vm_uart_tx_byte>>=1;
}
else{
if(io_uart_para.vm_uart_tx_bit > 8){
io_uart0_tx_write_High;
io_uart0_rx_timer_disable();
io_uart_para.vm_uart_tx_flag = 0; //设置为发送完毕
io_uart_para.vm_uart_dir = IDLE;
}
}
io_uart_para.vm_uart_tx_bit ++;
}
}
4. Send test:
int main(void)
{
board_yoc_init();
LOGD(TAG, "%s\n", aos_get_app_version());
oled_init();
io_uart_init();
timer1_init();
LOGD(TAG, "led and key test");
while (1) {
io_uart_para.vm_uart_tx_byte = 0x01;
io_uart_para.vm_uart_tx_bit = 0;
io_uart_para.vm_uart_dir = VM_SEND;
io_uart0_tx_write_Low;
io_uart0_rx_timer_enable();
while(io_uart_para.vm_uart_dir == IDLE);
//io_uart0_tx_write_High;
LOGD(TAG, "send 0x1end");
//aos_msleep(2000);
io_uart0_tx_write_Low;
io_uart_para.vm_uart_tx_byte = 0x02;
io_uart_para.vm_uart_tx_bit = 0;
io_uart_para.vm_uart_dir = VM_SEND;
io_uart0_rx_timer_enable();
while(io_uart_para.vm_uart_dir == IDLE);
LOGD(TAG, "send 0x2end");
//aos_msleep(2000);
io_uart0_tx_write_Low;
io_uart_para.vm_uart_tx_byte = 0x03;
io_uart_para.vm_uart_tx_bit = 0;
io_uart_para.vm_uart_dir = VM_SEND;
io_uart0_rx_timer_enable();
while(io_uart_para.vm_uart_dir == IDLE);
LOGD(TAG, "send 0x3end");
aos_msleep(2000);
}
return 0;
}
【Experimental results】:
[Discussion] This time, the simulation of sending serial port data is only less than one-third successful, and the serial port receiving function is not yet completed. I post it here myself, firstly to review it again, and secondly to record it.
The next step is to encapsulate the sending function and then work hard to write the serial port receiving function.
|