STM8S00F3 to read/write I2C device

Thread Starter

Vindhyachal Takniki

Joined Nov 3, 2014
594
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 peripheral
b) i2c_read_one_byte_data() : read from address of NAU7802 and read only one byte
c) i2c_write_data() : write buffer to NAU7802 to register specified

4. 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/W



void 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 */
 

Attachments

Thread Starter

Vindhyachal Takniki

Joined Nov 3, 2014
594
MCU is STM8S003F3

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/W


void 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 */
 

JohnInTX

Joined Jun 26, 2012
4,787
I am not familiar with the STM I2C library that you're using but here are a few things that jumped out looking at the simplified code in #2.
  • In lines 20 and 21 you specify an internal pullup presumably for the I2C bus. What is that value? For 100KHz I2C you need around 2.2K to 4.7K to get the signals right. Add external pullups if necessary.
  • In i2c_read_one_byte_data, line 60 you send another Start condition. If the library has it, you should send RepeatStart instead. rS library routines will reset the bus to 1,1 for the rS without generating a false stoP condition. A Start routine typically assumes the bus is already 1,1 and may generate an error if not.
  • On line 78 you send a stoP before reading anything then later you call I2C_ReceiveData (line 86). That won't work When the slave receives a stoP, it will be silent until the next valid Start/Address sequence.
  • I don't know what you're doing with the interrupts. If you HAVE interrupts and the I2C is not using them, you shouldn't have to disable interrupts that may drive timers etc. I2C is fully static and will wait.
  • I also don't know how the ACK/NAK works in the library but in general you must verify an ACK from the slave for each byte written, including slave addresses. For reads, you also verify ACK for the slave address+READ after the repeat start. Then after each byte read, the master generates an ACK after each byte read if it wants to read more or a NAK then stoP when it has read the last byte. I'm not sure you're doing that correctly in all cases but check it out.

It would help to know what the error you referred to actually was.
Hope that helps.
Have fun!
 
Last edited:
Top