STM32CubeMXコードジェネレータが出力するUART(USART)のコードについて。
![mb-stm32f103_001.jpg]()
以下の様な送信/受信関数が提供されます。
HAL_UART_Transmit、HAL_UART_Receiveはブロッキングインタフェースで、内部で送信レジスタ、受信レジスタを監視して動作していますが、それ以下の関数は割り込みとDMAを併用するノンブロッキングインタフェースとなっています。
それぞれの関数は、引数のデータ数に送信や受信が達する事で完了となります。
それ以前に再びこの関数が呼ばれた時は、戻り値にHAL_BUSYが返ります。
つまり問題は受信時に処理を完了させる要素が引数の受信データ数となっている点ですね。
送信はイイのですよ、事前に送信データのサイズは明確にできますから。
ですが受信の場合相手がいる訳ですから、実際に受信するデータの数が事前に判る状況はあまり無いでしょう。
100byteデータを受信するとなっても、通信ですから途中でなにが起こるか判らない。
受信サイズを100byteとしてしまって途中で1byteこけた場合はそのまま処理が永久に?完了しない事となります。
ブロッキングインタフェースの場合は引数にタイムアウトを設定できるので、タイムアウトを使う事でプログラムが不動となる事は避けられそうです。
しかしノンブロッキングインタフェースではタイムアウトは設定されていないので、1byteでも受信数が少ない場合は不動となる可能性が有ります。
逆に言えば受信データ数には1を超える数字を設定しなければイイ!と言う、高機能な関数を消極的な使い方をすれば解決できそうです、、、orz
ついでにリングバッファを構成しましょう。
※usart1とusart2を使えるようにした。
※USARTのコンフィギュレーションは別のところで行ってる。
※includeなどは省いている。
※usart2はループバック、usart1はTeratermに接続している。

