发在ST论坛上的,转一份过来。这个bug很早就有了,而且算法也写得太复杂了点。
This error lasts a long long time, and maybe still exists other version of stdperiph or Cube.
In STM32Cube_FW_F4_V1.5.0 the error is in this line of stm32f4xx_hal_uart.h:
#define UART_BRR_SAMPLING8(_PCLK_, _BAUD_) ((UART_DIVMANT_SAMPLING8((_PCLK_), (_BAUD_)) << 4)|(UART_DIVFRAQ_SAMPLING8((_PCLK_), (_BAUD_)) & 0x0F))
should be:
#define UART_BRR_SAMPLING8(_PCLK_, _BAUD_) ((UART_DIVMANT_SAMPLING8((_PCLK_), (_BAUD_)) << 4)|(UART_DIVFRAQ_SAMPLING8((_PCLK_), (_BAUD_)) & 0x07))
Can I complain about the too complex algorithm?
When oversampling by 16, the divide rate is PCLK/(BAUD*16). We have 4 bit fraction in BRR register, then:
BRR = ((PCLK/(BAUD*16))<<4 = PCLK/BAUD. Isn't that simple?
In most case when PCLK/BAUD>100, you can ignore the truncation error.
Or you can use use the rounding to be more accurate: BRR = (PCLK+BAUD/2)/BAUD
Now we can replace UART_BRR_SAMPLING16 macro with:
#define UART_BRR_SAMPLING16(_PCLK_, _BAUD_) (((_PCLK_)+(_BAUD_)/2)/_BAUD_)
When oversampling by 8, the divide rate is PCLK/(BAUD*8).
In manual: "When OVER8=1, the DIV_Fraction3 bit is not considered and must be kept cleared." means BRR register has 3 bit fraction, and 1 bit blank.
Then BBR=(PCLK/(BAUD*8))<<3 = PCLK/BAUD, same result except that one blank bit is inserted in bit3.
Following inline function can replace the UART_BRR_SAMPLING8 Macro:
__INLINE static uint16_t UART_BRR_SAMPLING8(uint32_t _PCLK_, uint32_t _BAUD_)
{
uint16_t Div = (_PCLK_ + _BAUD_/2)/_BAUD_; //result in 3 bit fraction, 15 bit Mantissa
//When OVER8=1, the DIV_Fraction3 bit is not considered and must be kept cleared.
uint16_t DIV_Mantissa = (Div & ~0x7)<<1;
uint16_t DIV_Fraction = Div & 0x07
return (DIV_Mantissa | DIV_Fraction);
}
Variable DIV_Mantissa and DIV_Fraction are used for more clear.
my git commit:
https://github.com/skywolf/STM32 ... 0859f5a82087af4afeb
https://git.oschina.net/dingtu/S ... 0859f5a82087af4afeb |