Skip to content

i2c_sam0 driver does not execute a STOP condition #21233

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

Closed
sslupsky opened this issue Dec 6, 2019 · 3 comments
Closed

i2c_sam0 driver does not execute a STOP condition #21233

sslupsky opened this issue Dec 6, 2019 · 3 comments
Assignees
Labels
area: I2C bug The issue is a bug, or the PR is fixing a bug platform: Microchip SAM Microchip SAM Platform (formerly Atmel SAM) priority: low Low impact/importance bug

Comments

@sslupsky
Copy link
Contributor

sslupsky commented Dec 6, 2019

Describe the bug
The i2c_sam0 driver does not execute a STOP condition. As a result, at the end of each transaction, the SCL line is forced low.

To Reproduce
Steps to reproduce the behavior:

  1. use blinky example
  2. add an i2c peripheral
  3. make
  4. observe the SCL line
  5. See error

Expected behavior
SCL should be released (go high) when a bus transaction is complete.

Impact
When SCL is held low, the pull up resistors on the bus consume power on the order of 500uA or more (depending on the value of the pull up resistor) indefinitely. This bug rules out any low power applications that require the i2c driver.

Additional context
The i2c CMD bits can only be set when either the Slave on Bus interrupt flag (INTFLAG.SB) or Master on Bus interrupt flag (INTFLAG.MB) is '1'. See 28.10.2. So, the stop command must be issued before the MB and SB interrupt flag bits are cleared. See 28.10.6. Otherwise, the clock (SCL) will be held low.

I created a POC to verify the expected behaviour. Writing the data register or reading the data register when SBEN is enabled clears SB and MB. Thus, we do not need to clear MB or SB in the ISR. Thus, the following line was removed from the i2c_sam0_isr() in my POC:

	i2c->INTFLAG.reg = status;

The end of RX is not handled properly so the following code segment was reorganized in the i2c_sam0_isr():

	if (status & SERCOM_I2CM_INTFLAG_SB) {
		if (!data->msg.size) {
			i2c->INTENCLR.reg = SERCOM_I2CM_INTENCLR_MASK;
			k_sem_give(&data->sem);
			return;
		}

		if (data->msg.size == 1) {
			/*
			 * If this is the last byte, then prepare for an auto
			 * NACK before doing the actual read.  This does not
			 * require write synchronization.
			 */
			i2c->CTRLB.bit.ACKACT = 1;
		}

		*data->msg.buffer = i2c->DATA.reg;
		data->msg.buffer++;
		data->msg.size--;

		return;
	}

The error flag is cleared in i2c_sam0_terinate_on_error():

	i2c->INTFLAG.reg = SERCOM_I2CM_INTFLAG_ERROR;

This POC shows that the STOP condition is properly executed at the end of a bus transaction.

@sslupsky sslupsky added the bug The issue is a bug, or the PR is fixing a bug label Dec 6, 2019
@galak galak added area: I2C platform: Microchip SAM Microchip SAM Platform (formerly Atmel SAM) labels Dec 10, 2019
@galak galak added the priority: medium Medium impact/importance bug label Dec 10, 2019
@jhedberg jhedberg added priority: low Low impact/importance bug and removed priority: medium Medium impact/importance bug labels Feb 18, 2020
@jhedberg
Copy link
Member

@mnkp is there anything you could do to help with this one?

@sslupsky
Copy link
Contributor Author

@jhedberg I have a PR pending to address this and several other issues with the sam0 i2c driver. The reason this has taken quite some time to resolve is the inter relationship with the low power modes of the sam0 and the rtc_timer driver. I've addressed both and will submit PR's soon.

BTW, this is a pretty serious issue. I2C is pretty much unusable on sam0.

sslupsky added a commit to sslupsky/zephyr that referenced this issue Jul 10, 2020
Optimizations:
When using system power management, the bus transactions
can be interrupted by low power modes which causes excessive
power consumption and can cause the transactions to terminate
before completed. Further, other interrupts can cause bus transaction
anomalies.

When using the RESTART flag, the MB and SB bits must be cleared.

This commit prevents interruption of the bus during low power modes and
correctly clears the MB or SB flags when a bus transaction is restarted.
Also fixes an initialization problem with the INACTOUT timer and ensures
the LOWTOUT is properly configured when using i2c_configure().

The GCLK_SERCOM_SLOW clock is used to time the i2c
time-outs and must be configured to use a 32KHz oscillator.
See 28.6.3.1

This commit configures GCLK4 to 32768 Hz

Fixes zephyrproject-rtos#21711, zephyrproject-rtos#21549, zephyrproject-rtos#21233, zephyrproject-rtos#21232, zephyrproject-rtos#21114, zephyrproject-rtos#21092

A problem can arise when back to back transactions occur before
the STOP transaction is complete.

This commit also introduces a busy wait for the STOP to complete
with an timeout in the event there is a bus failure.

Signed-off-by: Steven Slupsky <[email protected]>
@sslupsky
Copy link
Contributor Author

@MaureenHelm PR 24050 has been rebased.

@sslupsky sslupsky closed this as completed Sep 8, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area: I2C bug The issue is a bug, or the PR is fixing a bug platform: Microchip SAM Microchip SAM Platform (formerly Atmel SAM) priority: low Low impact/importance bug
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants