STM8S00F3 to read/write I2C device - Page 1
Forum section: electronics / beginners

author: Vindhyachal.takniki
author_rank: Frequent Contributor
timestamp: June 11, 2020, 11:49:51 am
content: 1. I have to read/write NAU7802 register, datasheet of which is attched.2. STM8S is running at 16Mhz.3. Write three functions:a) i2c_init() : init the i2c peripheralb) i2c_read_one_byte_data() : read from address of NAU7802 and read only one bytec) i2c_write_data() : write buffer to NAU7802 to register specified4. I am trying to read the registers of NAU7802 which return constant values, by i always gets error. What could be wrong in code?Code:#define I2C_TIMEOUT 10000 //this is not exact timing, just a counter#define I2C_SPEED 100000#define I2C_SLAVE_ADDRESS7 0x2A //this is random not to be used actually, STM8S used in master mode#define NAU7802_ADD 0x54 //this is address of NAU7802, 8 bit address, last bit will be R/Wvoid i2c_init(void){/* I2C Peripheral Disable */I2C_Cmd(DISABLE);/* I2C DeInit */I2C_DeInit();/* I2C Peripheral clock disable */CLK_PeripheralClockConfig(CLK_PERIPHERAL_I2C , DISABLE);/* GPIO INIT */GPIO_Init(GPIOB , GPIO_PIN_4 , GPIO_MODE_IN_PU_NO_IT);GPIO_Init(GPIOB , GPIO_PIN_5 , GPIO_MODE_IN_PU_NO_IT);/* enable clock */CLK_PeripheralClockConfig(CLK_PERIPHERAL_I2C , ENABLE);/* I2C configuration */I2C_Cmd( ENABLE);/* sEE_I2C configuration after enabling it */I2C_Init(I2C_SPEED, I2C_SLAVE_ADDRESS7, I2C_DUTYCYCLE_2, I2C_ACK_CURR,I2C_ADDMODE_7BIT, 16);}uint8_t i2c_read_one_byte_data(uint8_t *p_buffer , uint8_t read_addr){uint16_t timeout;uint8_t err = 0U;uint8_t break_loop;/* While the bus is busy */timeout = I2C_TIMEOUT;break_loop = 0U;while( (I2C_GetFlagStatus(I2C_FLAG_BUSBUSY)) && (0U == break_loop) ){timeout--;if(!timeout){break_loop = 1U;err = 1U;}}if(0U == err){/* Send START condition */I2C_GenerateSTART( ENABLE);timeout = I2C_TIMEOUT;break_loop = 0U;/* Test on EV5 and clear it */while( (!I2C_CheckEvent(I2C_EVENT_MASTER_MODE_SELECT)) && (0U == break_loop) ){timeout--;if(!timeout){break_loop = 1U;err = 2U;}}}if(0U == err){/* Send NAU7802 address for write */I2C_Send7bitAddress(NAU7802_ADD , I2C_DIRECTION_TX);timeout = I2C_TIMEOUT;break_loop = 0U;/* Test on EV6 and clear it */while( (!I2C_CheckEvent(I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)) && (0U == break_loop) ){timeout--;if(!timeout){break_loop = 1U;err = 3U;}}}if(0U == err){/* Send reg address for write */I2C_SendData( read_addr );timeout = I2C_TIMEOUT;break_loop = 0U;/* Test on EV8 and clear it */while( (I2C_GetFlagStatus(I2C_FLAG_TRANSFERFINISHED) == RESET) && (0U == break_loop) ){timeout--;if(!timeout){break_loop = 1U;err = 4U;}}}if(0U == err){/* Send START condition a second time */I2C_GenerateSTART( ENABLE);timeout = I2C_TIMEOUT;break_loop = 0U;/* Test on EV5 and clear it (cleared by reading SR1 then writing to DR) */while( (!I2C_CheckEvent(I2C_EVENT_MASTER_MODE_SELECT)) && (0U == break_loop) ){timeout--;if(!timeout){break_loop = 1U;err = 5U;}}}if(0U == err){/* Send register address for read */I2C_Send7bitAddress(NAU7802_ADD, I2C_DIRECTION_RX);timeout = I2C_TIMEOUT;break_loop = 0U;/* Wait on ADDR flag to be set (ADDR is still not cleared at this level */while( (I2C_GetFlagStatus( I2C_FLAG_ADDRESSSENTMATCHED) == RESET) && (0U == break_loop) ){timeout--;if(!timeout){break_loop = 1U;err = 6U;}}}if(0U == err){/* Disable Acknowledgement */I2C_AcknowledgeConfig(I2C_ACK_NONE);/* Call User callback for critical section start (should typically disable interrupts) */disableInterrupts();/* Clear ADDR register by reading SR1 then SR3 register (SR1 has already been read) */(void)I2C->SR3;/* Send STOP Condition */I2C_GenerateSTOP( ENABLE);/* Call User callback for critical section end (should typically re-enable interrupts) */enableInterrupts();/* Wait on ADDR flag to be set (ADDR is still not cleared at this level */timeout = I2C_TIMEOUT;break_loop = 0U;while( (I2C_GetFlagStatus( I2C_FLAG_RXNOTEMPTY) == RESET) && (0U == break_loop) ){timeout--;if(!timeout){break_loop = 1U;err = 7U;}}}if(0U == err){/* Read the byte received from the EEPROM */*p_buffer = I2C_ReceiveData();/* Wait on ADDR flag to be set (ADDR is still not cleared at this level */timeout = I2C_TIMEOUT;break_loop = 0U;while( (I2C->CR2 & I2C_CR2_STOP) && (0U == break_loop) ){timeout--;if(!timeout){break_loop = 1U;err = 8U;}}}if(0U == err){/* Re-Enable Acknowledgement to be ready for another reception */I2C_AcknowledgeConfig( I2C_ACK_CURR);}/* if some error make sure to send stop */if(0U != err){/* Send STOP Condition */I2C_GenerateSTOP( ENABLE);}/* Perform a read on SR1 and SR3 register to clear eventually pending flags */(void)I2C->SR1;(void)I2C->SR3;return err;}uint8_t i2c_write_data(uint8_t *p_buffer , uint8_t write_addr , uint8_t num_byte_to_write){uint16_t timeout;uint8_t err = 0U;uint8_t break_loop;/* While the bus is busy */timeout = I2C_TIMEOUT;break_loop = 0U;while( (I2C_GetFlagStatus(I2C_FLAG_BUSBUSY)) && (0U == break_loop) ){timeout--;if(!timeout){break_loop = 1U;err = 1U;}}if(0U == err){/* Send START condition */I2C_GenerateSTART( ENABLE);timeout = I2C_TIMEOUT;break_loop = 0U;/* Test on EV5 and clear it */while( (!I2C_CheckEvent(I2C_EVENT_MASTER_MODE_SELECT)) && (0U == break_loop) ){timeout--;if(!timeout){break_loop = 1U;err = 2U;}}}if(0U == err){/* Send NAU7802 address for write */I2C_Send7bitAddress(NAU7802_ADD , I2C_DIRECTION_TX);timeout = I2C_TIMEOUT;break_loop = 0U;/* Test on EV6 and clear it */while( (!I2C_CheckEvent(I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)) && (0U == break_loop) ){timeout--;if(!timeout){break_loop = 1U;err = 3U;}}}if(0U == err){/* Send reg address for write */I2C_SendData( write_addr );timeout = I2C_TIMEOUT;break_loop = 0U;/* Test on EV8 and clear it */while( (!I2C_CheckEvent(I2C_EVENT_MASTER_BYTE_TRANSMITTED)) && (0U == break_loop) ){timeout--;if(!timeout){break_loop = 1U;err = 4U;}}}if(0U == err){while(num_byte_to_write){/* Send data */I2C_SendData( *p_buffer );timeout = I2C_TIMEOUT;break_loop = 0U;/* Test on EV8 and clear it *//* Wait till all data have been physically transferred on the bus */while( (!I2C_GetFlagStatus(I2C_FLAG_TRANSFERFINISHED)) && (0U == break_loop) ){timeout--;if(!timeout){break_loop = 1U;err++;}}num_byte_to_write--;p_buffer++;}}/* Send STOP condition */I2C_GenerateSTOP(ENABLE);/* Perform a read on SR1 and SR3 register to clear eventually pending flags */(void)I2C->SR1;(void)I2C->SR3;return err;} /* function ends here */

