-
Notifications
You must be signed in to change notification settings - Fork 1.4k
Nrf internal pullup support #5718
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
…nal pullups on certain boards - namely the nrf52833
microdev1
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the PR @scath999. Few suggestions but you are on the right track.
|
@microdev1 thanks for this quick review |
dhalbert
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My comments would have been very similar to @microdev1's. I suggest using internal_pullup, to make clear which pullup we're talking about.
As you note, this is a job, because to make the API consistent, we have to add the new argument in the common-hal impl in all the ports. It should also be added to bitbangio.I2C.
|
@dhalbert @microdev1 Thank you so much! If I can ask a couple of questions, to be answered when you guys have time:
I was afraid you'd just ignore this draft PR or get back to me in a few months - I'm really grateful for the input! Cheers! |
You can just think of it as a way of creating the name
All the definitions and uses of the routines below will need to add the extra argument. Also the inline documentation in shared-bindings will need to document the new argument. Someone will have to figure out how to turn on the internal pullups for each port, which will of course vary based on that chip family's hardware details. The CI builds will not lie, and will error out on the places where you missed :) |
I see - thank you! If I can ask a quick followup, what do underscores in variable names do in this context? I'm concerned that this will create and expose a variable with a space in the API. (e.g.
I understand, and will use your list - I have bandwidth for this right now, so I'm actively working on this.
Yikes! I take it I'm not putting other people's work in danger here - is there some preventative measure I can take to keep this safe? I'm terrified of breaking anything (as silly as that might sound).
That's a huge relief. I did see some when building the project with changes initially, and was grateful to see that extremely rigorous tests were being performed by github. Thanks again, @dhalbert - you've been extremely kind and patient. |
Underscores become underscores. We have plenty of MP_QSTRs with underscores in them, don't worry. There are a bunch of escapes for such characters: see
That's why we do code reviews, and testing (manual in this case). |
|
Not sure what to make of the call in
Does this mean I'll need to change calls for |
There's only one call to that routine anyway. You'll need to add the extra argument inside this call. But you don't need to add an extra argument to Now you have to understand how various compile options are passed along. You can study |
|
Super helpful. Seems like I'll need to explicitly set CIRCUITPY_BOARD to 0, since it appears to default to 1 in Am I misreading that? Also, is it wise to Example ( In the case of the 52833, I would then add something like I don't know enough to tell if this will cause other important |
Don't turn off
Yes, make it more specific:
Don't do this for all 52833 builds. I thought the reason for this was just that your particular board had no pullups for on-board I2C peripherals. Is that the case? Ideally the board would have on-board pullups. But we put pullups on our I2C breakouts, and most other mfrs do too. The microcontroller boards don't in general have pullups except when there are on-board sensors. Taking a step back here, is this the previous paragraph resetting one of your original assumptions? |
Yes, I see that now. Better to have a different define to work with and leave that high-level define alone.
Can do. That said, I found something interesting the Makes me wonder if someone has already solved this problem for that board in a simpler way, or if this is undesired functionality because it may be hidden from the developer. Not calling fault here, just confused by this choice and unsure if I should take the same approach - even use the same Further, there appear to be boards that set the pull of passed SDA and SCL pins For example, Am I understanding this correctly?
I see your point. It was my understanding that all 52833 boards have this functionality, which appears to be a wrong assumption. My next question is (of course) how can I indicate that my particular board has this capability, and have CPY expose that functionality? Seems like I need to just straight out
I totally get this, and I admit I'm concerned that the internal pullups won't be strong enough, but I'll need to show that adding them on is necessary before I ask the team to rework the board.
A bit confused by this - do you mean sensors that are integrated into the chipset, or 3rd-party sensors that have been wired into the system? Are you asking because this is important to this case, or important for CPY and this feature? This is an honest question; I'm not doubting you, I just want to understand the implications of what I'm trying to add for my project, and CPY in general. Thanks again :) |
|
Let's discuss the basic requirements of pullups in the issue you opened for this #5689, instead of here in the PR. I brought this up in general in a comment there. I'll paste your relevant comments from above there, in this new comment: #5689 (comment) |
|
I appreciate it @dhalbert, and thank you. I'll join you there on that count. That said, I'm still puzzled by how to proceed given the other issues outlined in my previous post. I want to build this feature out in a way you'll appreciate and that will be useful for the community, but I'm unsure what to make of those items. Thoughts? |
dhalbert
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Initial suggestions
| nrfjprog.exe --program $< --sectorerase -f $(MCU_VARIANT) | ||
| nrfjprog.exe --erasepage $(BOOT_SETTING_ADDR) -f $(MCU_VARIANT) | ||
| nrfjprog.exe --memwr $(BOOT_SETTING_ADDR) --val 0x00000001 -f $(MCU_VARIANT) | ||
| nrfjprog.exe --reset -f $(MCU_VARIANT) | ||
|
|
||
| sd: $(BUILD)/firmware.hex | ||
| nrfjprog --eraseall -f $(MCU_VARIANT) | ||
| nrfjprog --program $(SOFTDEV_HEX) -f $(MCU_VARIANT) | ||
| nrfjprog --program $< --sectorerase -f $(MCU_VARIANT) | ||
| nrfjprog --reset -f $(MCU_VARIANT) | ||
| nrfjprog.exe --eraseall -f $(MCU_VARIANT) | ||
| nrfjprog.exe --program $(SOFTDEV_HEX) -f $(MCU_VARIANT) | ||
| nrfjprog.exe --program $< --sectorerase -f $(MCU_VARIANT) | ||
| nrfjprog.exe --reset -f $(MCU_VARIANT) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this for Windows?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For Windows bash, yes. I thought I had added a comment indicating this.
I understand this can't stay, but needed it to build on my side.
Looking for input on this - no idea how to resolve.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We would recommend that you build on Linux if you can. Alternatively you could define an $(NRFJPROG) that is selected to be the right thing by some platform detection.
| // Set pulls on I2C pins up if setpullup is 1 - this supports boards with internal pullups | ||
| if (internal_pullup){ | ||
| nrf_gpio_pin_pull_t hal_pull = NRF_GPIO_PIN_PULLUP; | ||
|
|
||
| nrf_gpio_cfg_input(scl->number, hal_pull); | ||
| nrf_gpio_cfg_input(sda->number, hal_pull); | ||
| } | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Move this down to line 124, and add an else for lines 125-136; do the check for external pullups only if internal_pullup is false.
Take away the #if CIRCUITPY_REQUIRE_I2C_PULLUPS; it is superseded by the passed-in boolean.
You don't need the hal_pull variable: you can use the constant:
| // Set pulls on I2C pins up if setpullup is 1 - this supports boards with internal pullups | |
| if (internal_pullup){ | |
| nrf_gpio_pin_pull_t hal_pull = NRF_GPIO_PIN_PULLUP; | |
| nrf_gpio_cfg_input(scl->number, hal_pull); | |
| nrf_gpio_cfg_input(sda->number, hal_pull); | |
| } | |
| // Set pulls on I2C pins up if setpullup is 1 - this supports boards with internal pullups | |
| if (internal_pullup){ | |
| nrf_gpio_cfg_input(scl->number, NRF_GPIO_PIN_PULLUP); | |
| nrf_gpio_cfg_input(sda->number, NRF_GPIO_PIN_PULLUP); | |
| } | |
| // Set pulls up if internal_pullup is true | ||
| if (internal_pullup){ | ||
| nrf_gpio_pin_pull_t hal_pull = NRF_GPIO_PIN_PULLUP; | ||
|
|
||
| nrf_gpio_cfg_input(scl->number, hal_pull); | ||
| nrf_gpio_cfg_input(sda->number, hal_pull); | ||
| } | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will be redundant with the changes above; remove all this.
| // Set pulls up if internal_pullup is true | |
| if (internal_pullup){ | |
| nrf_gpio_pin_pull_t hal_pull = NRF_GPIO_PIN_PULLUP; | |
| nrf_gpio_cfg_input(scl->number, hal_pull); | |
| nrf_gpio_cfg_input(sda->number, hal_pull); | |
| } |
| // Set pull for SDA and SCL pins UP if internal_pullup = true | ||
| if (internal_pullup){ | ||
| gpio_set_pulls(sda->number, true, false) | ||
| gpio_set_pulls(scl->number, true, false) | ||
| } | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Make a similar change as suggested in the nrf port:
if (internal_pullup) {
// set the pullups
} else {
// test for pullups
}| #if CIRCUITPY_I2C_INTERNAL_PULLUPS | ||
| #define I2C_USE_INTERNAL_PULLUPS = true | ||
| #else | ||
| #define I2C_USE_INTERNAL_PULLUPS = false | ||
| #endif | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't do this; we will only enable internal pullups on the boards that you want to use them on, which will be your own company's board, not any of the existing boards.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, you're saying leave this out of git add?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The idea of this PR is to be able to specify internal pullups at run-time, instead of compile time. Conceivably you would want board.I2C() or similar to use internal pullups, but that would be for a specialized board (e.g. your company board), not for any current board. That would be a reason to use a compile-time setting, and the reason I suggested BOARD_I2C_USE_INTERNAL_PULLUPS
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I hear you. So you're saying move that #define to the board's .mk?
The only reason I've added a constant at all is to accommodate common_hal_board_create_i2c(void): It callscommon_hal_busio_i2c_construct which will include the internal_pullups param. I figured the least invasive change was to declare a constant rather than change yet another method signature and any calls to it.
Doing the latter would require me to get into shared-bindings/board/__init__.c and play with board_i2c() which would now need the internal_pullups param... that's starting to get messy.
Thoughts?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right, I'm just saying check for the constant CIRCUITPY_BOARD_I2C_USE_INTERNAL_PULLUPS in common_hal_board_create_i2c(void). But define that constant directly, and then I think you can eliminate CIRCUITPY_I2C_INTERNAL_PULLUPS and I2C_USE_INTERNAL_PULLUPS.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not to be thick-headed, but confused about what you mean by "define that constant directly".
To clarify, I assume you mean something like
mp_obj_t common_hal_board_create_i2c(void) {
// All callers have either already verified this or come so early that it can't be otherwise.
assert(i2c_singleton == NULL || common_hal_busio_i2c_deinited(i2c_singleton));
busio_i2c_obj_t *self = &i2c_obj;
self->base.type = &busio_i2c_type;
// ---> Check if board supports internal pullups
// and define the constant. e.g.
if (internal_pullups_are_supported)
const bool I2C_USE_INTERNAL_PULLUPS = true;
else
const bool I2C_USE_INTERNAL_PULLUPS = false;
common_hal_busio_i2c_construct(self, DEFAULT_I2C_BUS_SCL, DEFAULT_I2C_BUS_SDA, I2C_USE_INTERNAL_PULLUPS, 100000, 255);
i2c_singleton = (mp_obj_t)self;
return i2c_singleton;
}
My question is how can I know at runtime if the board has support for internal pullups?
This isn't an issue if it's just for my own board, but if it's for the community at large (which is what I'm assuming) it would need to be more robust - I'd need to know if the board supports this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My question is how can I know at runtime if the board has support for internal pullups?
With the addition of the internal_pullups argument to busio.I2C(), all boards now support internal pullups. You just have to ask for them by setting internal_pullups to be true in the constructor.
The question now for a particular board is whether board.I2C() asks for internal pullups by default. So I'm sayin to remove the older compile time constants, and add a CIRCUITPY_BOARD_I2C_USE_INTERNAL_PULLUPS, which defaults to 0.
Then in the code above, you would just do
mp_obj_t common_hal_board_create_i2c(void) {
...
common_hal_busio_i2c_construct(self, DEFAULT_I2C_BUS_SCL, DEFAULT_I2C_BUS_SDA, CIRCUITPY_BOARD_I2C_USE_INTERNAL_PULLUPS, 100000, 255);
...
}There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Did you post and then delete (retract) a comment there? To answer that, nearly all chips have always had the capability of supporting internal pullups, we just didn't expose that. Now we are. It's a choice of the user about whether they are going to connect some I2C devices without pullups. That could happen on any board.
And, there might be some boards, with board-mounted I2C devices, without external pullups. In that case, we might want board.I2C() to use internal pullups by default. It might actually be better not to do that, since it hides whether internal pullups are used or not. On code written for your board, you might just go ahead and set internal_pullups=True explicitly when creating a busio.I2C() for use with the board-mounted I2C cervices. Then we don't need any compile-time constants at all.
There may be some chips that don't have pull-ups; I don't know. For those chips, the common-hal constructor would raise NotImplementedError if internal_pullups=True, to indicate it was not possible.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok. I'm confused about some of this, mainly because I'm trying to relate now to set your suggested CIRCUITPY_BOARD_I2C_USE_INTERNAL_PULLUPS at runtime, but perhaps it's better to put a pin in this?
In the interim, I can simply pass true to that part of the method and move on to the bigger issue: i2c.scan() is not returning any devices, even after I set the pulls up and read a proper voltage (3.3V) on them at runtime. At this point, I need to figure out what's going wrong there. After all, if going through all of this trouble still yields no usable result, what's the point?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok. I'm confused about some of this, mainly because I'm trying to relate now to set your suggested
CIRCUITPY_BOARD_I2C_USE_INTERNAL_PULLUPSat runtime, but perhaps it's better to put a pin in this?
I'm suggesting that the compile-time constant need not exist at all. The user code will decide whether or not to use internal pullups.
In the interim, I can simply pass true to that part of the method and move on to the bigger issue: i2c.scan() is not returning any devices, even after I set the pulls up and read a proper voltage (3.3V) on them at runtime. At this point, I need to figure out what's going wrong there.
I'll build this and try it out.
Are you trying this with a PCA10100 and an external sensor without pullups, or are you trying it on your own board?
|
|
||
| # Support for Internal Pullups for this MCU | ||
| CIRCUITPY_I2C_INTERNAL_PULLUPS = 1 | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The default for the pca10100 should not be changed: you are using it as a test board, but that's for your own use. It is your company's board that will turn this on; no existing boards will do this.
|
|
||
| // If the board supports internal pullups, set the SDA and SCL channel pulls up | ||
| if (internal_pullup){ | ||
| i2c_check_pin_config(sda, 1); | ||
| i2c_check_pin_config(scl, 1); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Make a similar change as suggested in the nrf port:
if (internal_pullup) {
// set the pullups
} else {
// test for pullups
}| // This appears to be a board-specific way of supporting internal pullups without | ||
| // going through all of the changes I've made - @dhalbert can you comment? | ||
| // Not going to change anything here before discussion - will just throw internal_pullup away |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Make a similar change as suggested in the nrf port:
if (internal_pullup) {
// set the pullups
} else {
// test for pullups
}There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, so do away with the existing code beneath this comment?
// This appears to be a board-specific way of supporting internal pullups without
// going through all of the changes I've made - @dhalbert can you comment?
// Not going to change anything here before discussion - will just throw internal_pullup away
#if CIRCUITPY_I2C_ALLOW_INTERNAL_PULL_UP
gpio_pullup_en(sda->number);
gpio_pullup_en(scl->number);
#endif
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is in ports/espressif/common-hal/busio/I2C.c around line 64.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
not do away with it, but move it into the then clause of the if statement above
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, so remove the #if and wrap the contents into the if-else. Can do.
| uint8_t scl_alt = 0; // Are these necessary, or can they be declared in the for? | ||
| uint8_t sda_alt = 0; // e.g. for (uint8_t scl_alt = 0; scl_alt < 6; scl_alt++) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch, I believe yes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thumbsup.
| // If board supports internal pullups, set SDA and SCL channels up | ||
| if (internal_pullup){ | ||
| gpio_set_pin_pull_mode(sda->number, GPIO_PULL_UP); | ||
| gpio_set_pin_pull_mode(scl->number, GPIO_PULL_UP); | ||
| } | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Make a similar change as suggested in the nrf port:
if (internal_pullup) {
// set the pullups
} else {
// test for pullups
}
dhalbert
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
HI, replied to your queries, and deleted a few erroneous comments of mine.
| // This appears to be a board-specific way of supporting internal pullups without | ||
| // going through all of the changes I've made - @dhalbert can you comment? | ||
| // Not going to change anything here before discussion - will just throw internal_pullup away |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
not do away with it, but move it into the then clause of the if statement above
| nrfjprog.exe --program $< --sectorerase -f $(MCU_VARIANT) | ||
| nrfjprog.exe --erasepage $(BOOT_SETTING_ADDR) -f $(MCU_VARIANT) | ||
| nrfjprog.exe --memwr $(BOOT_SETTING_ADDR) --val 0x00000001 -f $(MCU_VARIANT) | ||
| nrfjprog.exe --reset -f $(MCU_VARIANT) | ||
|
|
||
| sd: $(BUILD)/firmware.hex | ||
| nrfjprog --eraseall -f $(MCU_VARIANT) | ||
| nrfjprog --program $(SOFTDEV_HEX) -f $(MCU_VARIANT) | ||
| nrfjprog --program $< --sectorerase -f $(MCU_VARIANT) | ||
| nrfjprog --reset -f $(MCU_VARIANT) | ||
| nrfjprog.exe --eraseall -f $(MCU_VARIANT) | ||
| nrfjprog.exe --program $(SOFTDEV_HEX) -f $(MCU_VARIANT) | ||
| nrfjprog.exe --program $< --sectorerase -f $(MCU_VARIANT) | ||
| nrfjprog.exe --reset -f $(MCU_VARIANT) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We would recommend that you build on Linux if you can. Alternatively you could define an $(NRFJPROG) that is selected to be the right thing by some platform detection.
| #if CIRCUITPY_I2C_INTERNAL_PULLUPS | ||
| #define I2C_USE_INTERNAL_PULLUPS = true | ||
| #else | ||
| #define I2C_USE_INTERNAL_PULLUPS = false | ||
| #endif | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The idea of this PR is to be able to specify internal pullups at run-time, instead of compile time. Conceivably you would want board.I2C() or similar to use internal pullups, but that would be for a specialized board (e.g. your company board), not for any current board. That would be a reason to use a compile-time setting, and the reason I suggested BOARD_I2C_USE_INTERNAL_PULLUPS
|
I am going to close this for now because the original motivation I believe has become moot. We can revisit this at some point in the future if we see more demand. I am reluctant to add it now because it increases code size on even the small builds. |
Addresses #5689.
Not a full PR - only outlining suggested edits to limited number of files in support of internal pullups on certain NRF boards.
@dhalbert notified me that all instances of
common_hal_busio_i2c_constructwould need an extra parameter added. Accepting this as true, I didn't feel comfortable making that many changes before receiving guidance from the project owners.I wasn't able to figure out the proper parameter to pass - @tannewt suggested
MP_QSTR_internal_pullup, but this isn't a recognized type and I'm too new to this project to start creating types (or even know where to do that).Hoping for input.