-
Notifications
You must be signed in to change notification settings - Fork 2k
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
drivers/periph/i2c: add periph_i2c_reconfigure feature & implementation for sam0 #13421
Conversation
On first sight I see a benefit in |
Not quite.
There is no grantee all I would have preferred a |
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.
To me the current proposal goes against the general concept of simple, minimal, and lean low-level APIs.
I would like to get other opinions (and suggestions) on this: e.g. @haukepetersen, @MrKevinWeiss and @MichelRottleuthner please have a look.
My first thoughts are that we should really consider things when it comes to API changes (though this appears not to be a change but just an addition which isn't as critical). That being said I would like to first understand what everyone else is doing (zephyr, mbed, each vendors HAL) if we want to talk about another set of changes to the i2c api. With regards to the reinit maybe it would be better to make the init capable of being called multiple times? If the mutex is the problem check to see if it is already initialized. As for the pins, I really think we should just specify the struct and have it a standard way of describing it rather than having to add a workaround function to convert to a standard. |
Ok, I will then
|
23bb807
to
469bae4
Compare
I changed the implementation accordingly & rebased to resolve a merge conflict. |
So as far as I see it looks good. I still want to do some testing (maybe I will get to it tomorrow). I think @smlng comments should be addressed and I think he is on vacation so if we don't hear from him and testing/review is complete I think we can dismiss. In terms of the API comparison, we would only talk about the deinit call
From what I can tell the vendors seem to support an i2c_disable API call with a device handle and sometimes return code (though I think we don't need one and can just assert for invalid conditions). |
cpu/sam0_common/periph/i2c.c
Outdated
@@ -79,6 +79,20 @@ void i2c_init(i2c_t dev) | |||
int32_t tmp_baud; | |||
|
|||
assert(dev < I2C_NUMOF); | |||
|
|||
/* i2c_deinit() has been called - restore config */ | |||
if (mutex_trylock(&locks[dev]) == 0) { |
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 it safe to call mutex_trylock()
on uninitialized mutexes?
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.
As long as MUTEX_INIT
remains defined to {{ NULL }}
and locks
is a static
buffer…
I agree it's not nice to rely on an implementation detail here, should probably make that more explicit (and drop the call to mutex_init()
in i2c_init()
.
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.
Does it make sense to wrap all the reinit functionality with #ifdef MODULE_PERIPH_I2C_RECONFIGURE
so it doesn't add code size to the init function and doesn't compile the other functions slowing down the CI (even though it doesn't link)?
drivers/include/periph/i2c.h
Outdated
* @brief Change the pins of the given I2C bus back to plain GPIO functionality | ||
* | ||
* The pin mux of the SDA and SCL pins of the bus will be changed back to | ||
* GPIO mode and the I2C bus is powered off. |
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.
Can you clarify what GPIO mode (if it saves the previous state, has some default state, input, with or without pullups, etc.)?
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.
Depends no the implementation, gpio_init()
should be called if you want a defined state - I'll add a line.
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.
Depends no the implementation, gpio_init()
should be called if you want a defined state - I'll add a line.
cpu/sam0_common/periph/gpio.c
Outdated
@@ -92,6 +92,14 @@ void gpio_init_mux(gpio_t pin, gpio_mux_t mux) | |||
port->PMUX[pin_pos >> 1].reg |= (mux << (4 * (pin_pos & 0x1))); | |||
} | |||
|
|||
void gpio_disable_mux(gpio_t pin) |
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.
Should this be wrapped with #ifdef MODULE_PERIPH_I2C_RECONFIGURE
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.
No, this can be useful on it's own (and it's internal to sam0)
It will also be needed for spi_deinit()
and uart_deinit()
.
I just pulled you PR for test purposes into my PR #13412 and it is working well :) Thank you! For a clean PR, I need the standardized I2C struct @MrKevinWeiss was talking about. Currently, I am assuming that |
Thanks for working on this! I want to add to the discussion that this functionality will also be helpful (required?) for implementing generic functionality to recover slaves from blocking or failed states. The below code can be used as an example to trigger such a situation. If the node is reset while looping over #include <stdio.h>
#include "xtimer.h"
#include "phydat.h"
#include "saul_reg.h"
int main(void)
{
phydat_t res;
xtimer_sleep(5); /* wait a bit to see the output */
saul_reg_t *dev = saul_reg;
int cnt = 0;
while (dev != NULL) {
cnt++;
printf("%s\n", saul_class_to_str(dev->driver->type));
dev = dev->next;
}
printf("found %d SAUL devices\n", cnt);
dev = saul_reg_find_type(SAUL_SENSE_ACCEL);
if (dev == NULL) {
printf("no such device found!\n");
return 1;
}
while (1) {
saul_reg_read(dev, &res);
}
return 0;
} |
Well the other platforms will need to be touched anyway when they implement |
Are you thinking about some kind of generic i2c_conf_t struct that is inherited into an platform-specific i2c_conf_t struct? |
1c95731
to
4ea4094
Compare
@MrKevinWeiss can you add advise on readjusting the layers here? |
It seems like there will be another abstraction layer is what is selected to move forward. The unification of the implementation specific structs should be done on a seperate PR. So like I said I won't block. I am also thinking @smlng can dismiss his review? |
Btw.: SPI already has That would spare us additional complexity in |
+1 for this approach, what do you think @MrKevinWeiss? |
Make sense +1 |
@MrKevinWeiss do you have any i2c driver to test this? I'm sorry to say I don't anything to test ATM :/. |
If you happen to have a
it should match the MAC address printed on the bottom of the board. |
Maybe @aabadie has a samr21-xpro and can test? |
I tested on the I was able to acquire, read registers, release, reinit pins, acquire, read registers. It works as expected! |
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.
@MrKevinWeiss tested. @smlng requested changes but deffering opion to @MrKevinWeiss and @MichelRottleuthner. The later was fine with the changes #13421 (comment). @MrKevinWeiss are you fine with the changes as well?
I think we can dismiss @smlng after 1 month.
On my side this is an ACK!
4e5e405
to
0a6c640
Compare
Just the CI need to pass now I guess! |
It is often desireable to re-configure the pins of a bus back to GPIO mode, either to save power when an external peripheral is turned off and current would leak, or because a device may need a non-standard in-band signal to be generated on the bus lines. To serve those use cases, this patch introduces four new functions to the I2C API: - `i2c_init_pins()` equivalent to spi_init_pins(), restores I2C pin configuration - `i2c_deinit_pins()` to switch the configuration of the I2C pins back to GPIO mode and block access to the bus. - `i2c_pin_sda()` to get the data pin for a given bus - `i2c_pin_scl()` to get the clock pin for a given bus Since it's unreasonable to expect having implementations for all platforms already, those functions are only availiable when the periph_i2c_reconfigure feature is availiable. Applications should use FEATURES_REQUIRED += periph_i2c_reconfigure or FEATURES_OPTIONAL if they want to make use of those functions.
This adds sam0 implementations for - i2c_init_pins() - i2c_deinit_pins() - i2c_pin_sda() - i2c_pin_scl()
Add a test to re-configure the I2C pins to GPIO functionality and use them as output. A small delay is added to allow for observing the change in power draw.
0a6c640
to
896f9db
Compare
go! |
Contribution description
It is often desirable to re-configure the pins of a bus back to GPIO mode,
either to save power when an external peripheral is turned off and current
would leak, or because a device may need a non-standard in-band signal to
be generated on the bus lines.
To serve those use cases, this patch introduces four new functions to the
I2C API:
i2c_deinit()
to switch the configuration of the I2C pins back to GPIO mode and block access to the bus.i2c_reinit()
to return the bus pins back to I2C mode and release the bus again.i2c_pin_sda()
to get the data pin for a given busi2c_pin_scl()
to get the clock pin for a given busSince it's unreasonable to expect having implementations for all platforms
already, those functions are only available when the periph_i2c_reconfigure
feature is available.
Applications should use
FEATURES_REQUIRED += periph_i2c_reconfigure
orFEATURES_OPTIONAL += periph_i2c_reconfigure
if they want to make use of those functions.Testing procedure
Run the
tests/periph_i2c
test application.On a supported platform, the
i2c_gpio
command should be available.Verify that I2C communication is possible before and after issuing the
i2c_gpio
command.You can observe a change of power draw when the pins are being reconfigured.
Issues/PRs references
alternative to #13413
allows for a generic solution of #13412
If this approach is acceptable, I will provide implementations for SPI and UART as well.