author: garethw
author_rank: Regular Contributor
timestamp: June 11, 2020, 01:08:18 pm
content: I've not used STM8 before but I have, and am currently working with, STM32. When passing the I2C peripheral address I have to leave it in 7-bit format. In your case you would send 0x2A, not 0x54, as the address and the hardware shifts it over for you.Again, I don't know if this applies to the STM8 or not but it is easy enough to try.

author: Vindhyachal.takniki
author_rank: Frequent Contributor
timestamp: June 11, 2020, 02:01:42 pm
content: MCU is STM8S003F3Edit: Here is code, with error handling removed, for better understanding:Code:#define I2C_TIMEOUT 10000 //this is not exact timing, just a counter#define I2C_SPEED 100000#define I2C_SLAVE_ADDRESS7 0x54 //this is random not to be used actually, STM8S used in master mode#define NAU7802_ADD 0x54 //this is address of NAU7802, 8 bit address, last bit will be R/Wvoid i2c_init(void){/* I2C Peripheral Disable */I2C_Cmd(DISABLE);/* I2C DeInit */I2C_DeInit();/* I2C Peripheral clock disable */CLK_PeripheralClockConfig(CLK_PERIPHERAL_I2C , DISABLE);/* GPIO INIT */GPIO_Init(GPIOB , GPIO_PIN_4 , GPIO_MODE_IN_PU_NO_IT);GPIO_Init(GPIOB , GPIO_PIN_5 , GPIO_MODE_IN_PU_NO_IT);/* enable clock */CLK_PeripheralClockConfig(CLK_PERIPHERAL_I2C , ENABLE);/* I2C configuration */I2C_Cmd( ENABLE);/* sEE_I2C configuration after enabling it */I2C_Init(I2C_SPEED, I2C_SLAVE_ADDRESS7, I2C_DUTYCYCLE_2, I2C_ACK_CURR,I2C_ADDMODE_7BIT, 16);}uint8_t i2c_read_one_byte_data(uint8_t *p_buffer , uint8_t read_addr){/* While the bus is busy */while( I2C_GetFlagStatus(I2C_FLAG_BUSBUSY) );/* Send START condition */I2C_GenerateSTART( ENABLE);/* Test on EV5 and clear it */while(!I2C_CheckEvent(I2C_EVENT_MASTER_MODE_SELECT);/* Send NAU7802 address for write */I2C_Send7bitAddress(NAU7802_ADD , I2C_DIRECTION_TX);/* Test on EV6 and clear it */while( !I2C_CheckEvent(I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED) )/* Send reg address for write */I2C_SendData( read_addr );/* Test on EV8 and clear it */while(I2C_GetFlagStatus(I2C_FLAG_TRANSFERFINISHED) == RESET);/* Send START condition a second time */I2C_GenerateSTART( ENABLE);/* Test on EV5 and clear it (cleared by reading SR1 then writing to DR) */while(!I2C_CheckEvent(I2C_EVENT_MASTER_MODE_SELECT));/* Send register address for read */I2C_Send7bitAddress(NAU7802_ADD, I2C_DIRECTION_RX);/* Wait on ADDR flag to be set (ADDR is still not cleared at this level */while(I2C_GetFlagStatus( I2C_FLAG_ADDRESSSENTMATCHED) == RESET);/* Disable Acknowledgement */I2C_AcknowledgeConfig(I2C_ACK_NONE);/* should typically disable interrupts) */disableInterrupts();/* Clear ADDR register by reading SR1 then SR3 register (SR1 has already been read) */(void)I2C->SR3;/* Send STOP Condition */I2C_GenerateSTOP( ENABLE);/* should typically re-enable interrupts) */enableInterrupts();/* Wait on ADDR flag to be set (ADDR is still not cleared at this level */while(I2C_GetFlagStatus( I2C_FLAG_RXNOTEMPTY) == RESET);/* Read the byte received from the EEPROM */*p_buffer = I2C_ReceiveData();while( (I2C->CR2 & I2C_CR2_STOP) );/* Re-Enable Acknowledgement to be ready for another reception */I2C_AcknowledgeConfig( I2C_ACK_CURR);/* if some error make sure to send stop */if(0U != err){/* Send STOP Condition */I2C_GenerateSTOP( ENABLE);}/* Perform a read on SR1 and SR3 register to clear eventually pending flags */(void)I2C->SR1;(void)I2C->SR3;return err;}uint8_t i2c_write_data(uint8_t *p_buffer , uint8_t write_addr , uint8_t num_byte_to_write){/* While the bus is busy */while( (I2C_GetFlagStatus(I2C_FLAG_BUSBUSY));/* Send START condition */I2C_GenerateSTART( ENABLE);while(!I2C_CheckEvent(I2C_EVENT_MASTER_MODE_SELECT));/* Send NAU7802 address for write */I2C_Send7bitAddress(NAU7802_ADD , I2C_DIRECTION_TX);while(!I2C_CheckEvent(I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));/* Send reg address for write */I2C_SendData( write_addr );/* Test on EV8 and clear it */while( (!I2C_CheckEvent(I2C_EVENT_MASTER_BYTE_TRANSMITTED));while(num_byte_to_write){/* Send data */I2C_SendData( *p_buffer );/* Wait till all data have been physically transferred on the bus */while( (!I2C_GetFlagStatus(I2C_FLAG_TRANSFERFINISHED));num_byte_to_write--;p_buffer++;}/* Send STOP condition */I2C_GenerateSTOP(ENABLE);/* Perform a read on SR1 and SR3 register to clear eventually pending flags */(void)I2C->SR1;(void)I2C->SR3;return err;} /* function ends here */