以下の様な送信/受信関数が提供されます。
HAL_StatusTypeDef HAL_UART_Transmit(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout); HAL_StatusTypeDef HAL_UART_Receive(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout); HAL_StatusTypeDef HAL_UART_Transmit_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size); HAL_StatusTypeDef HAL_UART_Receive_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size); HAL_StatusTypeDef HAL_UART_Transmit_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size); HAL_StatusTypeDef HAL_UART_Receive_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size);
HAL_UART_Transmit、HAL_UART_Receiveはブロッキングインタフェースで、内部で送信レジスタ、受信レジスタを監視して動作していますが、それ以下の関数は割り込みとDMAを併用するノンブロッキングインタフェースとなっています。
それぞれの関数は、引数のデータ数に送信や受信が達する事で完了となります。
それ以前に再びこの関数が呼ばれた時は、戻り値にHAL_BUSYが返ります。
つまり問題は受信時に処理を完了させる要素が引数の受信データ数となっている点ですね。
送信はイイのですよ、事前に送信データのサイズは明確にできますから。
ですが受信の場合相手がいる訳ですから、実際に受信するデータの数が事前に判る状況はあまり無いでしょう。
100byteデータを受信するとなっても、通信ですから途中でなにが起こるか判らない。
受信サイズを100byteとしてしまって途中で1byteこけた場合はそのまま処理が永久に?完了しない事となります。
ブロッキングインタフェースの場合は引数にタイムアウトを設定できるので、タイムアウトを使う事でプログラムが不動となる事は避けられそうです。
しかしノンブロッキングインタフェースではタイムアウトは設定されていないので、1byteでも受信数が少ない場合は不動となる可能性が有ります。
逆に言えば受信データ数には1を超える数字を設定しなければイイ!と言う、高機能な関数を消極的な使い方をすれば解決できそうです、、、orz
ついでにリングバッファを構成しましょう。
※usart1とusart2を使えるようにした。
※USARTのコンフィギュレーションは別のところで行ってる。
※includeなどは省いている。
※usart2はループバック、usart1はTeratermに接続している。
HAL_StatusTypeDef usartWrite( UART_HandleTypeDef *huart, const uint8_t *data, uint16_t size ); HAL_StatusTypeDef usartPutc( UART_HandleTypeDef *huart, char c ); HAL_StatusTypeDef usartPuts( UART_HandleTypeDef *huart, const char *str ); int usartGetc( UART_HandleTypeDef *huart ); int usartAvailable( UART_HandleTypeDef *huart ); static struct P_USART_RCV_INFORMATIONS { char *rcvBuf; uint16_t wptr,rptr; uint16_t overWrite; uint16_t bufferSize; } pUsartRcvInfo[2]; static char rx1Buffer[ 256 ]; /* recieve ring buffer. */ static char rx2Buffer[ 256 ]; /* recieve ring buffer. */ void user( void ) { volatile int count = 1; HAL_StatusTypeDef result; pUsartRcvInfo[0].rcvBuf = rx1Buffer; pUsartRcvInfo[0].wptr = pUsartRcvInfo[0].rptr = pUsartRcvInfo[0].overWrite = 0; pUsartRcvInfo[0].bufferSize = sizeof(rx1Buffer); pUsartRcvInfo[1].rcvBuf = rx2Buffer; pUsartRcvInfo[1].wptr = pUsartRcvInfo[1].rptr = pUsartRcvInfo[1].overWrite = 0; pUsartRcvInfo[1].bufferSize = sizeof(rx2Buffer); HAL_UART_Receive_IT( &huart1, (uint8_t *)&pUsartRcvInfo[0].rcvBuf[ pUsartRcvInfo[0].wptr ], 1 ); HAL_UART_Receive_IT( &huart2, (uint8_t *)&pUsartRcvInfo[1].rcvBuf[ pUsartRcvInfo[1].wptr ], 1 ); while (1) { char buf[128]; sprintf( buf, "hello world. count = %d\r\n", count++ ); result = usartPuts( &huart2, (const char *)buf ); if( result != HAL_OK ) { debugPrint( "uart2 transmit was not success. error code = %d\r\n", result ); } HAL_Delay( 10UL ); while( 1 ) { int c = usartGetc( &huart2 ); if( c < 0 ) break; usartPutc( &huart1, c ); } HAL_Delay( 90UL ); } } HAL_StatusTypeDef usartWrite( UART_HandleTypeDef *huart, const uint8_t *data, uint16_t size ) { HAL_StatusTypeDef result; //while( (result = HAL_UART_Transmit( huart, (uint8_t *)data, size, 100UL )) == HAL_BUSY ) {} while( (result = HAL_UART_Transmit_IT( huart, (uint8_t *)data, size )) == HAL_BUSY ) {} return result; } HAL_StatusTypeDef usartPutc( UART_HandleTypeDef *huart, char c ) { return usartWrite( huart, (const uint8_t *)&c, 1 ); } HAL_StatusTypeDef usartPuts( UART_HandleTypeDef *huart, const char *str ) { return usartWrite( huart, (const uint8_t *)str, strlen(str) ); } int usartGetc( UART_HandleTypeDef *huart ) { int c; uint16_t next; if( huart->Instance == USART1 ) { if( pUsartRcvInfo[0].rptr == pUsartRcvInfo[0].wptr ) return (-1); /* */ next = pUsartRcvInfo[0].rptr + 1; if( next >= pUsartRcvInfo[0].bufferSize ) next = 0; c = pUsartRcvInfo[0].rcvBuf[ pUsartRcvInfo[0].rptr ] & 0x00ff; pUsartRcvInfo[0].rptr = next; } else if( huart->Instance == USART2 ) { if( pUsartRcvInfo[1].rptr == pUsartRcvInfo[1].wptr ) return (-1); /* */ next = pUsartRcvInfo[1].rptr + 1; if( next >= pUsartRcvInfo[1].bufferSize ) next = 0; c = pUsartRcvInfo[1].rcvBuf[ pUsartRcvInfo[1].rptr ] & 0x00ff; pUsartRcvInfo[1].rptr = next; } return c; } int usartAvailable( UART_HandleTypeDef *huart ) { if( huart->Instance == USART1 ) { if( pUsartRcvInfo[0].wptr >= pUsartRcvInfo[0].rptr ) { return pUsartRcvInfo[0].wptr - pUsartRcvInfo[0].rptr; } else { return (pUsartRcvInfo[0].bufferSize + pUsartRcvInfo[0].wptr) - pUsartRcvInfo[0].rptr; } } else if( huart->Instance == USART2 ) { if( pUsartRcvInfo[1].wptr >= pUsartRcvInfo[1].rptr ) { return pUsartRcvInfo[1].wptr - pUsartRcvInfo[1].rptr; } else { return (pUsartRcvInfo[1].bufferSize + pUsartRcvInfo[1].wptr) - pUsartRcvInfo[1].rptr; } } return 0; } #if 0 /** * @brief Tx Transfer completed callbacks. * @param huart: pointer to a UART_HandleTypeDef structure that contains * the configuration information for the specified UART module. * @retval None */ void HAL_UART_TxCpltCallback( UART_HandleTypeDef *huart ) { } #endif /** * @brief Rx Transfer completed callbacks. * @param huart: pointer to a UART_HandleTypeDef structure that contains * the configuration information for the specified UART module. * @retval None */ void HAL_UART_RxCpltCallback( UART_HandleTypeDef *huart ) { uint16_t next; if( huart->Instance == USART1 ) { next = pUsartRcvInfo[0].wptr + 1; if( next >= pUsartRcvInfo[0].bufferSize ) next = 0; if( next == pUsartRcvInfo[0].rptr ) /* do not permit over write. */ { pUsartRcvInfo[0].overWrite++; return; } pUsartRcvInfo[0].wptr = next; HAL_UART_Receive_IT( huart, (uint8_t *)&pUsartRcvInfo[0].rcvBuf[ pUsartRcvInfo[0].wptr ], 1 ); } else if( huart->Instance == USART2 ) { next = pUsartRcvInfo[1].wptr + 1; if( next >= pUsartRcvInfo[1].bufferSize ) next = 0; if( next == pUsartRcvInfo[1].rptr ) /* do not permit over write. */ { pUsartRcvInfo[1].overWrite++; return; } pUsartRcvInfo[1].wptr = next; HAL_UART_Receive_IT( huart, (uint8_t *)&pUsartRcvInfo[1].rcvBuf[ pUsartRcvInfo[1].wptr ], 1 ); } }