не используйте отладчик при работе с системными регистрами кроме случаев когда вы знаете чем это грозит.
там у них... ну, мне не нравится как стм сделал I2C. Вот смотрите примерчик, брал у кого-то(то ли stm32lib, толи opencm3), что-то исправил, что-то добавил. из-за лени там всё ещё есть одна ошибка:
при ошибке обмена не сбрасывается периферия и следующий START не начнётся.
Код
namespace Driver
{
class CI2C : public Driver::II2CDevice
{
private:
I2C_TypeDef* const mI2C;
uint16_t mArbitrationTimeout;
public:
CI2C(I2C_TypeDef* const pI2C)
: mI2C(pI2C), mArbitrationTimeout(0)
{
}
//////////////////////////////////////////////
///////////// General control set ////////////
//////////////////////////////////////////////
virtual void SetArbitrationTimeout(const uint16_t pTimeoutMS) final { mArbitrationTimeout = pTimeoutMS; }
//////////////////////////////////////////////
////////////// Data exchange set /////////////
//////////////////////////////////////////////
virtual Service::ERetVal Write(const uint8_t pAddress, const uint8_t* pData, const uint8_t pDataSize) final;
virtual Service::ERetVal Read(const uint8_t pAddress, uint8_t* pData, const uint8_t pDataSize) final;
};
}
Код
namespace Driver
{
Service::ERetVal CI2C::Write(const uint8_t pAddress, const uint8_t* pData, const uint8_t pDataSize)
{
using namespace Service;
uint16_t tto;
if(pDataSize == 0) return ERetVal::InvalidArgument;
tto = mArbitrationTimeout;
while(I2C_GetFlagStatus(mI2C, I2C_FLAG_BUSY) == SET) { Delay_MS::U8(1); if(--tto == 0) return ERetVal::DeviceBusy; }
// Start the config sequence
I2C_GenerateSTART(mI2C, ENABLE);
// Test on EV5 and clear it
tto = mArbitrationTimeout;
while(I2C_CheckEvent(mI2C, I2C_EVENT_MASTER_MODE_SELECT) == RESET) { Delay_MS::U8(1); if(--tto == 0) return ERetVal::DeviceBusy; }
// Transmit the slave address and enable writing operation
I2C_Send7bitAddress(mI2C, pAddress, I2C_Direction_Transmitter);
// Test on EV6 and clear it
tto = mArbitrationTimeout;
while(I2C_CheckEvent(mI2C, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED) != SUCCESS) { Delay_MS::U8(1); if(--tto == 0) return ERetVal::DeviceBusy; }
// EV6
uint8_t to_send = pDataSize;
uint8_t i = 0;
// Write first byte EV8_1
I2C_SendData(mI2C, pData[i++]);
while(--to_send)
{
// wait on BTF
tto = mArbitrationTimeout;
while(I2C_GetFlagStatus(mI2C, I2C_FLAG_BTF) != SET) { Delay_MS::U8(1); if(--tto == 0) return ERetVal::DeviceBusy; }
I2C_SendData(mI2C, pData[i++]);
}
// wait on BTF
tto = mArbitrationTimeout;
while(I2C_GetFlagStatus(mI2C, I2C_FLAG_BTF) != SET) { Delay_MS::U8(1); if(--tto == 0) return ERetVal::DeviceBusy; }
// генерируем STOP
I2C_GenerateSTOP(mI2C, ENABLE);
tto = mArbitrationTimeout;
while(I2C_GetFlagStatus(mI2C, I2C_FLAG_STOPF) == SET) { Delay_MS::U8(1); if(--tto == 0) return ERetVal::DeviceBusy; }
return Service::ERetVal::Ok;
}
Service::ERetVal CI2C::Read(const uint8_t pAddress, uint8_t* pData, const uint8_t pDataSize)
{
using namespace Service;
uint16_t tto;
if(pDataSize < 1) return Service::ERetVal::InvalidArgument;
// Wait for idle I2C interface
tto = mArbitrationTimeout;
while(I2C_GetFlagStatus(mI2C, I2C_FLAG_BUSY) == SET) { Delay_MS::U8(1); if(--tto == 0) return ERetVal::DeviceBusy; }
// Enable Acknowledgement, clear POS flag
I2C_AcknowledgeConfig(mI2C, ENABLE);
I2C_NACKPositionConfig(mI2C, I2C_NACKPosition_Current);
// Intiate Start Sequence (wait for EV5
I2C_GenerateSTART(mI2C, ENABLE);
tto = mArbitrationTimeout;
while(I2C_CheckEvent(mI2C, I2C_EVENT_MASTER_MODE_SELECT) == RESET) { Delay_MS::U8(1); if(--tto == 0) return ERetVal::DeviceBusy; }
// Send Address
I2C_Send7bitAddress(mI2C, pAddress, I2C_Direction_Receiver);
// EV6
tto = mArbitrationTimeout;
while(I2C_GetFlagStatus(mI2C, I2C_FLAG_ADDR) == RESET) { Delay_MS::U8(1); if(--tto == 0) return ERetVal::DeviceBusy; }
uint8_t i = 0;
if(pDataSize == 1)
{
// Clear Ack bit
I2C_AcknowledgeConfig(mI2C, DISABLE);
// EV6_1 -- must be atomic -- Clear ADDR, generate STOP
__disable_irq();
(void)mI2C->SR2;
I2C_GenerateSTOP(mI2C, ENABLE);
__enable_irq();
// Receive data EV7
tto = mArbitrationTimeout;
while(I2C_GetFlagStatus(mI2C, I2C_FLAG_RXNE) == RESET) { Delay_MS::U8(1); if(--tto == 0) return ERetVal::DeviceBusy; }
pData[i++] = I2C_ReceiveData(mI2C);
}
else if(pDataSize == 2)
{
// Set POS flag
I2C_NACKPositionConfig(mI2C, I2C_NACKPosition_Next);
// EV6_1 -- must be atomic and in this order
__disable_irq();
(void)mI2C->SR2; // Clear ADDR flag
I2C_AcknowledgeConfig(mI2C, DISABLE); // Clear Ack bit
__enable_irq();
// EV7_3 -- Wait for BTF, program stop, read data twice
tto = mArbitrationTimeout;
while(I2C_GetFlagStatus(mI2C, I2C_FLAG_BTF) != SET) { Delay_MS::U8(1); if(--tto == 0) return ERetVal::DeviceBusy; }
__disable_irq();
I2C_GenerateSTOP(mI2C, ENABLE);
pData[i++] = mI2C->DR;
__enable_irq();
pData[i++] = mI2C->DR;
}
else
{
uint8_t to_read = pDataSize;
volatile uint32_t tsr;
tsr = mI2C->SR2; // Clear ADDR flag
while(to_read-- != 3)
{
// EV7 -- cannot guarantee 1 transfer completion time, wait for BTF instead of RXNE
tto = mArbitrationTimeout;
while(I2C_GetFlagStatus(mI2C, I2C_FLAG_BTF) != SET) { Delay_MS::U8(1); if(--tto == 0) return ERetVal::DeviceBusy; }
pData[i++] = I2C_ReceiveData(mI2C);
}
tto = mArbitrationTimeout;
while(I2C_GetFlagStatus(mI2C, I2C_FLAG_BTF) != SET) { Delay_MS::U8(1); if(--tto == 0) return ERetVal::DeviceBusy; }
// EV7_2 -- Figure 1 has an error, doesn't read N-2 !
I2C_AcknowledgeConfig(mI2C, DISABLE); // clear ack bit
__disable_irq();
pData[i++] = I2C_ReceiveData(mI2C); // receive byte N-2
I2C_GenerateSTOP(mI2C,ENABLE); // program stop
__enable_irq();
pData[i++] = I2C_ReceiveData(mI2C); // receive byte N-1
pData[i++] = I2C_ReceiveData(mI2C); // receive byte N
to_read = 0;
}
// Wait for stop
tto = mArbitrationTimeout;
while(I2C_GetFlagStatus(mI2C, I2C_FLAG_STOPF) == SET) { Delay_MS::U8(1); if(--tto == 0) return ERetVal::DeviceBusy; }
return Service::ERetVal::Ok;
}
}