author: Vindhyachal.takniki
author_rank: Frequent Contributor
timestamp: June 12, 2020, 02:41:28 pm
content: moveup..

author: garethw
author_rank: Regular Contributor
timestamp: June 13, 2020, 05:54:24 am
content: I've had a look through the stm8s_i2c.c source file and it looks like its your responsibility to shift the address. 0x54 is correct in your case.Code:00434 * @brief Transmits the 7-bit address (to select the) slave device.00435 * @param Address : Specifies the slave address which will be transmitted.00436 * @param Direction : Specifies whether the I2C device will be a Transmitter or a Receiver.00437 * This parameter can be any of the @ref I2C_Direction_TypeDef enumeration.00438 * @retval None00439 */00440 void I2C_Send7bitAddress(uint8_t Address, I2C_Direction_TypeDef Direction)00441 {00442 /* Check function parameters */00443 assert_param(IS_I2C_ADDRESS_OK(Address));00444 assert_param(IS_I2C_DIRECTION_OK(Direction));0044500446 /* Clear bit0 (direction) just in case */00447 Address &= (uint8_t)0xFE;0044800449 /* Send the Address + Direction */00450 I2C->DR = (uint8_t)(Address | (uint8_t)Direction);00451 }The only thing I can suggest is to use a logic analyser to see what the bus is doing. If you don't have access to a logic analyser you might be able to capture the SDA and SCL lines with a scope and decode by hand to check the correct address and ack are being sent/received.

author: Kjelt
author_rank: Super Contributor
timestamp: June 14, 2020, 11:33:32 am
content: Not sure if ST has solved the issue on this newer STM8S0 device because I am out of the game now for a few years and lost the updates but in the past there were major issues with the I2C peripheral on the STM8S20x series. So bad that I went back to bitbanging in some cases.Here is some more info: if you see that the bus is stuck than you can take this into account of the cause, and before shipping to any customer do a continuous read test of at least 10000 consecutive reads.https://www.eevblog.com/forum/testgear/i2c-vs-spi/msg301237/#msg301237