Repository navigation
Fix overflow of the UART fractional baud rate divisor - #1012
Merged
Merged
Conversation
calculate_baudrate_dividers() rounded only the fractional part of the divisor, so whenever the lower 7 bits of 8 * clk / baud were 0x7F the fractional value became 64. UARTFBRD is 6 bits wide, so that got truncated to 0 while the integer part was not incremented, e.g. 57871 baud at 125 MHz was programmed as 134 + 0/64 instead of 135 + 0/64. Round the whole divisor to the nearest 1/64 before splitting it, as the C SDK does since raspberrypi/pico-sdk#1774. Fixes #820
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #820.
calculate_baudrate_dividers()only rounded the fractional part of the divisor:When the low 7 bits of
8 * clk / baudare0x7F, the fractional part rounds up to 64.UARTFBRD.BAUD_DIVFRACis only 6 bits wide, so it is written as 0 and the integer part is not incremented. For example 57871 baud at 125 MHz was programmed as 134 + 0/64 instead of 135 + 0/64 (the jump to ~58300 baud that @KisImre measured). The error is about1 / divint, so it gets large at high baud rates.This change rounds the whole divisor to the nearest 1/64 before splitting it, so the carry goes into the integer part. That gives the same result as the C SDK after raspberrypi/pico-sdk#1774 (
baud_rate_div = 8 * clk / baud + 1; ibrd = baud_rate_div >> 7; fbrd = (baud_rate_div & 0x7f) >> 1). I checked that every value of8 * clk / baudup to 2^20 gives the same result. The only values that change are the carry cases, which previously came out as(n, 64)and now come out as(n + 1, 0). The same change is applied to bothrp2040-halandrp235x-hal, which have identical copies of the function. The match is re-indented only because rustfmt now putsOk(match ...)on one line.I added host unit tests in both crates:
(67, 52).(135, 0). Before this change it gave(134, 64).Tested:
cargo test --tests --features critical-section-implandcargo test --doc --features critical-section-implinrp2040-halandrp235x-hal.thumbv6m-none-eabi,thumbv8m.main-none-eabihfandriscv32imac-unknown-none-elf.cargo clippy -- -D warningsandcargo fmt -- --check.I have not tested this on hardware.