Use information from STM32Cube to update the I2C driver.

This commit is contained in:
Jonathan Naylor 2021-02-28 13:23:17 +00:00
parent f033fea2fb
commit 2ae731e78c
4 changed files with 51 additions and 72 deletions

View File

@ -24,6 +24,7 @@
#include "Globals.h" #include "Globals.h"
const uint16_t MAX_NBYTES_SIZE = 255U;
CI2CPort::CI2CPort(uint8_t n) : CI2CPort::CI2CPort(uint8_t n) :
m_port(NULL), m_port(NULL),
@ -97,9 +98,9 @@ bool CI2CPort::init()
// Configure and Initialize the I2C // Configure and Initialize the I2C
I2C_InitTypeDef I2C_InitStructure; I2C_InitTypeDef I2C_InitStructure;
I2C_InitStructure.I2C_Timing = 50000U; //400kHz (Fast Mode) I2C_InitStructure.I2C_Timing = 0x0010061AU; // 400kHz (Fast Mode)
I2C_InitStructure.I2C_AnalogFilter = I2C_AnalogFilter_Enable; I2C_InitStructure.I2C_AnalogFilter = I2C_AnalogFilter_Enable;
I2C_InitStructure.I2C_DigitalFilter = 7U; I2C_InitStructure.I2C_DigitalFilter = 0U; // No digital filter
I2C_InitStructure.I2C_Mode = I2C_Mode_I2C; I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
I2C_InitStructure.I2C_OwnAddress1 = 0x00U; // We are the master. We don't need this I2C_InitStructure.I2C_OwnAddress1 = 0x00U; // We are the master. We don't need this
I2C_InitStructure.I2C_Ack = I2C_Ack_Enable; I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;
@ -121,68 +122,49 @@ uint8_t CI2CPort::write(uint8_t addr, const uint8_t* data, uint16_t length)
if (!m_ok) if (!m_ok)
return 6U; return 6U;
// Generate a start condition. (As soon as the line becomes idle, a Start condition will be generated) // Wait for the I2C transmitter to become free
m_port->CR2 |= I2C_CR2_START; if (waitISRFlagsSet(I2C_ISR_BUSY))
return 6U;
// Set I2C device address if needed // Configure the data transfer
if (addr != m_addr) { uint16_t size;
bool ret = setAddr(addr, I2C_Direction_Transmitter); if (length > MAX_NBYTES_SIZE)
if (!ret) size = MAX_NBYTES_SIZE;
return 7U; else
size = length;
m_addr = addr; configureDataTransfer(size);
}
// Unstretch the clock by just reading ISR (Physically the clock is continued to be strectehed because we have not written anything to the TXDR yet.)
(void)m_port->ISR;
// Start Writing Data // Start Writing Data
while (length--) { while (length > 0U) {
bool ret = write(*data++); // Wait for the TXIS flag to be set
if (!ret) if (waitISRFlagsSet(I2C_ISR_TXIS))
return 7U; return 6U;
// Write the byte to the TXDR
m_port->TXDR = *data++;
length--;
size--;
// Configure the data transfer
if (size == 0U && length > 0U) {
if (length > MAX_NBYTES_SIZE)
size = MAX_NBYTES_SIZE;
else
size = length;
configureDataTransfer(size);
}
} }
// Wait for the data on the shift register to be transmitted completely if (waitISRFlagsSet(I2C_ISR_STOPF))
bool ret = waitISRFlagsSet(I2C_ISR_TC); return 6U;
if (!ret)
return 7U;
// Here TXE=BTF=1. Therefore the clock stretches again. m_port->ISR &= ~I2C_ISR_STOPF;
// Order a stop condition at the end of the current tranmission (or if the clock is being streched, generate stop immediatelly) m_port->CR2 &= (uint32_t)~((uint32_t)(I2C_CR2_SADD | I2C_CR2_HEAD10R | I2C_CR2_NBYTES | I2C_CR2_RELOAD | I2C_CR2_RD_WRN));
m_port->CR2 |= I2C_CR2_STOP;
// Stop condition resets the TXE and BTF automatically.
// Wait to be sure that line is iddle
ret = waitLineIdle();
if (!ret)
return 7U;
return 0U; return 0U;
} }
bool CI2CPort::write(uint8_t c)
{
// Write the byte to the TXDR
m_port->TXDR = c;
// Wait till the content of TXDR is transferred to the shift Register.
return waitISRFlagsSet(I2C_ISR_TXE);
}
bool CI2CPort::setAddr(uint8_t addr, uint8_t dir)
{
// Write address to the TXDR (to the bus)
m_port->TXDR = (addr << 1) | dir;
// Wait till ADDR is set (ADDR is set when the slave sends ACK to the address).
// Clock streches till ADDR is Reset. To reset the hardware i)Read the SR1 ii)Wait till ADDR is Set iii)Read SR2
// Note1:Spec_p602 recommends the waiting operation
return waitISRFlagsSet(I2C_ISR_ADDR);
}
bool CI2CPort::waitISRFlagsSet(uint32_t flags) bool CI2CPort::waitISRFlagsSet(uint32_t flags)
{ {
// Wait till the specified ISR Bits are set // Wait till the specified ISR Bits are set
@ -197,20 +179,19 @@ bool CI2CPort::waitISRFlagsSet(uint32_t flags)
return true; return true;
} }
bool CI2CPort::waitLineIdle() void CI2CPort::configureDataTransfer(uint8_t size)
{ {
// Wait till the Line becomes idle. m_port->CR2 &= ~(I2C_CR2_SADD |
uint32_t timeOut = HSI_VALUE; I2C_CR2_NBYTES |
I2C_CR2_RELOAD |
// Check to see if the Line is busy I2C_CR2_AUTOEND |
// This bit is set automatically when a start condition is broadcast on the line (even from another master) (I2C_CR2_RD_WRN & (uint32_t)(I2C_Generate_Start_Write >> (31U - I2C_CR2_RD_WRN_Pos))) |
// and is reset when stop condition is detected. I2C_CR2_START |
while (m_port->ISR & I2C_ISR_BUSY) { I2C_CR2_STOP);
if (!(timeOut--)) m_port->CR2 |= (uint32_t)(((uint32_t)m_addr & I2C_CR2_SADD) |
return false; (((uint32_t)size << I2C_CR2_NBYTES_Pos) & I2C_CR2_NBYTES) |
} (uint32_t)I2C_CR2_RELOAD |
(uint32_t)I2C_Generate_Start_Write);
return true;
} }
#endif #endif

View File

@ -52,10 +52,8 @@ private:
bool m_ok; bool m_ok;
uint8_t m_addr; uint8_t m_addr;
bool setAddr(uint8_t addr, uint8_t dir);
bool write(uint8_t c);
bool waitISRFlagsSet(uint32_t flags); bool waitISRFlagsSet(uint32_t flags);
bool waitLineIdle(); void configureDataTransfer(uint8_t size);
}; };
#endif #endif

@ -1 +1 @@
Subproject commit 6241f7c05eeb6cf1ecd16ca0274bf310efee853f Subproject commit a06aca356cbfb4db847c66512e0a6ee52e58b116

View File

@ -19,6 +19,6 @@
#if !defined(VERSION_H) #if !defined(VERSION_H)
#define VERSION_H #define VERSION_H
#define VERSION "20210102" #define VERSION "20210228"
#endif #endif