-
Notifications
You must be signed in to change notification settings - Fork 2.1k
cpu/sam0: re-work i2c driver #7588
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
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.
Codewise looks sensitive except some quirks I've commented. Please note that in public API methods you should test if the value of "bus" is sensitive (< NUMOF).
I unassign myself as I can't test or qualify this PR regarding functionality since I've very few knowledge of samd platforms and no board to test it.
cpu/sam0_common/periph/i2c.c
Outdated
@@ -35,7 +37,7 @@ | |||
#include "debug.h" | |||
|
|||
/* guard file in case no I2C device is defined */ | |||
#if I2C_NUMOF | |||
#ifdef I2C_NUMOF |
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.
if it's defined as 0 line 62 will fail to compile, but it's still a valid value, meaning disabled.
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 issue can also be applied on sam0 UART. (maybe somewhere else too ?)
What should I do ?
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.
You are right, there's currently a mixture of #if
and #ifdef
s. It should be addressed by the build system in the future anway. So by now, whatever it's Ok
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.
Yes, I was thinking of opening an issue for this point to have community's opinion as some driver use #if xxx_NUMOF and others #ifdef xxx_NUMOF. I'll do it later today.
|
||
/* Reset I2C */ | ||
I2CSercom->CTRLA.reg = SERCOM_I2CS_CTRLA_SWRST; | ||
while (I2CSercom->SYNCBUSY.reg & SERCOM_I2CM_SYNCBUSY_MASK) {} | ||
dev(bus)->CTRLA.reg = SERCOM_I2CM_CTRLA_SWRST; |
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 was i2cs
and now i2cm
. 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.
Yes.
I2C Sercom can be either master or slave. I2CS bit resets all registers related to slave mode which is not our case (as our aim is to reset our master I2C here). This must be an unspotted mistake from previous driver.
return i2c_config[bus].dev; | ||
} | ||
|
||
int i2c_init_master(i2c_t bus, i2c_speed_t speed) |
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.
Bus should be tested against NUMOF.
|
||
/* Enable Smart Mode (ACK is sent when DATA.DATA is read) */ | ||
I2CSercom->CTRLB.reg = SERCOM_I2CM_CTRLB_SMEN; | ||
dev(bus)->CTRLB.reg = SERCOM_I2CM_CTRLB_SMEN; | ||
|
||
/* Find and set baudrate. Read speed configuration. Set transfer | ||
* speed: SERCOM_I2CM_CTRLA_SPEED(0): Standard-mode (Sm) up to 100 | ||
* kHz and Fast-mode (Fm) up to 400 kHz */ | ||
switch (speed) { |
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.
Idea: This could be refactored if the I2C speed enum contains the values which create tmp_baud
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.
Hum, I understand what you mean. But the calculation requires to know both CORE_CLOCK and the I2C desired speed. I don't think the user must rewrite those values if he changes CORE_CLOCK.
Maybe others maintainers have some ideas ?
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 meant the following: you can redefine the i2c_speed_t
in periph_cpu_common.h
as
typedef enum {
I2C_SPEED_NORMAL = 100000,
I2C_SPEED_FAST = 400000,
...
} i2c_speed_t;
Then you can skip the switch
:
tmp_baud = (int32_t)(((CLOCK_CORECLOCK + (2 * (speed)) - 1) / (2 * (speed))) - 5);
if (tmp_baud < 255 && tmp_baud > 0) {
dev(bus)->CTRLA.reg |= SERCOM_I2CM_CTRLA_SPEED(0);
dev(bus)->BAUD.reg = SERCOM_I2CM_BAUD_BAUD(tmp_baud);
}
But now I relised that the high
speed has different values (2 instead of 0 and HSBAD instead of BAUD), so I'm not sure it makes sense.
cpu/sam0_common/periph/i2c.c
Outdated
[I2C_3] = MUTEX_INIT | ||
#endif | ||
}; | ||
static mutex_t locks[I2C_NUMOF]; |
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.
Locks should be initialized in the init function
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.
What about something like
static mutex_t locks[I2C_NUMOF] = {[0 ... I2C_NUMOF-1]= MUTEX_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.
It's a good options, but I think this syntax is only GCC compliant
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.
Indeed, g++ cannot handle this. It is a no-go ?
cpu/sam0_common/periph/i2c.c
Outdated
{ | ||
if (sercom == NULL) { | ||
if (dev(bus) == NULL) { |
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.
bus should be tested against NUMOF (also in many other functions)
@lebrush Thanks for your review. I'll address all your comments asap. |
@lebrush I added more tests against |
53b2496
to
15cfcc1
Compare
#7241 solved the NUMOF issue. |
Signed-off-by: dylad <dylan.laduranty@mesotic.com>
Signed-off-by: dylad <dylan.laduranty@mesotic.com>
Signed-off-by: dylad <dylan.laduranty@mesotic.com>
I rebased this PR to lastest master. |
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 like this PR. I don't think it will go into the next release but it's a good work already.
|
||
#define I2C_0_DEV SERCOM3->I2CM | ||
#define I2C_IRQ_PRIO 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.
This define is unsused with sam0 cpus (only used with cc2538 and stm32). Maybe just remove ?
.scl_pin = GPIO_PIN(PA, 23), | ||
.mux = GPIO_MUX_C, | ||
.gclk_src = GCLK_CLKCTRL_GEN_GCLK0, | ||
.runstdby = 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.
What about a flags
field containing a list of enums, for example: (ENUM1 | ENUM2). Then you could use bitwise comparison in the driver? This will allow future potential extensions of the driver implementation (I don't see any right now though)
Thanks for the review @aabadie |
I'm closing this in favor of the I2C refactoring. |
This PR introduces a common i2c_config struct in
periph_conf.h
for all sam0 based boards. Additionnal I2C SERCOM can be add more easily.SAML21 can know use SERCOM5 if desired.
I'm wondering if I can remove the init of GCLK_SLOW because it is only for some SMBus timeout (no used yet by RIOT). Should I remove it ? This should not impact the current driver state but I want the community's opinion first :)
I also tried to keep the 80 characters limit per lines.