C PIC32 USART_BufferAddRead 丢失字节

问题描述

在我的项目中,我需要通过 UART 连接一个 PIC32MZ2048EFH144 和一个外部设备。我使用 Harmony v1.1 以这种方式设置 USART 外设:

CONfig_USE_DRV_USART=y
CONfig_DRV_USART_DRIVER_MODE="STATIC"
CONfig_DRV_USART_INTERRUPT_MODE=y
CONfig_DRV_USART_BYTE_MODEL_SUPPORT=n
CONfig_DRV_USART_READ_WRITE_MODEL_SUPPORT=n
CONfig_DRV_USART_BUFFER_QUEUE_SUPPORT=y
CONfig_DRV_USART_SUPPORT_TRANSMIT_DMA=n
CONfig_DRV_USART_SUPPORT_RECEIVE_DMA=n
CONfig_DRV_USART_INSTANCES_NUMBER=2
CONfig_DRV_USART_CLIENTS_NUMBER=2
CONfig_DRV_USART_PERIPHERAL_ID_IDX1="USART_ID_4"
CONfig_DRV_USART_BAUD_RATE_IDX1=9600
CONfig_DRV_USART_XMIT_INT_PRIORITY_IDX1="INT_PRIORITY_LEVEL1"
CONfig_DRV_USART_XMIT_INT_SUB_PRIORITY_IDX1="INT_SUBPRIORITY_LEVEL0"
CONfig_DRV_USART_RCV_INT_PRIORITY_IDX1="INT_PRIORITY_LEVEL1"
CONfig_DRV_USART_RCV_INT_SUB_PRIORITY_IDX1="INT_SUBPRIORITY_LEVEL0"
CONfig_DRV_USART_ERR_INT_PRIORITY_IDX1="INT_PRIORITY_LEVEL1"
CONfig_DRV_USART_ERR_INT_SUB_PRIORITY_IDX1="INT_SUBPRIORITY_LEVEL0"
CONfig_DRV_USART_OPER_MODE_IDX1="DRV_USART_OPERATION_MODE_norMAL"
CONfig_DRV_USART_INIT_FLAG_WAKE_ON_START_IDX1=n
CONfig_DRV_USART_INIT_FLAG_AUTO_BAUD_IDX1=n
CONfig_DRV_USART_INIT_FLAG_STOP_IN_IDLE_IDX1=n
CONfig_DRV_USART_LINE_CNTRL_IDX1="DRV_USART_LINE_CONTROL_8NONE1"
CONfig_DRV_USART_HANDSHAKE_MODE_IDX1="DRV_USART_HANDSHAKE_NONE"
CONfig_DRV_USART_XMIT_QUEUE_SIZE_IDX1=10
CONfig_DRV_USART_RCV_QUEUE_SIZE_IDX1=10
CONfig_DRV_USART_STATIC_RX_MODES_IDX1="USART_HANDSHAKE_MODE_FLOW_CONTROL"
CONfig_DRV_USART_STATIC_OP_MODES_IDX1="USART_ENABLE_TX_RX_USED"
CONfig_DRV_USART_STATIC_LINECONTROL_MODES_IDX1="USART_8N1"
CONfig_DRV_USART_STATIC_TX_ENABLE_IDX1=y
CONfig_DRV_USART_STATIC_RX_ENABLE_IDX1=y
CONfig_DRV_USART_STATIC_TX_INTR_MODES_IDX1="USART_TRANSMIT_FIFO_NOT_FULL"
CONfig_DRV_USART_STATIC_RX_INTR_MODES_IDX1="USART_RECEIVE_FIFO_ONE_CHAR"

一开始,外部设备发送一条唤醒消息,我正确接收并回复唤醒确认。 在这个序列之后,我发送了一个 requestDevID ...在这一点上我遇到了一些麻烦。通过示波器,我可以看到外部设备正确回答了这个请求,但在我的代码中我没有得到完整的消息。

答案是:0xFA 0xFF 0x01 0x04 0x07 0x78 0x26 0x1A 0x3D 我看到的(当我停止调试时)是:0x78 0x26 0x1A 0x3D 0x07

我的代码如下:

