Dear Dialog Support Team,
Recently, we are porting LIS2DS/LIS3DH driver on DA14580 platform, but get stuck in I2C operation.
LISx sensor has different read sequence from other reference i2c sensor (like mc3410)/i2c eeprom.
Here is the sequence of reading one byte from slave
---------------
Master | ST | SAD + W | ... ... | SUB | ... ... | SR | SAD + R | ... ... | ... ... ... | NMAK | SP
Slave | ... ... | ... ... ... ... | SAK | ... ... | SAK | ... ... | ... ... ... ... | SAK | DATA | .... ... | ...
ST: Start Condition
SR: Repeated Start Condition
SP:停止条件
SAK: Slave Acknowledge
SUB: Slave Sub-Address, register address in LISxDx
SAD: Slave Address, 0x3a, 0011 1010
SAD + W: Slave Address + W, 0x3a, 0011 1010
SAD + R: Slave Address + R, 0x3b, 0011 1011
NMAK: No Master Acknowledge
----
My question is how to implement SR + (SAD +R), and I tried to use
// Send repeated SR & set SAD + R
SetWord16(I2C_TAR_REG, ((i2c_dev_address + 1) & IC_TAR)|SPECIAL|GC_OR_START);
as below:
void i2c_master_init(uint16_t dev_address, uint8_t speed, uint8_t address_mode, uint8_t address_size)
{
mem_address_size = address_size;
SetBits16(CLK_PER_REG, I2C_ENABLE, 1); // enable clock for I2C
SetWord16(I2C_ENABLE_REG, 0x0); // Disable the I2C controller
SetWord16(I2C_CON_REG, I2C_MASTER_MODE | I2C_SLAVE_DISABLE | I2C_RESTART_EN); // Slave is disabled
SetBits16(I2C_CON_REG, I2C_SPEED, speed); // Set speed
SetBits16(I2C_CON_REG, I2C_10BITADDR_MASTER, address_mode); // Set addressing mode
SetWord16(I2C_TAR_REG, (dev_address & IC_TAR)); // Set Slave device address
SetWord16(I2C_ENABLE_REG, 0x1); // Enable the I2C controller
while( (GetWord16(I2C_STATUS_REG) & 0x20) != 0 ); // Wait for I2C master FSM to be IDLE
i2c_dev_address = dev_address;
}
uint8_t i2c_read_byte(uint32_t address)
{
SEND_I2C_COMMAND(地址& 0 xff); // Set address LSB, write access
// Send repeated SR & set SAD + R
SetWord16(I2C_TAR_REG, ((i2c_dev_address + 1) & IC_TAR)|SPECIAL|GC_OR_START);
WAIT_WHILE_I2C_FIFO_IS_FULL(); // Wait if Tx FIFO is full
SEND_I2C_COMMAND(0x0100); // Set R/W bit to 1 (read access)
WAIT_UNTIL_I2C_FIFO_IS_EMPTY(); // Wait until I2C Tx FIFO empty
WAIT_FOR_RECEIVED_BYTE(); // Wait for received data
return (0xFF & GetWord16(I2C_DATA_CMD_REG)); // Get received byte
}
However, it doesn't work, and the program is blocked at "WAIT_FOR_RECEIVED_BYTE()".
I also reviewed the previous discussions about i2c operations, but it seems there is nobody to talk about the repeated SR.
Please help on this topic, thank you in advance!
Hi Horace,
You dont have to do anything explictly in order to issue a restart condition on the 580's i2c module. The I2C module will issue a restart command (a start command) when you switch from Read to Write command or the opposite (Write to Read command). Please check the attachment, is the interaction of the 580 with an I2C eeprom flash.
Thanks MT_dialog
Dear MT,
Thanks a lot for reply.
>> The I2C module will issue a restart command (a start command) when you switch from Read to Write command or the opposite (Write to Read command
OK, so I simply changed the code like below:
- // Send repeated Start Condition & Set Slave device address
-// SetWord16(I2C_TAR_REG, ((i2c_dev_address + 1) & IC_TAR)|SPECIAL|GC_OR_START);
+ // Set Slave device address
+ SetWord16(I2C_TAR_REG, ((i2c_dev_address + 1) & IC_TAR));
But it still gets dead-loop in
WAIT_FOR_RECEIVED_BYTE(); // Wait for received data
The sequence that required by sensor is a little different from the picture that you attached,
and there is only 1 data written after setup write cmd in LISxDx sensor, rather than 2 in eeprom flash.
I have no idea why the following code doesn't work :(
...
SetWord16(I2C_TAR_REG, (i2c_dev_address & IC_TAR)); // Set Slave device address
SetWord16(I2C_ENABLE_REG, 0x1); // Enable the I2C controller
while( (GetWord16(I2C_STATUS_REG) & 0x20) != 0 ); // Wait for I2C master FSM to be IDLE
SEND_I2C_COMMAND(register & 0xFF); // Set address LSB, write access
// Set SAD + R
SetWord16(I2C_TAR_REG, ((i2c_dev_address + 1) & IC_TAR));
WAIT_WHILE_I2C_FIFO_IS_FULL(); // Wait if Tx FIFO is full
SEND_I2C_COMMAND(0x0100); // Set R/W bit to 1 (read access)
WAIT_UNTIL_I2C_FIFO_IS_EMPTY(); // Wait until I2C Tx FIFO empty
WAIT_FOR_RECEIVED_BYTE(); // Wait for received data
Please help to indicate where the issue is, thanks again!
Hi Horace,
In order to produce the sequence that you ve indicated above i ve used the following code:
i2c_eeprom_init(I2C_SLAVE_ADDRESS, I2C_SPEED_MODE, I2C_ADDRESS_MODE, I2C_ADDRESS_SIZE); //initialize the i2c, in I2C address size place the address size of your device times
SEND_I2C_COMMAND(0x03 & 0xFF); // the address size that device has is two bytes length, if your device takes one byte length you can use this instruction to read from 0x03 address or whatever address you need.
WAIT_WHILE_I2C_FIFO_IS_FULL(); // Wait if Tx FIFO is full
SEND_I2C_COMMAND(0x0100); // Set read access for
The above snippet produces the waveform that i ve attached below, of course the data responded from the memory is wrong but i suppose this is what you are looking for.
Thanks MT_dialog
Dear MT,
Thank you very much for kind help.
However, the case is more complicated than the scenario that you wrote
In your case, the slave address is kept at 0x50 unchanged.
But as the attached spec, the LIS sensor has following requirements.
1)
The Slave Address (SAD) associated to the LIS2DS12 is 00111xxb where the xx bits are
modified by the SA0/SDO pin in order to modify the device address.
If the SA0/SDO pin is connected to the supply voltage, the address is 0011101b
2)
The slave address is completed with a Read/Write bit. If the bit is ‘1’ (Read), a repeated
START (SR) condition must be issued after the two sub-address bytes. If the bit is ‘0’ (Write)
the master will transmit to the slave with direction unchanged
Therefore, SAD + R = 0x3b, while SAD + W = 0x3a (if SA0 is connected to VCC)
it means I have to change the value in I2C_TAR_REG twice to generate the sequence in Table 20 (please check the attached file or my first comment)
I tried several combinations, but all attempts failed, like:
i2c_eeprom_init(0x3A, I2C_FAST, I2C_7BIT_ADDR, I2C_1BYTE_ADDR); //initialize the i2c, SAD + W, FAST_MODE, 7BIT, 1BYTE
SEND_I2C_COMMAND(0x0F); // WHO_AM_I_REG address -- 0xF
WAIT_WHILE_I2C_FIFO_IS_FULL(); // Wait if Tx FIFO is full
1) SetWord16(I2C_TAR_REG, (0x3A + 1)); // Repeat SR + (SAD + R)
2) SetWord16(I2C_ENABLE_REG, 0);
SetWord16(I2c_TAR_REG, (0x3A + 1)); // Repeat SR + (SAD + R)
SetWord16(I2C_ENABLE_REG, 1);
WAIT_WHILE_I2C_FIFO_IS_FULL(); // Wait if Tx FIFO is full
SEND_I2C_COMMAND(0x0100);
...
Any suggestions?
Hi Horace,
我不看到任何不同的特定sensor, as far as i can understand, the one pin that defines the address of the sensor should be connected either to vcc or gnd in order to define the sensors 7bit address 0x1D or 0x1E, this is what you should set in the I2C_TAR_REG, after that you dont have to change the value of the I2C_TAR_REG when you want to perform a read or a write operation, the I2C module will add a "0" or a "1" automatically, just like the captures i ve sent you. In the captures i ve attached the instrument decodes the address and the read and write operation, if you check the clocks and the pulses on SDA and SCL you will see that the write is Write [0x50] is an 8-bit sequence of 0x50 plus an extra 0 to declare write (if you read it as an 8-bit number this results in 0xA0) and in the read operation Read [0x50] is an 8-bit sequence of 0x50 plus an extra 1 to declare read (if you read it as am 8-bit number this wil result to a 0xA1). Please try using as a target addres NOT 0x3A but 0x1D which is the actual address of your device, the additional bit will be placed (either a "1" or a "0") when you perform a read or write, and that is done via the I2C_DATA_CMD_REG. If you write to the I2C_DATA_CMD_REG the value of the sub-address of the slave (write only the 0:7 bits of the register) the module will send out the address of the device followed by the Write command (hence 1D(11101) + 0 -> 0x3A) followed by the data that you ve written in the I2C_DATA_CMD_REG. After that when you want to read, by writting the value 0x100 the module will understand that you want to perform a read (since you have set the 9th bit of theI2C_DATA_CMD_REG) and will provide the address of the device it wants to read, followed by a read command (hence 1D(11101)+1 -> 0x3B) and clock on the SCL line in order to clock data from the slave from the address previously written on the bus, as long as there ins't a stop condition on the bus and you keep feeding the I2C_DATA_CMD_REG with 0x100 the module will keep on providing clock (without exposing the Slave address).
Thanks MT_dialog
Hi MT,
Tons of thanks for your patience & kind guiding, although it still doesn't work.
I guess the remaining issue might be related to timing, and will capture the signals of SDA & SCL later.
Hi MT,
The driver works now, after the hardware guy replaced with a new board.
Please close the ticket, thank you again for saving our hours!