がれすたさんのDIY日記

電子回路、Python、組み込みシステム開発、自作エフェクターを語るblog

MIMXRT10xxのUART割り込みメモ

UARTの割り込みについて少し迷ったのでメモ代わりに残しておく。
コードに関しては公式のサンプル内にあるlpuart_interrupt_rb_transferってやつを参考に解説しているので全容はそっちを見てください。

送受信APIの確認

まず割り込みには以下に示すの二つのAPIを使うことになる。

LPUART_TransferReceiveNonBlocking(LPUART_Type *base,
                              lpuart_handle_t *handle,
                              lpuart_transfer_t *xfer,
                              size_t *receivedBytes)
LPUART_TransferSendNonBlocking(LPUART_Type *base,
                              lpuart_handle_t *handle, 
                              lpuart_transfer_t *xfer)

handleはLPUART1のような感じでLPUARTモジュールのハンドルを渡す。
xferはデータ構造そのもので

typedef struct _lpuart_transfer
{
    uint8_t *data;   /*!< The buffer of data to be transfer.*/
    size_t dataSize; /*!< The byte count to be transfer. */
} lpuart_transfer_t;

のように定義している。

実際の使い方

実際の使い方はこんな感じ

LPUART_GetDefaultConfig(&config);//デフォルト設定を読み込む
config.baudRate_Bps = BOARD_DEBUG_UART_BAUDRATE;//このマクロだと115200
config.enableTx = true;//送信有効
config.enableRx = true;//受信有効
LPUART_Init(DEMO_LPUART, &config, DEMO_LPUART_CLK_FREQ);//初期化はポーリングと同じ


/*
 *ハンドルの生成
 *この時点でコールバック関数も登録する。
 *この例ではUserdataがNULLになっているがコールバックに何かデータ渡したいならここにポインタを入れる
 */
LPUART_TransferCreateHandle(DEMO_LPUART, &g_lpuartHandle, LPUART_UserCallback, NULL);


/*
 *リングバッファの有効
 *これの有無でLPUART_TransferReceiveNonBlocking内部での処理が変わる(後述)
 */
LPUART_TransferStartRingBuffer(DEMO_LPUART, &g_lpuartHandle, g_rxRingBuffer, RX_RING_BUFFER_SIZE);

/*
 *xfer構造体にバッファの登録をする。
 *データ構造はこの構造体が決めるのでデータプロトコルが複数ある場合は複数用意しておくと可視性が上がる
*/
xfer.data = g_tipString;//バッファは各自用意する
xfer.dataSize = sizeof(g_tipString) - 1;//サイズも各自編集

/*
 * ノンブロッキング送信API
 * 送信完了後コールバックに飛ぶ
 * あとはxfer構造体のバッファーにデータをセットしてこいつをコールすればいい
 *
*/
LPUART_TransferSendNonBlocking(DEMO_LPUART, &g_lpuartHandle, &xfer);

/*
 * ノンブロッキング受信API
 * 受信完了後コールバックに飛ぶ
*/
LPUART_TransferReceiveNonBlocking(DEMO_LPUART, &g_lpuartHandle, &receiveXfer, &receivedBytes);

リングバッファの話についてだがLPUART_TransferReceiveNonBlockingの中にコメント解説がある。

/* How to get data:

       1. If RX ring buffer is not enabled, then save xfer->data and xfer->dataSize
          to lpuart handle, enable interrupt to store received data to xfer->data. When
          all data received, trigger callback.
       2. If RX ring buffer is enabled and not empty, get data from ring buffer first.
          If there are enough data in ring buffer, copy them to xfer->data and return.
          If there are not enough data in ring buffer, copy all of them to xfer->data,
          save the xfer->data remained empty space to lpuart handle, receive data
          to this empty space and trigger callback when finished. 
*/

用はLPUART_TransferStartRingBufferをコールして有効にしていると受信レジスタとxfer->dataの間にリングバッファが挟まるという感じです。
直訳するとリングバッファーに十分なデータがある場合は、それらをxfer-> dataにコピーして戻る。
リングバッファーに十分なデータがない場合は、それらすべてをxfer-> dataにコピーし、xfer-> dataの空きスペースをlpuartハンドルに保存。そのあとこの空きスペースにデータを受信し、終了時にコールバックをトリガーします。

LPUART_TransferReceiveNonBlockingで設定したデータ数が受信されるまでリングバッファとxfer-> data内でやりくりしてくれる。
あとは公式サンプルのようにrxOnGoing変数を監視してLPUART_TransferReceiveNonBlockingをコールしてもいいし

LPUART_TransferReceiveNonBlockingの返り値がステータスなのでそいつを頼りにしてBusyなら再コールするなりで対応すればいいと思います。


タイマーで定期的に受信したいなら

if(g_lpuartHandle.rxState == kStatus_LPUART_RxIdle){........}

みたいな書き方でもいいと思う