В общем у меня вот такое родилось, работает. На шине одновременно висят EEPROM 24LC16 и LIS3DH
CODE
// ==================================================
void I2C_Start_Direction_Adress_Size (I2C_TypeDef* Port, uint32_t Direction, uint8_t Adress, uint8_t Size)
{
Port->CR2 &= ~I2C_CR2_AUTOEND; // Stop by siftware
Port->CR2 &= ~I2C_CR2_RELOAD; // No reload
if (Direction == I2C_CR2_RD_WRN) Port->CR2 |= I2C_CR2_RD_WRN; // receive mode
else Port->CR2 &= ~I2C_CR2_RD_WRN; // transmit mode
Port->CR2 &= ~I2C_CR2_NBYTES; // clear NBYTES field
Port->CR2 |= Size<<16; // Set NBYTES
Port->CR2 &= ~I2C_CR2_SADD; // clear slave address field
Port->CR2 |= Adress; // Set slave address
Port->CR2 |= I2C_CR2_START; // Transmit START bit
while ((Port->ISR & I2C_ISR_BUSY)==0) {}; // Wait for done
}
// ==================================================
// ==================================================
void I2C_Stop (I2C_TypeDef* Port)
{
Port->CR2 |= I2C_CR2_STOP; // Stop to bus
while (Port->ISR & I2C_ISR_BUSY) {}; // wait for stop transmitted
// Clear flags
Port->ICR |= I2C_ICR_STOPCF;
Port->ICR |= I2C_ICR_NACKCF;
// Clear errors flags
if (Port->ISR & (I2C_ISR_ARLO | I2C_ISR_BERR))
{
Port->ICR |= I2C_ICR_ARLOCF;
Port->ICR |= I2C_ICR_BERRCF;
}
}
// ==================================================
i2c_operate_t I2C_Operate(I2C_TypeDef* Port, uint8_t addr, void* trsm, uint8_t tcount, void* rcv, uint8_t rcount)
{
uint8_t *u8_ptr;
uint32_t status;
if (((tcount==0) && (rcount==0)) || (tcount)) // tcount== 0 and rcount==0 for device presence check
{
I2C_Start_Direction_Adress_Size(Port, 0, addr, tcount);
// Check for status
while (!(Port->ISR & (I2C_ISR_TC | I2C_ISR_TXIS | I2C_ISR_NACKF) && (Port->ISR & I2C_ISR_BUSY))) {};
if (Port->ISR & I2C_ISR_NACKF)
{
I2C_Stop(Port);
return I2C_OPERATE_NO_DEVICE;
}
}
// Transmit part
if (tcount)
{
u8_ptr = (uint8_t*)trsm;
while ((((Port->ISR & I2C_ISR_TC)==0) && ((Port->ISR & I2C_ISR_NACKF)==0)) && (Port->ISR & I2C_ISR_BUSY))
{
if (Port->ISR & I2C_ISR_TXIS) Port->TXDR = *u8_ptr++; // Send data
}
status = Port->ISR;
if (status & (I2C_ICR_ARLOCF | I2C_ICR_BERRCF | I2C_ISR_NACKF)) // some errors
{
I2C_Stop(Port);
if (status & (I2C_ICR_ARLOCF | I2C_ICR_BERRCF)) return I2C_BUS_ERROR;
if (status & I2C_ISR_NACKF) return I2C_OPERATE_WRITE_NACK;
}
}
// Receive part
if (rcount)
{
u8_ptr = (uint8_t*)rcv;
I2C_Start_Direction_Adress_Size (Port, I2C_CR2_RD_WRN, addr, rcount);
if (Port->ISR & I2C_ISR_NACKF)
{
I2C_Stop(Port);
return I2C_OPERATE_NO_DEVICE;
}
u8_ptr = (uint8_t*)rcv;
while (!(Port->ISR & (I2C_ISR_TC | I2C_ISR_NACKF)) && (Port->ISR & I2C_ISR_BUSY))
{
if (Port->ISR & I2C_ISR_RXNE) *u8_ptr++ = Port->RXDR; // Receive data
}
}
status = Port->ISR;
I2C_Stop(Port);
if (status & (I2C_ICR_ARLOCF | I2C_ICR_BERRCF | I2C_ISR_NACKF)) // some errors
{
I2C_Stop(Port);
if (status & (I2C_ICR_ARLOCF | I2C_ICR_BERRCF)) return I2C_BUS_ERROR;
if (status & I2C_ISR_NACKF) return I2C_OPERATE_READ_NACK;
}
return I2C_OPERATE_OK;
}