STM8S003F3 I2c master-slave problem

Thread Starter

aamirali

Joined Feb 2, 2012
412
I have two STM8 boards. One is master & other is slave.
What master does is: send 4 bytes to slave & then read 4 bytes from slave.

Problem: Sometimes the cycle work & many times code is stuck. I don't know what exactly is the problem.


Master code:

Code:
#define FAST_I2C_MODE
#ifdef FAST_I2C_MODE
#define I2C_SPEED 300000
#else
#define I2C_SPEED 100000
#endif
/* definition of 10-bit or default 7-bit slave address */
/* #define TEN_BITS_ADDRESS */
#define OWN_ADDRESS    0xa0     
#define SLAVE_ADD_1    0x30                                             
                                                 
/* This define is used in master receiver */
/* Uncomment the line below if you want to use the safe procedure */
#define SAFE_PROCEDURE
#define BUFFERSIZE  4
volatile uint8_t TxBuffer[BUFFERSIZE];
volatile uint8_t RxBuffer[BUFFERSIZE];
volatile uint8_t NumOfBytes;
volatile uint8_t NumByteToRead;
volatile uint8_t slave_add;
volatile uint8_t Rx_Idx;
volatile uint8_t Tx_Idx;
int main(void)
{
    uint8_t test_i2c[4] = {0xaaU , 0x55U , 0xf0U , 0x0fU};
/* init sys clock to internal 16Mhz HSI & peripheral clock divider = 1 */
    set_system_clock();
    I2C_DeInit();
  
/* I2C Initialize */
    I2C_Init(I2C_SPEED, OWN_ADDRESS, I2C_DUTYCYCLE_2, I2C_ACK_CURR, I2C_ADDMODE_7BIT, 16);
    
    enableInterrupts();
    
    i2c_send_receive_4_bytes(SLAVE_ADD_1 , test_i2c);
    
}
void i2c_send_receive_4_bytes(uint8_t temp_slave_add , uint8_t tx_data[])
{
    uint8_t cnt;
  
/* set vars */
    Tx_Idx = 0U;
    Rx_Idx = 0U;
    NumOfBytes = BUFFERSIZE;
    NumByteToRead = BUFFERSIZE;
    
/* fill vars */
    slave_add = temp_slave_add;
    for(cnt = 0U ; cnt < BUFFERSIZE ; cnt++)
    {
        TxBuffer[cnt] = tx_data[cnt];
    }
      
/* Enable Buffer and Event Interrupt*/
    I2C_ITConfig((I2C_IT_TypeDef)(I2C_IT_EVT | I2C_IT_BUF) , ENABLE);      
    
/* Send START condition */
    I2C_GenerateSTART(ENABLE);  
    while(NumOfBytes);
    while(I2C_GetFlagStatus(I2C_FLAG_BUSBUSY));
    
/* Add a delay to be sure that communication is finished */
    Delay(0xffffU);  
    
/*****  reception phase ***/
/*  Wait 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 slave Address for write */
    I2C_Send7bitAddress(slave_add, I2C_DIRECTION_RX);
/* Test on EV6 and clear it */
    while(!I2C_CheckEvent(I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED));  
    
/* While there is data to be read */
    while(NumByteToRead)
    {
#ifdef SAFE_PROCEDURE
        if(3U != NumByteToRead)   /* Receive bytes from first byte until byte N-3 */
        {
            while((RESET == I2C_GetFlagStatus(I2C_FLAG_TRANSFERFINISHED)));        /* Poll on BTF */
        /* Read a byte from the Slave */
            RxBuffer[Rx_Idx] = I2C_ReceiveData();
        /* Point to the next location where the byte read will be saved */
            Rx_Idx++;
        /* Decrement the read bytes counter */
            NumByteToRead--;
        }
        if(3U == NumByteToRead)    /* it remains to read three data: data N-2, data N-1, Data N */
        {
        /* Data N-2 in DR and data N -1 in shift register */
            while((RESET == I2C_GetFlagStatus(I2C_FLAG_TRANSFERFINISHED)));    /* Poll on BTF */
        /* Clear ACK */
            I2C_AcknowledgeConfig(I2C_ACK_NONE);
        /* Disable general interrupts */
            disableInterrupts();
        /* Read Data N-2 */
            RxBuffer[Rx_Idx] = I2C_ReceiveData();
        /* Point to the next location where the byte read will be saved */
            Rx_Idx++;
        /* Program the STOP */
            I2C_GenerateSTOP(ENABLE);
        /* Read DataN-1 */
            RxBuffer[Rx_Idx] = I2C_ReceiveData();
        /* Enable General interrupts */
            enableInterrupts();
        /* Point to the next location where the byte read will be saved */
            Rx_Idx++;
            while((RESET == I2C_GetFlagStatus(I2C_FLAG_RXNOTEMPTY))); /* Poll on RxNE */
        /* Read DataN */
            RxBuffer[Rx_Idx] = I2C_ReceiveData();
        /* Reset the number of bytes to be read by master */
            NumByteToRead = 0U;
        }
#else
        if(1U == NumByteToRead)
        {
        /* Disable Acknowledgement */
            I2C_AcknowledgeConfig(I2C_ACK_NONE);
        /* Send STOP Condition */
            I2C_GenerateSTOP(ENABLE);
        /* Poll on RxNE Flag */
            while((RESET == I2C_GetFlagStatus(I2C_FLAG_RXNOTEMPTY)));
      
        /* Read a byte from the Slave */
            RxBuffer[Rx_Idx] = I2C_ReceiveData();
        /* Point to the next location where the byte read will be saved */
            Rx_Idx++;
        /* Decrement the read bytes counter */
            NumByteToRead--;
        }
        /* Test on EV7 and clear it */
        if(I2C_CheckEvent(I2C_EVENT_MASTER_BYTE_RECEIVED) )
        {
        /* Read a byte from the EEPROM */
            RxBuffer[Rx_Idx] = I2C_ReceiveData();
        /* Point to the next location where the byte read will be saved */
            Rx_Idx++;
        /* Decrement the read bytes counter */
            NumByteToRead--;
        }
#endif /* SAFE_PROCEDURE */
    }  
    
/* Add a delay to be sure that communication is finished */
    Delay(0xffffU);     
}
INTERRUPT_HANDLER(I2C_IRQHandler, 19)
{
    switch(I2C_GetLastEvent())
    {
    /* EV5 */
        case I2C_EVENT_MASTER_MODE_SELECT :
        /* Send slave Address for write */
            I2C_Send7bitAddress(slave_add, I2C_DIRECTION_TX);        
        break;
        
        
    /* EV6 */
        case I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED:
            if(0U != NumOfBytes)
            {
            /* Send the first Data */
                I2C_SendData(TxBuffer[Tx_Idx++]);
            /* Decrement number of bytes */
                NumOfBytes--;
            }
            if(0U == NumOfBytes)
            {
                I2C_ITConfig(I2C_IT_BUF, DISABLE);
            }
        break;     
        
        
    /* EV8 */
        case I2C_EVENT_MASTER_BYTE_TRANSMITTING:
        /* Transmit Data */
            I2C_SendData(TxBuffer[Tx_Idx++]);
        /* Decrement number of bytes */
            NumOfBytes--;
            if(0U == NumOfBytes)
            {
                I2C_ITConfig(I2C_IT_BUF, DISABLE);
            }
        break;
        
    /* EV8_2 */
        case I2C_EVENT_MASTER_BYTE_TRANSMITTED:
        /* Send STOP condition */
            I2C_GenerateSTOP(ENABLE);
            I2C_ITConfig(I2C_IT_EVT, DISABLE);
        break;
      
        default:
        break;      
        
    }
}



