Skip to content

Commit

Permalink
Merge pull request #3488 from LMESTM/dev_stm_i2c_v2_unitary_functions
Browse files Browse the repository at this point in the history
Dev stm i2c v2 unitary functions
  • Loading branch information
sg- committed Jan 9, 2017
2 parents 9af3173 + 4297e3f commit ddcd3ad
Show file tree
Hide file tree
Showing 8 changed files with 141 additions and 61 deletions.
18 changes: 6 additions & 12 deletions features/unsupported/tests/mbed/i2c_master_slave/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
#error [NOT_SUPPORTED] Target has only one I2C instance
#endif

#define ADDR (0xA0)
#define ADDR (0x80)
#define FREQ 100000

// ********************************************************
Expand Down Expand Up @@ -89,11 +89,8 @@ int main()
master.start();
master.write(ADDR);
master.write(sent);
if(slave.receive() != I2CSlave::WriteAddressed)
{
notify_completion(false);
return 1;
}
while(slave.receive() != I2CSlave::WriteAddressed);

slave.read(&received, 1);
if(sent != received)
{
Expand All @@ -105,14 +102,11 @@ int main()
// Second transfer: slave to master
master.start();
master.write(ADDR | 1);
if(slave.receive() != I2CSlave::ReadAddressed)
{
notify_completion(false);
return 1;
}
while(slave.receive() != I2CSlave::ReadAddressed);

slave.write(received);
received = master.read(0);
slave.stop();
master.stop();
notify_completion(received == sent);
}

Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ I2C master(D14, D15); // I2C_SDA, I2C_SCL
defined (TARGET_DISCO_F429ZI) || \
defined (TARGET_NUCLEO_F767ZI) || \
defined (TARGET_NUCLEO_L053R8) || \
defined (TARGET_NUCLEO_L073RZ) || \
defined (TARGET_NUCLEO_L152RE) || \
defined (TARGET_NUCLEO_L476RG)
I2CSlave slave(PB_11, PB_10);
Expand Down
1 change: 1 addition & 0 deletions targets/TARGET_STM/TARGET_STM32F0/common_objects.h
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ struct i2c_s {
IRQn_Type error_i2cIRQ;
uint32_t XferOperation;
volatile uint8_t event;
volatile int pending_start;
#if DEVICE_I2CSLAVE
uint8_t slave;
volatile uint8_t pending_slave_tx_master_rx;
Expand Down
1 change: 1 addition & 0 deletions targets/TARGET_STM/TARGET_STM32F3/common_objects.h
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ struct i2c_s {
IRQn_Type error_i2cIRQ;
uint32_t XferOperation;
volatile uint8_t event;
volatile int pending_start;
#if DEVICE_I2CSLAVE
uint8_t slave;
volatile uint8_t pending_slave_tx_master_rx;
Expand Down
1 change: 1 addition & 0 deletions targets/TARGET_STM/TARGET_STM32F7/common_objects.h
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ struct i2c_s {
IRQn_Type error_i2cIRQ;
uint32_t XferOperation;
volatile uint8_t event;
volatile int pending_start;
#if DEVICE_I2CSLAVE
uint8_t slave;
volatile uint8_t pending_slave_tx_master_rx;
Expand Down
1 change: 1 addition & 0 deletions targets/TARGET_STM/TARGET_STM32L0/common_objects.h
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ struct i2c_s {
IRQn_Type error_i2cIRQ;
uint32_t XferOperation;
volatile uint8_t event;
volatile int pending_start;
#if DEVICE_I2CSLAVE
uint8_t slave;
volatile uint8_t pending_slave_tx_master_rx;
Expand Down
1 change: 1 addition & 0 deletions targets/TARGET_STM/TARGET_STM32L4/common_objects.h
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ struct i2c_s {
IRQn_Type error_i2cIRQ;
uint32_t XferOperation;
volatile uint8_t event;
volatile int pending_start;
#if DEVICE_I2CSLAVE
uint8_t slave;
volatile uint8_t pending_slave_tx_master_rx;
Expand Down
178 changes: 129 additions & 49 deletions targets/TARGET_STM/i2c_api.c
Original file line number Diff line number Diff line change
Expand Up @@ -341,6 +341,9 @@ void i2c_init(i2c_t *obj, PinName sda, PinName scl) {
// I2C Xfer operation init
obj_s->event = 0;
obj_s->XferOperation = I2C_FIRST_AND_LAST_FRAME;
#ifdef I2C_IP_VERSION_V2
obj_s->pending_start = 0;
#endif
}

void i2c_frequency(i2c_t *obj, int hz)
Expand Down Expand Up @@ -440,6 +443,14 @@ i2c_t *get_i2c_obj(I2C_HandleTypeDef *hi2c){
return (obj);
}

void i2c_reset(i2c_t *obj) {
struct i2c_s *obj_s = I2C_S(obj);
/* As recommended in i2c_api.h, mainly send stop */
i2c_stop(obj);
/* then re-init */
i2c_init(obj, obj_s->sda, obj_s->scl);
}

/*
* UNITARY APIS.
* For very basic operations, direct registers access is needed
Expand Down Expand Up @@ -535,7 +546,7 @@ int i2c_byte_write(i2c_t *obj, int data) {
(__HAL_I2C_GET_FLAG(handle, I2C_FLAG_BTF) == RESET) &&
(__HAL_I2C_GET_FLAG(handle, I2C_FLAG_ADDR) == RESET)) {
if ((timeout--) == 0) {
return 0;
return 2;
}
}

Expand All @@ -548,92 +559,161 @@ int i2c_byte_write(i2c_t *obj, int data) {
}
#endif //I2C_IP_VERSION_V1
#ifdef I2C_IP_VERSION_V2

int i2c_start(i2c_t *obj) {
struct i2c_s *obj_s = I2C_S(obj);
I2C_HandleTypeDef *handle = &(obj_s->handle);
I2C_TypeDef *i2c = (I2C_TypeDef *)obj_s->i2c;
int timeout;

// Clear Acknowledge failure flag
__HAL_I2C_CLEAR_FLAG(handle, I2C_FLAG_AF);
/* This I2C IP doesn't */
obj_s->pending_start = 1;
return 0;
}

// Wait the STOP condition has been previously correctly sent
timeout = FLAG_TIMEOUT;
while ((i2c->CR2 & I2C_CR2_STOP) == I2C_CR2_STOP){
if ((timeout--) == 0) {
return 1;
}
int i2c_stop(i2c_t *obj) {
struct i2c_s *obj_s = I2C_S(obj);
I2C_HandleTypeDef *handle = &(obj_s->handle);
int timeout = FLAG_TIMEOUT;
#if DEVICE_I2CSLAVE
if (obj_s->slave) {
/* re-init slave when stop is requested */
i2c_init(obj, obj_s->sda, obj_s->scl);
return 0;
}
#endif
// Disable reload mode
handle->Instance->CR2 &= (uint32_t)~I2C_CR2_RELOAD;
// Generate the STOP condition
handle->Instance->CR2 |= I2C_CR2_STOP;

// Generate the START condition
i2c->CR2 |= I2C_CR2_START;

// Wait the START condition has been correctly sent
timeout = FLAG_TIMEOUT;
while (__HAL_I2C_GET_FLAG(handle, I2C_FLAG_BUSY) == RESET) {
while (!__HAL_I2C_GET_FLAG(handle, I2C_FLAG_STOPF)) {
if ((timeout--) == 0) {
return 1;
return I2C_ERROR_BUS_BUSY;
}
}

return 0;
}
/* Clear STOP Flag */
__HAL_I2C_CLEAR_FLAG(handle, I2C_FLAG_STOPF);

int i2c_stop(i2c_t *obj) {
struct i2c_s *obj_s = I2C_S(obj);
I2C_TypeDef *i2c = (I2C_TypeDef *)obj_s->i2c;
/* Erase slave address, this wiil be used as a marker
* to know when we need to prepare next start */
handle->Instance->CR2 &= ~I2C_CR2_SADD;

// Generate the STOP condition
i2c->CR2 |= I2C_CR2_STOP;
/* In case of mixed usage of the APIs (unitary + SYNC)
* re-inti HAL state */
if (obj_s->XferOperation != I2C_FIRST_AND_LAST_FRAME) {
i2c_init(obj, obj_s->sda, obj_s->scl);
}

return 0;
}

int i2c_byte_read(i2c_t *obj, int last) {
struct i2c_s *obj_s = I2C_S(obj);
I2C_TypeDef *i2c = (I2C_TypeDef *)obj_s->i2c;
I2C_HandleTypeDef *handle = &(obj_s->handle);
int timeout;
int timeout = FLAG_TIMEOUT;
uint32_t tmpreg = handle->Instance->CR2;
char data;
#if DEVICE_I2CSLAVE
if (obj_s->slave) {
return i2c_slave_read(obj, &data, 1);
}
#endif
/* Then send data when there's room in the TX fifo */
if ((tmpreg & I2C_CR2_RELOAD) != 0) {
while (!__HAL_I2C_GET_FLAG(handle, I2C_FLAG_TCR)) {
if ((timeout--) == 0) {
DEBUG_PRINTF("timeout in byte_read\r\n");
return -1;
}
}
}

/* Enable reload mode as we don't know how many bytes will eb sent */
handle->Instance->CR2 |= I2C_CR2_RELOAD;
/* Set transfer size to 1 */
handle->Instance->CR2 |= (I2C_CR2_NBYTES & (1 << 16));
/* Set the prepared configuration */
handle->Instance->CR2 = tmpreg;

// Wait until the byte is received
timeout = FLAG_TIMEOUT;
while (__HAL_I2C_GET_FLAG(handle, I2C_FLAG_RXNE) == RESET) {
while (!__HAL_I2C_GET_FLAG(handle, I2C_FLAG_RXNE)) {
if ((timeout--) == 0) {
return -1;
}
}

return (int)i2c->RXDR;
/* Then Get Byte */
data = handle->Instance->RXDR;

if (last) {
/* Disable Address Acknowledge */
handle->Instance->CR2 |= I2C_CR2_NACK;
}

return data;
}

int i2c_byte_write(i2c_t *obj, int data) {
struct i2c_s *obj_s = I2C_S(obj);
I2C_TypeDef *i2c = (I2C_TypeDef *)obj_s->i2c;
I2C_HandleTypeDef *handle = &(obj_s->handle);
int timeout;

// Wait until the previous byte is transmitted
timeout = FLAG_TIMEOUT;
while (__HAL_I2C_GET_FLAG(handle, I2C_FLAG_TXIS) == RESET) {
if ((timeout--) == 0) {
return 0;
int timeout = FLAG_TIMEOUT;
uint32_t tmpreg = handle->Instance->CR2;
#if DEVICE_I2CSLAVE
if (obj_s->slave) {
return i2c_slave_write(obj, (char *) &data, 1);
}
#endif
if (obj_s->pending_start) {
obj_s->pending_start = 0;
//* First byte after the start is the address */
tmpreg |= (uint32_t)((uint32_t)data & I2C_CR2_SADD);
if (data & 0x01) {
tmpreg |= I2C_CR2_START | I2C_CR2_RD_WRN;
} else {
tmpreg |= I2C_CR2_START;
tmpreg &= ~I2C_CR2_RD_WRN;
}
/* Disable reload first to use it later */
tmpreg &= ~I2C_CR2_RELOAD;
/* Disable Autoend */
tmpreg &= ~I2C_CR2_AUTOEND;
/* Do not set any transfer size for now */
tmpreg |= (I2C_CR2_NBYTES & (1 << 16));
/* Set the prepared configuration */
handle->Instance->CR2 = tmpreg;
} else {
/* Set the prepared configuration */
tmpreg = handle->Instance->CR2;

/* Then send data when there's room in the TX fifo */
if ((tmpreg & I2C_CR2_RELOAD) != 0) {
while (!__HAL_I2C_GET_FLAG(handle, I2C_FLAG_TCR)) {
if ((timeout--) == 0) {
DEBUG_PRINTF("timeout in byte_write\r\n");
return 2;
}
}
}
/* Enable reload mode as we don't know how many bytes will eb sent */
tmpreg |= I2C_CR2_RELOAD;
/* Set transfer size to 1 */
tmpreg |= (I2C_CR2_NBYTES & (1 << 16));
/* Set the prepared configuration */
handle->Instance->CR2 = tmpreg;
/* Prepare next write */
timeout = FLAG_TIMEOUT;
while (!__HAL_I2C_GET_FLAG(handle, I2C_FLAG_TXE)) {
if ((timeout--) == 0) {
return 2;
}
}
/* Write byte */
handle->Instance->TXDR = data;
}

i2c->TXDR = (uint8_t)data;

return 1;
}
#endif //I2C_IP_VERSION_V2

void i2c_reset(i2c_t *obj) {
struct i2c_s *obj_s = I2C_S(obj);
/* As recommended in i2c_api.h, mainly send stop */
i2c_stop(obj);
/* then re-init */
i2c_init(obj, obj_s->sda, obj_s->scl);
}

/*
* SYNC APIS
*/
Expand Down

0 comments on commit ddcd3ad

Please sign in to comment.