Wie kann man in einem Harmony USART BufferEventHandler zwischen einem Lese- und einem Schreibvorgang unterscheiden?

Ich möchte den Harmony USART-Treiber auf einem PIC32MX695F512H mit Interrupts und Pufferunterstützung verwenden. Nach dem Setzen der entsprechenden Einstellungen im MPLAB Harmony Configurator hat das System die ISR für mich generiert ( system_interrupt.c):

void __ISR(_UART_2_VECTOR, ipl1AUTO) _IntHandlerDrvUsartInstance0(void) {
    DRV_USART_TasksTransmit(sysObj.drvUsart0);
    DRV_USART_TasksReceive(sysObj.drvUsart0);
    DRV_USART_TasksError(sysObj.drvUsart0);
}

Da dies eine generierte Datei ist, gehe ich davon aus, dass ich sie nicht bearbeiten soll. Aber wenn dies die ISR ist, wie kann ich sicherstellen, dass mein Code bei einem RX-Interrupt ausgeführt wird? Ich möchte die empfangenen Daten in einer Funktion erhalten, die ich bearbeiten soll.

So wie ich es verstehe, ist das der Buffer-Event-Handler. Ich kann also Folgendes tun (dieser Code ist stark vereinfacht):

void APP_BufferEventHandler(DRV_USART_BUFFER_EVENT bufferEvent,
        DRV_USART_BUFFER_HANDLE bufferHandle, uintptr_t context) {
    switch (bufferEvent) {
        case DRV_USART_BUFFER_EVENT_COMPLETE:
            // @todo
            break;
        case DRV_USART_BUFFER_EVENT_ERROR:
            appData.state = APP_ERROR;
            break;
        case DRV_USART_BUFFER_EVENT_ABORT:
            appData.state = APP_ERROR;
            break;
    }
}

//... in APP_Tasks somewhere:

    appData.usartHandle = DRV_USART_Open(DRV_USART_INDEX_0,
            DRV_IO_INTENT_READWRITE | DRV_IO_INTENT_NONBLOCKING);
    DRV_USART_BufferEventHandlerSet(appData.usartHandle,
            APP_BufferEventHandler, 0);

Meine Fragen sind:

  1. Ist dies tatsächlich der richtige Weg, um sicherzustellen, APP_BufferEventHandlerdass bei einem RX-Interrupt aufgerufen wird?
  2. Wie kann ich im Ereignishandler zwischen einem RX- und einem TX-Ereignis unterscheiden, wenn das Ereignis eines von COMPLETE, ERRORund ist ABORT?

Antworten (2)

Sie haben ziemlich genau ihr beabsichtigtes Modell richtig. Um Ihre Fragen zu beantworten:

  1. Ja, außer Sie möchten wahrscheinlich einen Kontextparameter weitergeben, wenn Sie die Callback-Handler-Set-Routine aufrufen. So können Sie helfen, die Quelle der Dinge zu identifizieren und damit umzugehen. (Wenn Sie beispielsweise zwei verschiedene, unabhängige „Nachrichtenaufgaben“ zur Übertragung an USART1 senden, gibt der Kontextparameter an, wie Sie wissen, welcher spezifische Absender die Ressource verwendet hat, damit Sie entsprechend handeln können).

Wenn Sie sich ihr Abstraktionsmodell unten ansehen, würden Sie den Kontextparameter verwenden , um festzustellen, auf welchen Client im Ereignishandler verwiesen wird, da mehrere Clients dieselbe USART-Hardware gemeinsam nutzen können.

ABS-Modell

  1. Mit einer Mischung aus den oben genannten Kontextparametern sowie einer gut definierten Zustandsmaschine, die jede Ihrer USARTs-Client-Zustandsmaschinen ausführt. Leider werden die Dinge in Harmony schnell kompliziert.

Unten ist einer ihrer Buffer Event Handler in ihrem USART-Treiberbeispiel. Sie können sehen, dass sie sowohl den Kontextparameter bestätigen als auch, wo ihre USART-Aufgaben-Zustandsmaschine das Ereignis behandeln und die Zustandsmaschine weiterbewegen soll.

C:\microchip\harmony\v1_06_02\apps\driver\usart\usart_loopback\firmware

void APP_BufferEventHandlerUsart1(DRV_USART_BUFFER_EVENT buffEvent,
                            DRV_USART_BUFFER_HANDLE hBufferEvent,
                            uintptr_t context )
{
    switch(buffEvent)
    {   
        /* Buffer event is completed successfully */
        case DRV_USART_BUFFER_EVENT_COMPLETE:
        {
            if((context == 1) &&(appData.usart1State == APP_STATE_USART1_WAIT_FOR_TX_COMPLETION))
            {
                    appData.usart1State = APP_STATE_USART1_WAIT_TO_RX_BACK_DATA;
            }
            else if((context == 1) &&(appData.usart1State == APP_STATE_USART1_WAIT_TO_RX_BACK_DATA))
            {
                    gDataRxedAtUsart1 = true;
                    appData.state = APP_STATE_VERIFY_LOOPBACK_DATA;
            }
        }
        break;
        /* Buffer event has some error */
        case DRV_USART_BUFFER_EVENT_ERROR:
            break;
       default:
            break;
    }
}

Es ist (meiner Meinung nach) schwer zu rechtfertigen, wie komplex es ist, Harmony für irgendetwas anderes als einen riesigen Multitasking-Giganten zum Laufen zu bringen. Wenn Sie jedoch viele Objekte haben, die sich viele Ressourcen teilen, kann es sich lohnen, Harmony auszuprobieren.

Meiner Meinung nach müssen Sie tatsächlich Code in der __ISR hinzufügen. Zum Beispiel:

void __ISR(_UART_1_VECTOR, ipl1AUTO) _IntHandlerDrvUsartInstance0(void) {
    DRV_USART_TasksTransmit(sysObj.drvUsart0);
    DRV_USART_TasksReceive(sysObj.drvUsart0);
    DRV_USART_TasksError(sysObj.drvUsart0);

    //o_LED_ld3 = ~o_LED_ld3; 
    while (!DRV_USART_ReceiverBufferIsEmpty(appData.UsartHandle))
    {
        // read received byte
        appData.rx_byte = DRV_USART_ReadByte(appData.UsartHandle); 
        //UART_Write_Char(appData.rx_byte);
    }
}
Die ISR befindet sich in einer generierten Datei (wie ich in der Frage geschrieben habe), daher halte ich dies nicht für eine gute Idee. Die Änderungen würden beim erneuten Generieren der Datei überschrieben.
Die Hälfte der Tutorials, die Sie zu MPLAB Harmony finden würden, werden Sie dazu bringen, in generierte Dateien (Interrupts, Init usw.) zu schreiben, daher denke ich nicht, dass dies ein gutes Argument ist. Und wenn Sie diese Dateien erneut generieren müssen, zeigt die IDE auf jede von Ihnen vorgenommene Änderung und lässt Sie entscheiden, ob Sie die Änderung beibehalten oder durch die neu generierte Version ersetzen möchten.