void mti710USART1BufferHandler(DRV_USART_BUFFER_EVENT bufferEvent,DRV_USART_BUFFER_HANDLE hBufferEvent,uintptr_t context){
    
    switch(bufferEvent){
        case DRV_USART_BUFFER_EVENT_COMPLETE:{
            if (context == 1){
                // to-do
                flag = 1;
            countFlag += 1;
        }
            break;
        case DRV_USART_BUFFER_EVENT_ERROR:{
            if (context == 1){
                // to-do
                flag = -1;
            }
        }
            break;
        case DRV_USART_BUFFER_EVENT_ABORT:
            break;
        default:
            break;
    }  
}

bool mti710Initialize(MTi710INSInitDriver_t mti710Init){
    
    mtiData.dvrMTi710INSIndex = mti710Init.dvrMTi710INSIndex;
    mtiData.drvUART.handle = DRV_HANDLE_INVALID;
    mtiData.drvUART.baudrate = 115200;
    
    memset(&mtiData.drvUART.TX.buffer,0x00,sizeof(mtiData.drvUART.TX.buffer));
    memset(&mtiData.drvUART.RX.buffer,sizeof(mtiData.drvUART.RX.buffer));
    
    mtiData.drvUART.handle = DRV_USART_Open(mtiData.dvrMTi710INSIndex,DRV_IO_INTENT_READWRITE | DRV_IO_INTENT_NONBLOCKING);
    
    if (mtiData.drvUART.handle != DRV_HANDLE_INVALID) {
        if (mti710SetBaudrate(mtiData.drvUART.handle,mtiData.drvUART.baudrate)){
            DRV_USART_BufferEventHandlerSet(mtiData.drvUART.handle,mti710USART1BufferHandler,(uintptr_t) 1);
            mtiData.drvMti710INsstate = MTi710INS_STATE_IDLE;
            
            return true;
        }
    }
    return false;
}

static void UARTRead(uint8_t* readBuffer,uint32_t bufferSize){    
    
    USART_ReceiverOverrunErrorClear_Default(DRV_USART_INDEX_1);
    while (DRV_USART_ClientStatus(mtiData.drvUART.handle) != DRV_USART_CLIENT_STATUS_READY);
    DRV_USART_BufferAddRead(mtiData.drvUART.handle,&(mtiData.drvUART.RX.bufferHandle),readBuffer,bufferSize);
}

...
...

uint32_t mti710Readdeviceid(struct XbusParser* parser,const uint32_t timeout_us){
    struct XbusMessage requestId = {XMID_ReqDid,NULL};
    
    mtiData.drvMti710INsstate = MTi710INS_REQ_READ_ID;
    if (flag == 0){
        mti710WriteData(&requestId);
        flag = 0;
    }
    mti710ReadData(9);
    if (flag == 1){
        XbusParser_parseBuffer(parser,(uint8_t*)&mtiData.drvUART.RX.buffer[0],sizeof(mtiData.drvUART.RX.buffer));
        flag = 0;
        return parser->currentMessage.mid == XMID_deviceid ? (uint32_t)parser->currentMessage.data : -1;
    } else {
        return -1;
    }
}

知道我的错误吗?

问候,

文森佐。

解决方法

第一件事:

当您从应用程序代码中读取硬件寄存器(如 UART RX 寄存器)时,您必须禁用 UART RX 中断。

UART RX 寄存器是共享资源。

UART RX 寄存器由应用程序代码(在后台执行)和中断代码(在前台执行)共享。

如果您不禁用 UART RX 中断,则您的应用程序代码可能会在读取过程中中断并出现错误。

共享资源必须这样读取:

char a;
uart__disable_rx_interrupt();   // Begin of critical section
a = UART_RX_REGISTER;
uart__enable_rx_interrupt();    // End of critical section

然而:

应用程序代码不应过于频繁地禁用 UART RX 中断,因为 UART 接口可能会错过一些传入数据。

这件事发生在 1996 年。

理想的代码应用程序代码应为 9600 波特率:

char a;
sleep(100);   // 100 ms
uart__disable_rx_interrupt();   // Begin of critical section
a = UART_RX_REGISTER;
uart__enable_rx_interrupt();    // End of critical section
printf(a);

最后一件事;

通常,数据被放置在环形缓冲区中

sleep(100);   // 100 ms
uart__disable_rx_interrupt();   // Begin of critical section
a = UART_RX_REGISTER;
uart__write_in_ring_buffer(a);
uart__enable_rx_interrupt();    // End of critical section
uart__write_in_ring_buffer(&ch);
printf(ch);

建议您阅读 Jean Labrosse 的书:“https://www.amazon.it/Embedded-Systems-Building-Blocks-Ready/dp/0879304405”

研究Jean使用环形缓冲区编写的UART设备驱动程序。