-
Notifications
You must be signed in to change notification settings - Fork 124
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Modeling of AFL/AFH registers presents a bit of a footgun #206
Comments
(Side note: in cases like this I really wish there were a way to have rustc turn certain guaranteed-at-runtime panics into compile errors! Like a semi-static assert. My indices to these arrays will almost always be constants, and so the assert will either be optimized out, or will end the program, but either way the compile will succeed.) |
yeah, that's exactly the reason why it is like this :) stm32-rs PACs don't have this issue because they simply don't arrayify AFRx/AFSELx. It has two downsides:
I don't see any easy way to fix it... The yaml matches how the registers are: 2 AFRx regs with 8 fields each. |
I don't use HALs, but even in non-HAL code, the stm32-rs approach to the GPIO registers in general forces horrible code duplication or macros. So I definitely sympathize with wanting to avoid that. I also don't see an easy fix, and I agree that the YAML matches reality. I am concerned about the indices in the top register not matching what the user might expect though. One approach that I do not recommend would be wrapping the afrl/afrh register pair in some kind of abstraction that makes it look like one register. Many of my applications depend on being able to reason about when, exactly, the alternate function switches, for correctness and to avoid glitching pins -- the current API allows this by making writes to each register explicit. Presenting them as a pair would open the question of which are written, in what order, and with how many cycles between. (I don't mean to imply that I think you're considering this option, but that doesn't mean someone else won't consider it!) Edit: I think perhaps the best "fix" here is an expansion of the rustdoc on these registers, to explain the potential error and why it exists. I can have a look at doing that. |
.......so if you're trying to keep this language-independent...where do I put a rustdoc block containing a Rust code example to attach to the AFR registers? The YAML file isn't right because it won't make sense to C or Python or Cobol programmers. |
yeah I dont' think adding a |
I've now ported a nontrivial firmware application over to stm32-metapac and I'm delighted with the results. It has enabled me to extend my G0 prototype to support C011 with very few code changes. So, thank you for all the hard work there.
I ran into something interesting during the porting process. First, I kept getting zero-byte binaries, but this was my own mistake. (In case anyone's reading this with that problem: make sure you've specified the
rt
andpac
features and included the-Tlink.x
linker arg in your target triple. And not, say, in a different but unrelated target triple you copied from another project. Learn from my mistakes.)Then I started getting very small binaries -- like 5 kiB instead of the ~18 kiB I was expecting. This is almost always a sign that rustc has decided that some code has become an unconditional panic or UB and eliminated the rest of the program.
After spending some time hunting and reading the machine code, the problem turned out to be my use of the AFRH register in the GPIO block. Previously, using the traditional PAC, I had
During the port to the metapac, I rewrote this code to
(This reflects the discovery that the registers described in the reference manual as AFRL / AFRH are modeled in the metapac as a two-element array -- which I'm not totally convinced about, but I can see the advantages for HALs!)
This code was compiling into an unconditional program-ending panic. Perhaps you can see the problem already. :-) If, like me, it isn't obvious, the answer is: the
AFR
field arrays in each of the two AFRx registers are treated as 8-element arrays. This means to set (say) AFRH9, you need toset_afr(1, 1)
instead ofset_afr(9, 1)
.Given that the fields in the AFRH register are numbered from 8 in the reference manual and all other SDKs, this seems like it's going to bite other people in the future. I've altered my code to use
set_afr(9 - 8, 1)
to try and remind me what's going on in the future.I wonder if you can think of a way to address? Since the setters already contain an index-checking assert, I suppose they could insist that the accesses start at 8 and subtract 8, but... even though that would have fixed my bug, it seems really weird and inconsistent.
Allowing the use of constants for the indices maybe? Passing
AFR8
which is secretly equivalent to 0 would make the code easier to read in terms of the datasheet. However, since the registers are modeled as an array, the types of AFRL and AFRH must match -- meaning that this would open the risk of usingAFR8
as an index to AFRL, which would be bad.Anyway, as you can probably infer from my questions, I don't see a super obvious fix here -- but I wanted to raise it before it surprises other people.
The text was updated successfully, but these errors were encountered: