C PIC32 USART_BufferAddПрочитать потерянные байты

в моем проекте мне нужно подключить через UART PIC32MZ2048EFH144 и внешнее устройство. Я установил периферийное устройство USART таким образом, используя Harmony v1.1:

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, 0x00, 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, 0, 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;
    }
}

Есть идеи о моих ошибках?

С уважением,

Винченцо.


person Vincenzo Cristiano    schedule 24.03.2021    source источник
comment
Есть ли у вас возможность изменить основные часы или часы подсистемы, чтобы увеличить скорость процессора? На платах TI я видел пропуск символов UART при передаче с более низкими тактовыми частотами подсистемы, такими как 3 МГц, но увеличение до 12 МГц устраняет проблему. У меня нет PIC32, но подозреваю, что поведение UART будет аналогичным. (Я синхронизирую часы ПК с часами MSP432, отправляя дату/время в формате POSIX, при более низких часах несколько символов будут отброшены)   -  person David C. Rankin    schedule 24.03.2021
comment
Привет @DavidC.Rankin, я думаю, что проблема не в тактовой частоте, а в синхронизации. Но, честно говоря, я не знаю, как это исправить.   -  person Vincenzo Cristiano    schedule 24.03.2021


Ответы (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);

Я предлагаю вам прочитать книгу Жана Лаброса: https://www.amazon.it/Embedded-Systems-Building-Blocks-Ready/dp/0879304405

Изучите драйвер устройства UART, написанный Джин с использованием кольцевого буфера.

person Enrico Migliore    schedule 24.03.2021
comment
Привет, Энрико, DRV_USART_BufferAddRead предоставляется структурой Harmony, и, зайдя внутрь, я вижу, что прерывание отключено. Вы предлагаете сделать что-то подобное? res = SYS_INT_SourceDisable(INT_SOURCE_USART_4_RECEIVE), а затем DRV_USART_BufferAddRead(mtiData.drvUART.handle, &(mtiData.drvUART.RX.bufferHandle), readBuffer, bufferSize); } - person Vincenzo Cristiano; 24.03.2021
comment
Постоянно вызываемый цикл while() может быть проблемой. Поместите sleep(100) или задержку цикла for в цикл while(). Также поищите пример Harmony. - person Enrico Migliore; 24.03.2021
comment
Пример Harmony использует FSM для записи и чтения. Обязательно ли использовать FSM для реализации асинхронного поведения? Я уже внутри FSM - person Vincenzo Cristiano; 24.03.2021