-
Notifications
You must be signed in to change notification settings - Fork 47
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
ACK polling #9
Comments
Using "classic" i2c_master lib this implemented next way:
|
In i2c there is a mechanism called clock stretching, which is used by slaves to signal to the master to wait, i.e. they are pulling SCL low. This is fully supported with brzo i2c. Now, it seems that this device is implementing this somehow with SDA. From the description in the datasheet I understood ACK polling this way: After the 8th SCL cycle has finished, the 9th cycle begins, and on the raising edge of SCL the master samples SDA. If SDA is high then it means NACK by the slave. This is the standard i2c operation. Now, this guy seems to keep SDA high for twr msecs (i.e. it is not yet ACKnowledging), before it will pull SDA low, to signal an ACK. i.e., it "stretches" SDA. The datasheet doesn't say what the slave is doing during twr msec with SCL. I guess, it won't pull it down (i.e. not stretching it). If the device is not pulling SCL low, then brzo i2c will read SDA being high and interprete it as NACK. So, it looks to me that this is very very special way of "clock" (i.e. SDA) stretching.... and I even would go that far to say that it is not really according to the i2c standard. What you would need to do is to wait twr msec after writes with a I also had a look in the microchip 24AA256/24LC256/24FC256 datasheet under section 7.0, there is a diagram explaining it better (for my understanding at least ;-) If the device could work with a STOP sequence after an NACK was returned, then you can do it with brzo i2c, otherwise not. |
Looks like Microchip EEPROM have same logic for "ACK polling" as Atmel. So in your opinion I just need to set clock stretching to 10000 before issuing write command to EEPROM? UPD: It's possible to implement this "ACK polling" in assembly in your library? |
|
P.S. |
Here is my investigation.
but this more looks like workaround than correct approach. Here is decoded signal from Logic Analizer, writing at address 0 array of 10 bytes all value 3:
And here is what actually should be:
While investigated that, I found one thing that makes your library hard to use for EEPROM write operations. Pay attention on my Logic Analizer output, notice two "0" after "Setup write" and then ten "1". Zeroes is the target EEPROM address, ten "1" - is data. The tricky part here is that if I will use two separate calls to brzo_i2c_write I will have additional "Setup write" before address and data - and this is error. Address and Data must be sent one after another, so imagine that I have next function prototype to write data to EEPROM:
To overrun this I need to malloc temporary array with size of data + 2, copy first two bytes of address into it, then copy data and after that send it in one brzo_i2c_write call. I guess this looks like redundant memory allocation:
So actually it would be very nice to have ability to control I2C at a bit lower level than you currently provide. Compared to "i2c_master", your library provide ideal SCL clock and timings and with you lib I get rid of my problem that I mentioned in previous post. But in current implementation it's not very comfortable to use it. By the way, there is an issue #1 - using Arduino "Wire" interface EEPROM write operation can be done like this:
|
Here is some ideas:
|
A big thank you for your investigations 👏 Since my "other work" keeps me rather busy these days, my answer is a bit short:
btw: Since you mentioned "i2c_master", are you using the native SDK only or are you on the arduino toolchain? EDIT: Will take a look at ACK Polling this weekend. |
Yes, I'm working with native non-os SDK (https://github.com/CHERTS/esp8266-devkit). Your library does not work out-of-box with it, but with minor modifications (like changing About ACK polling, it looks like really good thing because in my examples using ACK polling I have achieved only 1.4ms EEPROM post-write delay instead of hard-coded 10ms. So it was required to wait less more than in 5 times. |
I'm also trying to get the brzo_i2c library to work with a native non-os SDK (https://github.com/pfalcon/esp-open-sdk) . The compiler is giving me an error that I don't know how to fix:
The line it points to is the valkuc: Did you also run into this problem? Any idea of how to fix it? |
No, I did not have this issue. Probably you miss necessary includes. |
Perhaps it could also be related to the fact that I had to remove the
Did you have issues with these specifiers as well? |
Switch to gnu99 standard to solve issue with "asm volatile" (i.e. -std=gnu99 in CFLAGS). Or gnu89 if you currently on c89. |
Didn't help. I get the same error using either The CFLAG variable in my Makefile looks like this:
|
@valkuc : Great that you managed to compile it with the native SDK! I had a longer discussion with Pete Scargill about compiling my lib with the native SDK. As it seems, he was not successful. |
Sure, I can share my version of bzro-i2c library for non-os SDK. One problem is that I have removed all Arduino related code from it. So I need some time to adopt it to work both on Arduino and clean SDK. Anyway I will upload it today evening/night. |
I also managed to compile it for the non-os SDK! Adding the
Also works with |
@valkuc : Cool! Although being (much) less elegant, I could live with separate sources as well, i.e. one for native SDK, the other for Arduino... |
Pull request created. Code base almost same, ASM code untouched, just added conditional defines for ARDUINO |
The ACK polling support, I will have to shift for next weeks. Did a couple of local changes in order to have then a |
Thanks! Just added my vision about round() usage here #10 (comment) |
@valkuc : About success on ACK polling, i.e. when the master receives an ACK aft some times of polling: Does the EEPROM expect a STOP and then (of the next command) a START ... or is it without the STOP? If I have a look at the microchip datasheet, it says (page 10) ...If the cycle is complete, then the device will return the ACK and the master can then proceed with the next Read or Write command. => This is as Figure 7-1, i.e. without the STOP. So, which behaviour should I implement? |
I think we don't need to send STOP... we just poll, poll, poll slave device in loop until receive response, then exit loop. |
OK |
From http://www.microchip.com/forums/m536035.aspx ● Initial condition: a Write cycle is in progress. ● Step 1: the bus master issues a Start condition followed by a device select code (the ● Step 2: if the device is busy with the internal Write cycle, no ACK will be returned and |
I've just uploaded a first version of ACK polling, it's in this branch. Since I dont' have the EEPROM I cannot really test it. When I do the test with another i2c slave, I correctly get an ACK polling time out. Also, the scope pictures looks OK, i.e. the loop should work. For the Arduino Tool Chain, a very simple test sketch looks like this #include "brzo_i2c\brzo_i2c.h";
uint8_t SDA_PIN = 5;
uint8_t SCL_PIN = 4;
uint8_t SLAVE_ADDRESS = 0x52;
// 7 Bit Address is 52h aka Control Byte 1010 010 0b, with A2 = 0, A1 = 1, A0 = 0 and W = 0 => 164d, A4h
uint8_t dummy = 10;
uint8_t error = 0;
void setup() {
delay(1000);
Serial.begin(115200);
brzo_i2c_setup(SDA_PIN, SCL_PIN, 20000);
delay(1000);
}
void loop() {
Serial.println("Waiting 5 Seconds...");
delay(5000);
brzo_i2c_start_transaction(SLAVE_ADDRESS, 400);
// Write only the slave address, with the EEPROM you would write some bytes of course
brzo_i2c_write(&dummy, 0, false);
// With 400 KHz, a 50 usec timeout gives two iterations,
// otherwise here it is with 10 msec, i.e. 10000 usec
brzo_i2c_ACK_polling(10000);
error = brzo_i2c_end_transaction();
Serial.println(error);
}
Could you please check it? If you have a scope, scope picture will help me doing the debugging 😄 Could you please test it with your EEPROM? |
Thanks! |
I have tested new method. It's "almost" working, only one strange thing happens.
Writing 40 bytes to EEPROM (40 is just to write across multiple pages: write 32 bytes to first page, then 8 to second, they will be split by my routines into two write sequences) gives next signals in logic analizer:
So, looking in communication data it looks like all super and as it should be.
For some reason in terminal I see multiple occurrences of As I noted before, I'm writing 40 bytes, so actually I'm doing 2 write cycles - 32 and 8 bytes each. UPD: |
Thanks for the tests. I guess I already know... I forgot something ;-) => I will add this and you can test more :-) |
I've just added the (most probably) missing statement here in the ack polling branch. btw: Your waiting loop is dangerous, it will iterate over and over in case of ACK polling timeouts (i.e. error return code 34), but I think you did it for test purposes only. Otherwise change |
Tested again. Now all works as expected! Guess it's time to merge this branch into master.
Sure, I have added loop only to find that issue, now I will remove it. |
Now, about what I described in comment #9 (comment) about |
|
Hello,
I need to read and write to AT24C32 i2c eeprom. To ensure data was written by chip I need to use "acknowledge polling".
From datasheet:
How can I do ACK polling with you library?
The text was updated successfully, but these errors were encountered: