简介:
现在的mcu 多核已经是很常见的了,对于多核调试时uart log 是一种使用比较常用的方式,对于多核我们可以给每一个核分配一个物理串口,如果资源比较紧张我么也可以和其他核共享一个串口来打印,我们本次的试验是使用后者的方式core0 核 core1 共享一个串口进行打印。
其实现思路是通过核间通信的share memory,在share memory 中分配一段内存中分配一段空间按照Ring buff 的方式进行存储,一端进行写入另一端读取,然后再CORE0中将数据转发到物理串口,对应的实现原理如下。
代码实现
按照上述share memory 中的数据管理方式本地定义如下数据结构
#define VUART_CORE0_RX_CORE1_TX_BUFFER_SIZE 256 #define VUART_CORE0_TX_CORE1_RX_BUFFER_SIZE 128 //#pragma pack(1) struct virual_uart { char magic[4];/* VURT */ RingBuffer core0_rx_core1_tx; RingBuffer core0_tx_core1_rx; uint8_t core0_rx_core1_tx_buff[VUART_CORE0_RX_CORE1_TX_BUFFER_SIZE]; uint8_t core0_tx_core1_rx_buff[VUART_CORE0_TX_CORE1_RX_BUFFER_SIZE]; };
按照上述流程,在CORE0 侧初始化share memory ,并将share memory 的地址信息通过和间通信的机制通知到CORE1,代码如下。
#ifdef APP_USING_VIRTUAL_UART static struct virual_uart virual_uart0 @ "vuart0_sh_mem_section"; static void virual_uart_init(struct virual_uart * p_vuart) { /* init memory buffer */ memset((void *)p_vuart->core0_rx_core1_tx_buff,0,sizeof(p_vuart->core0_rx_core1_tx_buff)); memset((void *)p_vuart->core0_tx_core1_rx_buff,0,sizeof(p_vuart->core0_tx_core1_rx_buff)); /* init ringbuffer */ RingBuffer_Init(&p_vuart->core0_rx_core1_tx,p_vuart->core0_rx_core1_tx_buff,sizeof(p_vuart->core0_rx_core1_tx_buff)); RingBuffer_Init(&p_vuart->core0_tx_core1_rx,p_vuart->core0_tx_core1_rx_buff,sizeof(p_vuart->core0_tx_core1_rx_buff)); /* init magic value */ p_vuart->magic[0] = 'V'; p_vuart->magic[1] = 'U'; p_vuart->magic[2] = 'R'; p_vuart->magic[3] = 'T'; } #endif int main(void) { MAILBOX_Init(MAILBOX); NVIC_EnableIRQ(MAILBOX_IRQn); #ifdef APP_USING_VIRTUAL_UART virual_uart_init(&virual_uart0); rt_kprintf("send to core1 virual uart addr %x.\n",(uint32_t)(&virual_uart0)); MAILBOX_SetValue(MAILBOX,kMAILBOX_CM33_Core1,(uint32_t)(&virual_uart0)); #endif }
CORE1 侧将对应的log 输出函数 本地使用的printf 底层IO接口输出写入到Ringbuff
size_t __write(int handle, const unsigned char *buffer, size_t size) { while(MAILBOX_GetMutex(MAILBOX) == 0); RingBuffer_Write(&p_virtual_uart0->core0_rx_core1_tx,(uint8_t *)buffer,size); MAILBOX_SetMutex(MAILBOX); return size; }
CORE0 侧读取对应的Ringbuff 并将数据转发至UART 物理层,对应代码如下。
int main(void) { while (1) { uint8_t data; //rt_pin_write(LEDB_PIN, PIN_HIGH); /* Set GPIO output 1 */ //rt_thread_mdelay(500); /* Delay 500mS */ //rt_pin_write(LEDB_PIN, PIN_LOW); /* Set GPIO output 0 */ //rt_thread_mdelay(500); /* Delay 500mS */ while(MAILBOX_GetMutex(MAILBOX) == 0); while(RingBuffer_GetDataLength(&virual_uart0.core0_rx_core1_tx)) { RingBuffer_Read(&virual_uart0.core0_rx_core1_tx,&data,1); rt_kprintf("%c",data); } MAILBOX_SetMutex(MAILBOX); rt_thread_mdelay(10); } }
至此代码已经适配完成,在 CORE1 侧调用printf 函数验证虚拟串口的功能。
/*! * @brief Main function */ int main(void) { while(p_virtual_uart0 == NULL); if(p_virtual_uart0->magic[0] == 'V' && p_virtual_uart0->magic[1] == 'U' && p_virtual_uart0->magic[2] == 'R' && p_virtual_uart0->magic[3] == 'T') { printf("\r\n [core1] virtual uart init ok.\r\n"); } /* Configure LED */ LED_INIT(); for (;;) { SDK_DelayAtLeastUs(500000U, SDK_DEVICE_MAXIMUM_CPU_CLOCK_FREQUENCY); LED_TOGGLE(); printf("\r\n [core1] led toggle.\r\n"); } }
运行发现core0 和 core1 的log 都按照预期的在uart 上输出显示了,至此已经完成上述通过share memory 来虚拟串口显示log 的功能。