I've just started with the I2C protocol. I read about it in the datasheet, other documents, blogs and videos.
So, I started to develop my code and I think I did my first success, I succeeded to send start and check TWST for sending start signal.
I get started OK, but I can't proceed to send data. What I'm missing? I'm thinking I didn't send the correct address.
void I2C_init(void);
void I2C_start(void);
void I2C_stop(void);
void I2C_tx(uint8_t data);
void I2C_TWSR_Check(void);
void setup() {
Serial.begin(9600);
I2C_init();
// I2C_TWSR_Check();
I2C_start();
I2C_TWSR_Check();
I2C_tx(0x40); // sending the address
I2C_TWSR_Check(); // waiting for response
}
void loop() {
uint8_t i;
// simple loop to blink an LED on the I/O expander pin
for (i=0;i<5;i++) {
I2C_tx(0xff);
I2C_TWSR_Check();
_delay_ms(500);
I2C_tx(0x00);
I2C_TWSR_Check();
_delay_ms(500);
}
}
void I2C_init(void) {
//set SCL to 100kHz
TWSR = 0x00;
TWBR = 0x48;
//enable TWI
TWCR = (1<<TWEN);
}
void I2C_start(void) {
TWCR = (1<<TWINT)|(1<<TWSTA)|(1<<TWEN);
while (!(TWCR & (1<<TWINT)));
}
void I2C_stop(void) {
TWCR = (1<<TWINT)|(1<<TWSTO)|(1<<TWEN);
}
void I2C_tx(uint8_t u8data) {
TWDR = u8data;
while (!(TWCR & (1<<TWINT)));
}
void I2C_TWSR_Check(void) {
uint8_t Status;
Status = TWSR & 0xF8;
switch(Status) {
case 0x08: // start OK
Serial.println("Start is OK");
break;
case 0x10: // Re start
Serial.println("Re start");
break;
case 0x18: // SLA+W OK ACK
Serial.println("SLA+W OK ACK");
break;
case 0x20: // SLA+W no ACK
Serial.println("SLA+W no ACK");
break;
case 0x28: // data OK ACK
Serial.println("data OK ACK");
break;
case 0x30: // data OK no ACK
Serial.println("data OK no ACK");
break;
case 0x38: // arbitration lost in SLA+W or data TX
Serial.println("arbitration lost in SLA+W or data TX");
break;
default:
Serial.println("Error");
break;
}
}
-
Can you tell us exactly what I/O expander device you are using? If you could provide a link to the documentation that would be great!Mazaryk– Mazaryk2017年05月04日 15:32:10 +00:00Commented May 4, 2017 at 15:32
-
picclickimg.com/d/l400/pict/181805816595_/… Thank you so much for reply,R1S8K– R1S8K2017年05月04日 16:09:57 +00:00Commented May 4, 2017 at 16:09
-
I solved the problem :)R1S8K– R1S8K2017年05月05日 08:28:04 +00:00Commented May 5, 2017 at 8:28
-
Can you post the solution as an answer and accept the answer then, it might help people that have a similar issue in the future.Code Gorilla– Code Gorilla2017年05月05日 09:20:23 +00:00Commented May 5, 2017 at 9:20
-
Of course, but can I post it as an answer?R1S8K– R1S8K2017年05月09日 14:44:47 +00:00Commented May 9, 2017 at 14:44
1 Answer 1
OK the answer is that I didn't send the correct address!
Because if the I2C starting command with the slave is successful, then you should get successful sending ACK according reading the value of transmission status from the status register TWSR and ANDing this value with 0xF8. Then by reading the datasheet you know the value of transmission status. I developed a function to determine the status of transmission with Arduino Serial library which is I2C_TWSR_Check();.
I did this code for Master transmitter and receiver only.
So the trick is that you have to fix the address according to the AVR's TW address command format, which is the first bit is for read/write command and the remaining 7-bits are for the address, so you have to shift the real address which I got by "I2C address scanner" I got from one of AVRfreaks members.
For example, if the address is 0x20, then after shifting it 1-bit to the left, the new address is 0x40 for write operation and 0x41 for read operation.
void I2C_init(void);
void I2C_start(uint8_t address);
void I2C_stop(void);
void I2C_tx(uint8_t data);
uint8_t I2C_rx(void);
void I2C_TWSR_Check(void);
uint8_t bitmask;
/////////// I2C modules addresses ////////////
// 8-bit I/O expander 0x20
#define IOEXP_WR 0x40 // I/O 8-bits expander address
#define IOEXP_RD 0x41
// LCD1602 adapter
#define LCD1602_WR 0x4E // LCD1602 I2C adapter address
#define LCD1602_RD 0x4F
void setup() {
// put your setup code here, to run once:
Serial.begin(9600);
I2C_init();
}
void loop() {
I2C_start(LCD1602_WR);
I2C_TWSR_Check();
I2C_tx(0xff);
I2C_TWSR_Check();
I2C_stop();
_delay_ms(500);
I2C_start(LCD1602_WR);
I2C_tx(0x00);
I2C_stop();
_delay_ms(500);
}
void I2C_init(void)
{
//set SCL to 100kHz
TWSR = 0x00;
TWBR = 0x48;
//enable TWI
TWCR = (1<<TWEN);
}
void I2C_start(uint8_t address)
{
TWCR = (1<<TWINT)|(1<<TWSTA)|(1<<TWEN);
while (!(TWCR & (1<<TWINT)));
//I2C_TWSR_Check();
TWDR = address;
TWCR = (1<<TWINT)|(1<<TWEN)|(1<<TWEA);
while (!(TWCR & (1<<TWINT)));
//I2C_TWSR_Check();
}
void I2C_stop(void)
{
TWCR = (1<<TWINT)|(1<<TWSTO)|(1<<TWEN);
}
void I2C_tx(uint8_t data)
{
TWDR = data;
TWCR = (1<<TWINT)|(1<<TWEN)|(1<<TWEA);
while (!(TWCR & (1<<TWINT)));
//I2C_TWSR_Check();
}
uint8_t I2C_rx(void)
{
TWCR = (1<<TWINT)|(1<<TWEN)|(1<<TWEA);
while (!(TWCR & (1<<TWINT)));
return TWDR;
}
void I2C_TWSR_Check(void)
{
uint8_t Status;
Status = TWSR & 0xF8;
switch(Status)
{
/////////////// MASTER TRANSMITTER //////////////
case 0x08:
Serial.println("Start is OK");
break;
case 0x10:
Serial.println("Re start");
break;
case 0x18:
Serial.println("SLA+W OK ACK");
break;
case 0x20:
Serial.println("SLA+W no ACK");
break;
case 0x28:
Serial.println("data TX OK ACK");
break;
case 0x30:
Serial.println("data TX OK no ACK");
break;
case 0x38: // arbitration lost in SLA+W or data TX
Serial.println("arbitration lost in SLA+W or data TX");
break;
/////////////// MASTER RECEIVER //////////////
case 0x40:
Serial.println("SLA+R OK ACK");
break;
case 0x48:
Serial.println("SLA+R OK NO ACK");
break;
case 0x50:
Serial.println("data RX OK ACK");
break;
case 0x58:
Serial.println("data RX OK NO ACK");
break;
default:
Serial.println("Error");
break;
}
}
-
Question titles on SE sites should not be edited to indicate that a problem has been solved, rather the answer providing the solution should be marked accepted - even when as in this case it is your own.Chris Stratton– Chris Stratton2017年06月09日 15:39:34 +00:00Commented Jun 9, 2017 at 15:39
-
I thought it's better to declare to the viewer that the problem for this topic is solved and so anyone who is browsing for a certain point on Google would see that it's solved.R1S8K– R1S8K2017年06月11日 01:18:32 +00:00Commented Jun 11, 2017 at 1:18
-
The procedure for that on SE sites is accepting an answer, not editing the title. So accept your own answer - only that will cause the system to consider it resolved and stop churning it back up as if it needs further attention.Chris Stratton– Chris Stratton2017年06月11日 02:11:02 +00:00Commented Jun 11, 2017 at 2:11
-
"and stop churning it back up as if it needs further attention", what does this mean? Not so clear to me :) sorry.R1S8K– R1S8K2017年06月11日 02:17:18 +00:00Commented Jun 11, 2017 at 2:17
-
Just click the hollow check mark beside your answer so we can be done with this.Chris Stratton– Chris Stratton2017年06月11日 02:24:36 +00:00Commented Jun 11, 2017 at 2:24