web-dev-qa-db-ja.com

この場合、UART送信割り込みが機能しないのはなぜですか?

Stm32f0MCUを使用しています。

私は単純なUARTエコーコードを持っており、受信したすべてのバイトが送信されます。それが機能することをテストしました。これが;

_uint8_t Rx_data[5]; 
uint32_t tx_timeout = 0;
//Interrupt callback routine
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
    if (huart->Instance == USART1)  //current UART
    {
        HAL_UART_Transmit(&huart1, &Rx_data[0], 1, tx_timeout);        
        HAL_UART_Receive_IT(&huart1, Rx_data, 1);   //activate UART receive interrupt every time on receiving 1 byte
    }
}
_

コードは機能しますが、快適ではありません。まず、_tx_timeout_は0であり、ほとんどのコード例はゼロ以外です。副作用はわかりません。次に、HAL_UART_Transmit()はブロッキング呼び出しであり、割り込み内でブロッキング呼び出しを使用することはお勧めできません。そこで、呼び出しをブロックする代わりに、uart送信HAL_UART_Transmit_IT()に割り込みを使用することにしました。これが変更されたコードです。

_uint8_t Rx_data[5]; 
uint32_t tx_timeout = 0;
//Interrupt callback routine
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
    if (huart->Instance == USART1)  //current UART
    {
        HAL_UART_Transmit_IT(&huart1, &Rx_data[0], 1);        
        HAL_UART_Receive_IT(&huart1, Rx_data, 1);   //activate UART receive interrupt every time on receiving 1 byte
    }
}
_

ただし、期待どおりに動作しません。私のPCはASCII 12345678をstm32に送信します。正常に動作する場合、PCは12345678を受信します。ただし、PCは代わりに1357を受信します。HAL_UART_Transmit_IT()

4
user781486

最初:

前の質問 nullタイムアウトへの回答で説明されているように、フラグ状態の待機を除外するだけです。開いた場合HAL_UART_Transmit code-タイムアウトなしで1バイトを送信すると、ブロッキング状態が発生しないことがわかります。

2番目:

巨大なHALの関数とそのコールバックから1バイトを送受信するのは本当の方法ではありません。私は推測します:次にあなたの質問は「どうやってそこで解析を実装しなければならないのですか?」でしょう。そして、IRQコールバックに解析関数を挿入しないことを願っています!

したがって、一般的にはバッファが必要です。また、循環バッファを使用することをお勧めします。

mxconstants.h:

/* USER CODE BEGIN Private defines */

/* Buffer's length must be select according to real messages frequency */
#define RXBUF_LEN            128 // must be power of 2
#define TXBUF_LEN            128 // must be power of 2
#define RXBUF_MSK            (RXBUF_LEN-1)
#define TXBUF_MSK            (TXBUF_LEN-1)

/* USER CODE END Private defines */

main.c:

uint8_t rx_buf[RXBUF_LEN], tx_buf[TXBUF_LEN];
/* xx_i - counter of input bytes (tx - pushed for transmit, rx - received)
   xx_o - counter of output bytes (tx - transmitted, rx - parsed)
   xx_e - counter of echoed bytes */
volatile uint16_t rx_i = 0, tx_o = 0;
uint16_t rx_o = 0, rx_e = 0, tx_i = 0;
volatile uint8_t tx_busy = 0;

void transmit(uint8_t byte) 
{
    tx_buf[TXBUF_MSK & tx_i] = byte;
    tx_i++;
    tx_busy = 1;
    __HAL_UART_ENABLE_IT(&huart1, UART_IT_TXE);
}

void main(void)
{
    /* Initialization code */
    /* ... */
    /* Enable usart 1 receive IRQ */
    __HAL_UART_ENABLE_IT(&huart1, UART_IT_RXNE);
    for (;;) {
        /* Main cycle */
        while (rx_i != rx_e) {
            /* echo here */
            transmit(rx_buf[RXBUF_MSK & rx_e]);
            rx_e++;
        }
        while (rx_i != rx_o) {
            /* parse here */
            /* ... */
            rx_o++;
        }
        /* Power save 
        while (tx_busy);
        HAL_UART_DeInit(&huart1);
        */
    }
}

stm32f0xx_it.c:

extern uint8_t rx_buf[RXBUF_LEN], tx_buf[TXBUF_LEN];
extern volatile uint16_t rx_i, tx_o;
extern uint16_t rx_o, rx_e, tx_i;
extern volatile uint8_t tx_busy;

void USART1_IRQHandler(void)
{
    /* USER CODE BEGIN USART1_IRQn 0 */
    if((__HAL_UART_GET_IT(&huart1, UART_IT_RXNE) != RESET) && 
       (__HAL_UART_GET_IT_SOURCE(&huart1, UART_IT_RXNE) != RESET))
    {
        rx_buf[rx_i & RXBUF_MSK] = (uint8_t)(huart1.Instance->RDR & 0x00FF);
        rx_i++;
        /* Clear RXNE interrupt flag */
        __HAL_UART_SEND_REQ(&huart1, UART_RXDATA_FLUSH_REQUEST);
    }
    if((__HAL_UART_GET_IT(&huart1, UART_IT_TXE) != RESET) &&
       (__HAL_UART_GET_IT_SOURCE(&huart1, UART_IT_TXE) != RESET))
    {
        if (tx_i == tx_o) {
            __HAL_UART_DISABLE_IT(&huart1, UART_IT_TXE);
            __HAL_UART_ENABLE_IT(&huart1, UART_IT_TC);
        } else {
            huart1.Instance->TDR = (uint8_t)(tx_buf[TXBUF_MSK & tx_o] & (uint8_t)0xFF);
            tx_o++;
        }
    }
    if((__HAL_UART_GET_IT(&huart1, UART_IT_TC) != RESET) &&
       (__HAL_UART_GET_IT_SOURCE(&huart1, UART_IT_TC) != RESET))
    {
        tx_busy = 0;
        __HAL_UART_DISABLE_IT(&huart1, UART_IT_TC);
    }
    /* And never call default handler */
    return;
    /* USER CODE END USART1_IRQn 0 */

    HAL_UART_IRQHandler(&huart1);

    /* USER CODE BEGIN USART1_IRQn 1 */
    /* USER CODE END USART1_IRQn 1 */
}

そして3番目!!!

そしてこれについて:

HAL_UART_Transmit_ITが役に立たない/機能しないのはなぜですか?

遅すぎるから!そして、あなたが数えようとするとHAL_BUSY 結果:

uint8_t Rx_data[5]; 
uint32_t tx_timeout = 0;
//Interrupt callback routine
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
    static uint32_t hal_busy_counter = 0;
    if (huart->Instance == USART1)  //current UART
    {
        if (HAL_UART_Transmit_IT(&huart1, &Rx_data[0], 1) == HAL_BUSY) {
            hal_busy_counter++;
        }        
        HAL_UART_Receive_IT(&huart1, Rx_data, 1);   //activate UART receive interrupt every time on receiving 1 byte
    }
}

データ交換後にデバッガーでMCUを一時停止すると、驚かれることでしょう。これは、失われた文字の数と同じになります。

9
imbearr