简介:
现在的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 的功能。


 
					
				
 
			
			
			
						
			 我要赚赏金
 我要赚赏金 STM32
STM32 MCU
MCU 通讯及无线技术
通讯及无线技术 物联网技术
物联网技术 电子DIY
电子DIY 板卡试用
板卡试用 基础知识
基础知识 软件与操作系统
软件与操作系统 我爱生活
我爱生活 小e食堂
小e食堂