Slave code:
Code:
#define FAST_I2C_MODE
#ifdef FAST_I2C_MODE
#define I2C_SPEED 300000
#else
#define I2C_SPEED 100000
#endif
/* definition of 10-bit or default 7-bit slave address */
/* #define TEN_BITS_ADDRESS */
#define OWN_ADDRESS    0xa0     
#define SLAVE_ADD_1    0x30
#define SLAVE_ADD_2    0x31
#define SLAVE_ADD_3    0x32
#define SLAVE_ADD_4    0x33                                               
                                                 
/* This define is used in master receiver */
/* Uncomment the line below if you want to use the safe procedure */
#define SAFE_PROCEDURE
#define BUFFERSIZE  4
volatile uint8_t TxBuffer[BUFFERSIZE];
volatile uint8_t RxBuffer[BUFFERSIZE];
volatile uint8_t Rx_Idx;
volatile uint8_t Tx_Idx;
volatile uint16_t Event;
volatile uint8_t comm_complete;
int main(void)
{
    uint8_t test_i2c[4] = {0xaaU , 0x55U , 0xf0U , 0x0fU};
    uint8_t test_rx[4];
/* init sys clock to internal 16Mhz HSI & peripheral clock divider = 1 */
    set_system_clock();
    I2C_DeInit();
  
/* I2C Initialize */
    I2C_Init(I2C_SPEED, SLAVE_ADD_1, I2C_DUTYCYCLE_2, I2C_ACK_CURR, I2C_ADDMODE_7BIT, MHZ_SYS_FREQ);
/* Enable Error Interrupt*/
    I2C_ITConfig((I2C_IT_TypeDef)(I2C_IT_ERR | I2C_IT_EVT | I2C_IT_BUF), ENABLE);  
    
    enableInterrupts();
    
    i2c_send_receive_4_bytes(test_i2c , test_rx);
    
}
void i2c_send_receive_4_bytes(uint8_t tx_data[] , uint8_t rx_data[])
{
    uint8_t cnt;
  
/* fill vars */
    for(cnt = 0U ; cnt < BUFFERSIZE ; cnt++)
    {
        TxBuffer[cnt] = tx_data[cnt];
    }
    comm_complete = 0U;
    
    
/* wait while comm complete */
    while(0U == comm_complete);
    
/* disable interrupt */
    disableInterrupts();
    comm_complete = 0U;
    
/* fill the rx arr */  
    for(cnt = 0U ; cnt < BUFFERSIZE ; cnt++)
    {
        rx_data[cnt] = RxBuffer[cnt];
    }  
    
/* Enable general interrupts */
    enableInterrupts();  
    
} /* function ends here */
INTERRUPT_HANDLER(I2C_IRQHandler, 19)
{
/* Read SR2 register to get I2C error */
    if(0U != (I2C->SR2))
    {
    /* Clears SR2 register */
        I2C->SR2 = 0U;
    }
  
    Event = I2C_GetLastEvent();
    switch(Event)
    {
    /******* Slave transmitter ******/
    /* check on EV1 */
        case I2C_EVENT_SLAVE_TRANSMITTER_ADDRESS_MATCHED:
            Tx_Idx = 0U;
        break;
      
    /* check on EV3 */
        case I2C_EVENT_SLAVE_BYTE_TRANSMITTING:
        /* Transmit data */
            I2C_SendData(TxBuffer[Tx_Idx++]);
            
            if(BUFFERSIZE == Tx_Idx)
            {
                comm_complete = 1U;
            }
            
        break;
        
        
        
        
    /******* Slave receiver **********/
    /* check on EV1*/
        case I2C_EVENT_SLAVE_RECEIVER_ADDRESS_MATCHED:
            Rx_Idx = 0U;
        break;
      
    /* Check on EV2*/
        case I2C_EVENT_SLAVE_BYTE_RECEIVED:
            RxBuffer[Rx_Idx++] = I2C_ReceiveData();
        break;
        
    /* Check on EV4 */
        case (I2C_EVENT_SLAVE_STOP_DETECTED):
        /* write to CR2 to clear STOPF flag */
            I2C->CR2 |= I2C_CR2_ACK;
        break;
        default:
        break;
        
    }
}
 

ErnieM

Joined Apr 24, 2011
8,377
Problem: Sometimes the cycle work & many times code is stuck. I don't know what exactly is the problem.
We would need a better description then simply saying the code "is stuck." What sticks? The master or slave?

What is the bus condition when stuck? If the "stick"is due to the I2C the bus will show the error: are both SCL and SDA hi low or what? If one or the other is low does it clear if you reset (MCLR) either or both devices?

That much should show you which chip is sticking.

When you know that you can put that chip on an in circuit debugger (such as a PICkit) and code walk to see what is happening when the stick ocures.

(I would suspect the slave is the problem as slave code is the harder side to write.)
 

Thread Starter

aamirali

Joined Feb 2, 2012
412
There is no perfect sequence.
Some everyting works fine.

Sometimes master don't get out of:

Code:
while(I2C_GetFlagStatus(I2C_FLAG_BUSBUSY));
I added this line before sending start condition.



Edit: Anyone have I2c code of slave by bit banging in C.
I have written for master
 
Last edited:
Top