/ * @brief * Configure USART operating in synchronous mode to use a given baudrate * (or as close as possible to specified baudrate). * * @details * The configuration will be set to use a baudrate <= the specified baudrate * in order to ensure that the baudrate does not exceed the specified value. * * Fractional clock division is suppressed, although the HW design allows it. *
| 409 | * Baudrate to try to achieve for USART. |
| 410 | ******************************************************************************/ |
| 411 | void USART_BaudrateSyncSet(USART_TypeDef *usart, uint32_t refFreq, uint32_t baudrate) |
| 412 | { |
| 413 | uint32_t clkdiv; |
| 414 | |
| 415 | /* Inhibit divide by 0 */ |
| 416 | EFM_ASSERT(baudrate); |
| 417 | |
| 418 | /* |
| 419 | * We want to use integer division to avoid forcing in float division |
| 420 | * utils, and yet keep rounding effect errors to a minimum. |
| 421 | * |
| 422 | * CLKDIV in synchronous mode is given by: |
| 423 | * |
| 424 | * CLKDIV = 256 * (fHFPERCLK/(2 * br) - 1) |
| 425 | * or |
| 426 | * CLKDIV = (256 * fHFPERCLK)/(2 * br) - 256 = (128 * fHFPERCLK)/br - 256 |
| 427 | * |
| 428 | * The basic problem with integer division in the above formula is that |
| 429 | * the dividend (128 * fHFPERCLK) may become higher than max 32 bit |
| 430 | * integer. Yet, we want to evaluate dividend first before dividing in |
| 431 | * order to get as small rounding effects as possible. We do not want |
| 432 | * to make too harsh restrictions on max fHFPERCLK value either. |
| 433 | * |
| 434 | * One can possibly factorize 128 and br. However, since the last |
| 435 | * 6 bits of CLKDIV are don't care, we can base our integer arithmetic |
| 436 | * on the below formula without loosing any extra precision: |
| 437 | * |
| 438 | * CLKDIV / 64 = (2 * fHFPERCLK)/br - 4 |
| 439 | * |
| 440 | * and calculate 1/64 of CLKDIV first. This allows for fHFPERCLK |
| 441 | * up to 2GHz without overflowing a 32 bit value! |
| 442 | */ |
| 443 | |
| 444 | /* HFPERCLK used to clock all USART/UART peripheral modules */ |
| 445 | if (!refFreq) |
| 446 | { |
| 447 | refFreq = CMU_ClockFreqGet(cmuClock_HFPER); |
| 448 | } |
| 449 | |
| 450 | /* Calculate and set CLKDIV with fractional bits */ |
| 451 | clkdiv = 2 * refFreq; |
| 452 | clkdiv += baudrate - 1; |
| 453 | clkdiv /= baudrate; |
| 454 | clkdiv -= 4; |
| 455 | clkdiv *= 64; |
| 456 | /* Make sure we don't use fractional bits by rounding CLKDIV */ |
| 457 | /* up (and thus reducing baudrate, not increasing baudrate above */ |
| 458 | /* specified value). */ |
| 459 | clkdiv += 0xc0; |
| 460 | clkdiv &= 0xffffff00; |
| 461 | |
| 462 | /* Verify that resulting clock divider is within limits */ |
| 463 | EFM_ASSERT(clkdiv <= _USART_CLKDIV_MASK); |
| 464 | |
| 465 | /* If EFM_ASSERT is not enabled, make sure we don't write to reserved bits */ |
| 466 | clkdiv &= _USART_CLKDIV_DIV_MASK; |
| 467 | |
| 468 | usart->CLKDIV = clkdiv; |
no test coverage detected