ZigEmbeddedGroup / microzig

Unified abstraction layer and HAL for several microcontrollers
zlib License
1.25k stars 102 forks source link

RP2040 Clock Control Refactor #239

Closed haydenridd closed 1 month ago

haydenridd commented 1 month ago

This is the result of a couple weeks of twiddling and testing to create a clock interface with the high level goals of:

I'll highlight and explain a couple of the fundamental changes below.

Compile Time Interface for Generator

The RP2350 and RP2040 are very similar in their clock configs, but have just enough differences to warrant some sort of compile time interface. clocks/common.zig defines various functions and methods that are common to both chips. clocks/rp2040.zig defines behavior that is specific to the RP2040, and soon there will be a clocks/rp2350.zig to match. This is fairly self-explanatory when you look at the code, as the two different chips have slightly different options for clock sources, tick counters, etc.

Separating "Easy Mode" and "Hard Mode"

The configuration API has been reworked in order to provide a clear separation between the path of least resistance to getting a working clock configuration, and the "expert" focused custom clock configuration path.

clocks.config.preset provides helper functions for generating the full config.Global without having to get into the weeds. default() provides the same behavior as what currently gets configured, system() allows you to divide down the SYS and REF clock frequencies to lower levels, and output_to_gpio() lets you easily MUX + divide down a specified clock to a GPIO. The HAL now calls clocks.config.preset.default() to establish the global clock_config constant that users will usually pass to other HAL APIs so that they can determine what the current SYS clock frequency is.

On the other hand, there is nothing to stop a user from hand rolling their own config.Global, and overriding init() to provide their own clock initialization sequence.

I've added some examples showcasing how someone would go about fiddling with clocks in:

ALL the comptime Checks

I've added a TON of comptime checks to the various configuration methods to ensure that:

This does force clock configurations to be comptime known, however at the point where you need true runtime dynamic modification of your system clocks, you are doing something way, way more complicated than this HAL can support. In theory there's nothing to stop us from also supporting non-comptime known configuration, it would just require a ton more scaffolding code (think apply() vs apply_runtime()) that I just don't think is worth it. The existing API must be comptime known anyways.