-
Notifications
You must be signed in to change notification settings - Fork 39
STM32F103 I2C: When reading exactly two bytes the first byte is not acknowledged by the I2C master. #127
Comments
cc @Sh4rK, that's the bug you're seeing. We desperately need |
The reference manual between F1 and F4 is identical EXCEPT in drumroll 2B I2C Master Reception. |
I mean srsly? Really? Do we really need to double check every little stupid thing for them? |
+1 for HWUT -1 Disabling I2C That would be sad as we are so close to finally supporting it. Here the Uart Trace from the I2C. I had to use
|
Ok, I was starting to think I'm doing something really stupid. |
@Sh4rK I would strongly recommend that you use any kind of logic analyser. I've been using an FX2 based board even in my rail-office quite successfully. They are cheap and fast enough for I2C, UART, CAN and SPI. @salkinium:
If you have a recorded working sequence from an I'm just preparing a board with some sensors (BMP180, BME280, ...), busses (I2C, SPI, UART, CAN) and a dedicated FX2 logic analyser for such tests. |
I can reproduce this problem locally using the NUCLEO-F103 and the TMP102 chip.
|
This behavior is addressed in the F10xxB Errata sheet (Section 2.13.2 on page 22). |
Already checked the errata sheet and I'm not convinced that this describes the behaviour we observe. Actually, the data on the bus is not correct; it is not corrupted while reading it into the shift register.
Probably ST needs HWUT to test their séquence and this is connected to the problem we observe. |
@strongly-typed: None of the workarounds suggested in the errata sheet made any difference. But: I have 2B reads working, but I cannot confirm with a logic analyzer. - if (reading.length <= 2)
+ if (reading.length < 2) I'll try to test this on the STM32F4 series. |
Are you sure? Is the read of the second byte different from Your fix kills my bus. The stop condition is not generated after the 2B read. Here the annotated cycle of the bmp180 sample. The bus is then broken. Ping
Read calibration
Start conversion
Read temperature
After that the bus is broken. Here the UART log
|
I rewrote my example to use the BMP085 and my "fix" kills my bus too. |
I'm just looking into AN2824 Figure 2:
|
Even with that application note, I just can't make it work. Furthermore I can't debug my Nucleo-F103 due to ST-Link issues (yay). |
At least that hack works on STM32F103 with 2-byte reads. diff --git a/src/xpcc/architecture/platform/driver/i2c/stm32/i2c_master.cpp.in b/src/xpcc/architecture/platform/driver/i2c/stm32/i2c_master.cpp.in
index c4018fc..61dff3d 100644
--- a/src/xpcc/architecture/platform/driver/i2c/stm32/i2c_master.cpp.in
+++ b/src/xpcc/architecture/platform/driver/i2c/stm32/i2c_master.cpp.in
@@ -297,21 +295,9 @@ I2C{{ id }}_EV_IRQHandler(void)
reading = transaction->reading();
nextOperation = static_cast<xpcc::I2c::Operation>(reading.next);
- if (reading.length <= 2)
- {
- DEBUG_STREAM("NACK");
- I2C{{ id }}->CR1 &= ~I2C_CR1_ACK;
- }
- else
- {
- DEBUG_STREAM("ACK");
- I2C{{ id }}->CR1 |= I2C_CR1_ACK;
- }
- if (reading.length == 2)
- {
- DEBUG_STREAM("POS");
- I2C{{ id }}->CR1 |= I2C_CR1_POS;
- }
+ DEBUG_STREAM("ACK");
+ I2C{{ id }}->CR1 |= I2C_CR1_ACK;
+
DEBUG_STREAM("read op: reading=" << reading.length);
break;
@@ -341,13 +327,25 @@ I2C{{ id }}_EV_IRQHandler(void)
{
starting.address = 0;
// EV6: ADDR=1, cleared by reading SR1 register followed by reading SR2.
+
+ if (reading.length == 1)
+ {
+ DEBUG_STREAM("NACK");
+ I2C{{ id }}->CR1 &= ~I2C_CR1_ACK;
+ (void) I2C{{ id }}->SR1; // Clear ADDR
+
+ } else if (reading.length == 2)
+ {
+ DEBUG_STREAM("POS");
+ I2C{{ id }}->CR1 |= I2C_CR1_POS; // Set POS flag (NACK position next)
+ }
if (writing.length > 0 || reading.length > 3)
{
I2C{{ id }}->CR2 |= I2C_CR2_ITBUFEN;
}
if (!reading.length && !writing.length)
@@ -376,6 +372,11 @@ I2C{{ id }}_EV_IRQHandler(void)
*reading.buffer++ = dr & 0xff;
reading.length = 0;
checkNextOperation = CHECK_NEXT_OPERATION_YES_NO_STOP_BIT;
+ }
+ else if (reading.length == 2)
+ {
+ DEBUG_STREAM("NACK");
+ I2C{{ id }}->CR1 &= ~I2C_CR1_ACK;
}
}
@@ -387,11 +388,11 @@ I2C{{ id }}_EV_IRQHandler(void)
// EV8: TxE=1, shift register not empty, data register empty, cleared by writing DR
if (writing.length > 0)
{
I2C{{ id }}->DR = *writing.buffer++; // write data
--writing.length;
checkNextOperation = CHECK_NEXT_OPERATION_NO_WAIT_FOR_BTF;
}
@@ -399,7 +400,7 @@ I2C{{ id }}_EV_IRQHandler(void)
if (writing.length == 0)
{
// disable TxE, and wait for EV8_2
I2C{{ id }}->CR2 &= ~I2C_CR2_ITBUFEN;
}
}
@@ -443,11 +444,6 @@ I2C{{ id }}_EV_IRQHandler(void)
uint16_t dr = I2C{{ id }}->DR;
*reading.buffer++ = dr & 0xff;
- DEBUG_STREAM("waiting for stop");
- uint_fast32_t deadlockPreventer = 100000;
- while (I2C{{ id }}->CR1 & I2C_CR1_STOP && deadlockPreventer-- > 0)
- ;
-
DEBUG_STREAM("reading data2");
dr = I2C{{ id }}->DR;
*reading.buffer++ = dr & 0xff; Hope I did not delete too much from the diff because my diff included the debug output truncating. How can I make the diff so colourful as yours? |
Use I'm trying to get this to work, let's see. |
That can't be right, that doesn't clear ADDR, it should be SR2. This will be a NOP. |
You are right. But I did not test 1 byte reads yet ;-) |
But consider
from AN2824 page 5, 8, 9 and 10. |
Yes, sure, but SR1 is always read, it's the first instruction in the interrupt. So you only need to read SR2 at that time (also, there is no difference in my tests). |
So these minimal changes still work for me and don't break 1B transfers: diff --git a/src/xpcc/architecture/platform/driver/i2c/stm32/i2c_master.cpp.in b/src/xpcc/architecture/platform/driver/i2c/stm32/i2c_master.cpp.in
index c4018fc..c714cf2 100644
--- a/src/xpcc/architecture/platform/driver/i2c/stm32/i2c_master.cpp.in
+++ b/src/xpcc/architecture/platform/driver/i2c/stm32/i2c_master.cpp.in
@@ -297,7 +297,7 @@ I2C{{ id }}_EV_IRQHandler(void)
reading = transaction->reading();
nextOperation = static_cast<xpcc::I2c::Operation>(reading.next);
- if (reading.length <= 2)
+ if (reading.length < 2)
{
DEBUG_STREAM("NACK");
I2C{{ id }}->CR1 &= ~I2C_CR1_ACK;
@@ -377,6 +375,11 @@ I2C{{ id }}_EV_IRQHandler(void)
reading.length = 0;
checkNextOperation = CHECK_NEXT_OPERATION_YES_NO_STOP_BIT;
}
+ else if (reading.length == 2)
+ {
+ DEBUG_STREAM("NACK");
+ I2C{{ id }}->CR1 &= ~I2C_CR1_ACK;
+ }
} |
I can confirm correct reads with correct sequence of |
No side-effects for STM32F407 discovered (yet). But a more elaborate test sequence must be put in place. I could to that parallel to my porting efforts of STM32L4. |
It works for me too on the STM32F407. Yay, I'll prepare a PR. |
I stumbled over a coarse resolution of the
BMP180
sensor connected to anSTM32F103C8T6
atI2cMaster1
. When reading exactly two bytes the first byte is not acknowledged by the master so that the slave will not send its second byte. The value is then always0xff
and that resulted in a coarse temperature resolution.Nevertheless the transaction returns
true
.When reading three or more bytes the first data read is acknowledged.
With an
STM32F407
discovery board the two bytes read works correctly:The text was updated successfully, but these errors were encountered: