Skip to content

stm32: Add method for statically configuring pin alternate function #3952

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

Conversation

andrewleech
Copy link
Contributor

Works with pins declared normally in mpconfigboard.h, eg. (pin_XX)

Provides new mp_hal_pin_config_alt_static(pin_obj, mode, pull, fn, type) function
declared in pin_static_af.h to allow configuring pin alternate functions by name
eg.

mp_hal_pin_config_alt_static(MICROPY_HW_FMC_SDCLK, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, FMC, SDCLK);

For a full usage example see: #3940


#define mp_hal_pin_config_alt_static(pin_obj, mode, pull, fn, type) \
mp_hal_pin_config(pin_obj, mode, pull, STATIC_AF(pin_obj, fn, type)); \
_Static_assert(STATIC_AF(pin_obj, fn, type) != -1, "Missing AF")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be good to use MP_STATIC_ASSERT here. _Static_assert is a C11 feature and we only require C99.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hadn't seen that macro, thanks for the heads up

@andrewleech andrewleech force-pushed the stm32_static_alternate_pins branch from c2d13e9 to 682cb20 Compare July 18, 2018 00:55
@dpgeorge
Copy link
Member

Unfortunately it doesn't seem to work, because the ST HAL defines constants like TIM2, USART2, SDIO etc.

for af in named_pin.pin().alt_fn:
func = "%s%d" % (af.func, af.fn_num) if af.fn_num else af.func
pin_type = (af.pin_type or "NULL").split('(')[0]
STATIC_AF.add(" (pin_obj) == (pin_%s) && STATIC_AF_ ## fn ## _ ## type == STATIC_AF_%s_%s ? (%d) : \\" % (
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd suggest to change it to just STATIC_AF_ ## fn_type, and pass in fn and type as one entity, eg SDIO_D0.

print(" STATIC_AF_%s_%s," % (func, pin_type), file=af_defs_file)

print("};\n", file=af_defs_file)
print("#define STATIC_AF(pin_obj, fn, type) \\", file=af_defs_file)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would work if changed to STATIC_AF(pin_obj, fn_type)

@dpgeorge
Copy link
Member

I was trying to use the macro with sdcard.c, lines 153-158.

@andrewleech
Copy link
Contributor Author

Oh, are the fn tokens being expanded before they get joined to the unit for you?

I did wonder if it would be better to just pass in the entire enum value STATIC_AF_FMC_SDCLK as teh function argument then at least autocomplete / code navigation has a chance of working, rather than anonymous tokens that are being joined later

@dpgeorge
Copy link
Member

Oh, are the fn tokens being expanded before they get joined to the unit for you?

Yes. I think with FMC it wasn't, but other periphs are.

I did wonder if it would be better to just pass in the entire enum value STATIC_AF_FMC_SDCLK

Maybe that is a better idea. Less macro magic, less things to go wrong. At the expense of more typing. But it's not much more typing.

@andrewleech andrewleech force-pushed the stm32_static_alternate_pins branch 2 times, most recently from 0d3d068 to c26e2ec Compare July 18, 2018 04:05
@andrewleech
Copy link
Contributor Author

Ok it's set up to pass the enum as the arg now, looks to be working well on my end.

I've updated&rebased the sdram pr to suit as well.


#define mp_hal_pin_config_alt_static(pin_obj, mode, pull, fn, type) \
mp_hal_pin_config(pin_obj, mode, pull, STATIC_AF(pin_obj, fn, type)); \
MP_STATIC_ASSERT(STATIC_AF(pin_obj, fn, type) != -1)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like this is not updated to take just the single arg fn/type arg...?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

darn, I had fixed that.... I'm going to claim it as a rebase fail

@andrewleech andrewleech force-pushed the stm32_static_alternate_pins branch from c26e2ec to fb5965b Compare July 18, 2018 05:35
@dpgeorge
Copy link
Member

I was about to merge, and double checking it, but unfortunately it still has some problems!

The point is that the compiler doesn't know that pin objects have distinct addresses. So it can't optimise something like this:

&pin_A1_obj == &pin_A0_obj ? 1 :
&pin_A1_obj == &pin_A1_obj ? 2 :
-1

The first check may succeed if pin_A0_obj is aliased to pin_A1_obj. I'm not sure how to fix that, or if there is a way to work around it.

@andrewleech
Copy link
Contributor Author

Doesn't having the pin_A1_obj declared as const mean the compiler should know it's fixed?
Have you got some way of testing that the compiler isn't optimising it?

@andrewleech
Copy link
Contributor Author

ok, to test I've updated pin_static_af.h

#define mp_hal_pin_config_alt_static(pin_obj, mode, pull, fn_type) \
        mp_hal_pin_config(pin_obj, mode, pull, STATIC_AF(pin_obj, fn_type)); \
        MP_STATIC_ASSERT(STATIC_AF(pin_obj, fn_type) != -1);\
        MP_STATIC_ASSERT(__builtin_constant_p(STATIC_AF(pin_obj, fn_type)) == 1)

This still compiles, so I'm pretty sure __builtin_constant_p appears to be reporting that it is recognised as a constant.

@dpgeorge
Copy link
Member

Have you got some way of testing that the compiler isn't optimising it?

Two ways: 1) inspect the assembly output; 2) use _Static_assert instead of MP_STATIC_ASSERT to detect non-constant values.

I found this issue when converting sdcard.c to use the new macro, the SDMMC2 path. It only happens when the same AF is available on more than one pin.

@andrewleech
Copy link
Contributor Author

Yep thanks, I've confirmed the issue.

Not yet sure how to resolve this one, I've tried a few games with casting / const'ing in the auto-generated table to no avail.... not sure I fully understand the root cause yet, need more investigation.

@andrewleech andrewleech force-pushed the stm32_static_alternate_pins branch from fb5965b to 32373a3 Compare July 19, 2018 00:39
@andrewleech
Copy link
Contributor Author

I reckon I've got it sorted. Turns out the compiler is happy to coimpile-time calculate strcmp.
As such stringify'ing the pin definition and checking that works well.

I've left the (#defined out) version of the macro/function used to confirm that it is statically constant and working, looks good for the sdcard on the 769disc target too.

I've lost track of the number of trials it took to get this far... geez I hate macro magic. Why can't they just bring constexpr from c++ back into c!

The autogenerated file however is now a much simpler format, similar to your other initial suggestion.
This is an improvement even without the stringify compare test; comparing the pin pointer objects worked better like this in that some would compile time calculate, but at least the ones that are runtime calc are much smaller and arguably efficient enough.

The stringify's are more efficient again, but at the expense of being more strict about the format of the pin definition being passed in. I don't see this being a problem though?

@dpgeorge
Copy link
Member

Thanks a lot for working on this, it does look a lot better now. Really glad you found a way to fix it!

But still one minor thing: the STATIC_AF_* macros seem to be too smart for the MP_STATIC_ASSERT() to work, and if you give it a pin that doesn't have the alt function it will happily pass through -1 as the argument for the alt func, and at the same time MP_STATIC_ASSERT() will pass!

This could possibly be fixed by making MP_STATIC_ASSERT() better, but that's a bit out of scope of what we are trying to do here. (Maybe define this macro to use _Static_assert if it's provided by the compiler.)

As a workaround, I tried changing the -1 to 0xffffffffffffffffULL so that it warns about an overflowing constant literal if it gets to that path in the macro. That seems to work OK for me, with both MP_STATIC_ASSERT and the _Static_assert variants in pin_static_af.h. I'd suggest going this route, to be sure you get some kind of warning if the AF is wrong.

The stringify's are more efficient again, but at the expense of being more strict about the format of the pin definition being passed in. I don't see this being a problem though?

It should be ok. It does mean though that you must have the correct number of parenthesis, so this won't work:

mp_hal_pin_config_alt_static(pyb_pin_SD_CK, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_UP, STATIC_AF_SDMMC2_CK);

it instead needs to be (not extra parenthesis):

mp_hal_pin_config_alt_static((pyb_pin_SD_CK), MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_UP, STATIC_AF_SDMMC2_CK);

But I'd say that's acceptable. These pin definitions should anyway be specified in mpconfigboard.h where everything uses parenthesis. And it'll give an error if the parenthesis are wrong because it won't match any of the strings.

In summary: if you're happy changing -1 to 0xffffffffffffffffULL then it's good to go (and I can do this during merge if you like).

Works with pins declared normally in mpconfigboard.h, eg. (pin_XX)

Provides new mp_hal_pin_config_alt_static(pin_obj, mode, pull, fn, type) function
declared in pin_static_af.h to allow configuring pin alternate functions by name
@andrewleech andrewleech force-pushed the stm32_static_alternate_pins branch from 32373a3 to a48a18e Compare July 19, 2018 03:56
@andrewleech
Copy link
Contributor Author

Ah, I forgot to test that it still worked with MP_STATIC_ASSERT, thanks for following that up!
I'm quite happy with an overflow to force the fail, yet another win for warnings-as-errors. With this the MP_STATIC_ASSERT isn't needed at all, the warning is thrown from the function argument.

Yeah I do feel a little uncomfortable about the somewhat-hidden restriction on pin label/defining format this this macro magic enforces. Perhaps it would be possible to spin the macro's more to be slightly more flexible on brackets, but nothing really comes to mind.

Do you have any objection to two strcmp's &'d together, to cover these two (most likely?) use cases?
Have a look at this update. I've moved the "error" comment too so it shows up in the gcc error message when the AF is wrong pin, although it's still a little hidden in the overflow error message it's better than nothing.

ps. thanks so much for building a platform with enforced no-warnings, it's fantastic to see that in an open-source project of this size!

@dpgeorge
Copy link
Member

Do you have any objection to two strcmp's &'d together, to cover these two (most likely?) use cases?

That's ok.

I checked the latest version of this PR and verified that it all works as expected now. And I've now merged it in 4343c93 . sdcard.c was switched to use this new function/macro in 4201f36

Thanks for the effort on this!

thanks so much for building a platform with enforced no-warnings, it's fantastic to see that in an open-source project of this size!

You're welcome!

@dpgeorge dpgeorge closed this Jul 20, 2018
tannewt pushed a commit to tannewt/circuitpython that referenced this pull request Jan 21, 2021
Some ports need an extra operation to ensure that the main task is
awoken so that a queued background task will execute during an ongoing
light sleep.

This removes the need to enable supervisor ticks while I2SOut is operating.

Closes: micropython#3952
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants