AnsweredAssumed Answered

STM32F407VG I2C slave not getting I2C_EVENT_SLAVE_BYTE_TRANSMITTED event

Question asked by ellis.andrew.001 on Jul 4, 2016
Hi,

I am working on a project where I have got an STM32F407VG set up as an I2C slave. I'm able to receive incoming bytes correctly, and I'm able to send one byte without issue. However I need to be able to send multiple bytes to the mast, but I'm unable to do so.

The I2C interface is initialised with:

void init_i2c_slave()
{
    I2C_InitTypeDef I2C_InitStructure;
    NVIC_InitTypeDef    NVIC_InitStructure;
 
    /* I2C configuration ---------------------------------------------------------*/
    I2C_Config();
 
    /* Initialize I2C peripheral */
    /* I2C Init */
    I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
    I2C_InitStructure.I2C_DutyCycle = I2C_DUTYCYCLE;
    I2C_InitStructure.I2C_OwnAddress1 = SLAVE_ADDRESS;
    I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;
    I2C_InitStructure.I2C_ClockSpeed = I2C_SPEED;
 
    I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
 
    I2C_Init(I2Cx, &I2C_InitStructure);
 
    // I2C1 interrupts
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
    NVIC_InitStructure.NVIC_IRQChannel = I2C1_EV_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
    I2C_ITConfig(I2Cx, I2C_IT_EVT | I2C_IT_BUF | I2C_IT_ERR, ENABLE);
 
    I2C_StretchClockCmd(I2Cx, ENABLE);
    I2C_Cmd(I2Cx, ENABLE);
 
}

And I have the following to handle event interrupts:

//Clear ADDR by reading SR1, then SR2
void I2C_clear_ADDR()
{
    I2C_GetFlagStatus(I2Cx, I2C_FLAG_ADDR);
    ((void)(I2Cx->SR2));
}
 
//Clear STOPF by reading SR1, then writing CR1
void I2C_clear_STOPF()
{
    I2C_GetFlagStatus(I2Cx, I2C_FLAG_STOPF);
    I2C_Cmd(I2Cx, ENABLE);
}
 
void I2C1_BUF_IRQHandler()
{
    buf[0] = I2C_ReceiveData(I2C1);
 
    I2C_ClearITPendingBit(I2Cx, I2C_IT_BUF);
}
 
void I2C1_EV_IRQHandler(void)
{
    char num_msg = 0;
 
    if(I2C_GetITStatus(I2Cx, I2C_IT_AF)) I2C_ClearITPendingBit(I2Cx, I2C_IT_AF);
 
    switch (I2C_GetLastEvent(I2Cx))
    {
        case I2C_EVENT_SLAVE_RECEIVER_ADDRESS_MATCHED:
            I2C_clear_ADDR(I2Cx);
            break;
 
        case I2C_EVENT_SLAVE_BYTE_RECEIVED:
            I2C_Regs[reg_idx++] = I2C_ReceiveData(I2Cx);
            break;
 
        case I2C_EVENT_SLAVE_STOP_DETECTED:
            I2C_clear_STOPF(I2Cx);
 
             
            break;
 
        case I2C_EVENT_SLAVE_TRANSMITTER_ADDRESS_MATCHED: //EV1
            I2C_clear_ADDR(I2C1);
 
            //Decode command
            switch (I2C_Regs[0])
            {
                case 0x03: // read gennum register previously selected
                    I2C_SendData(I2Cx, I2C_Regs[reg_idx++]);                   
                    break;
            }
            break;
 
        case I2C_EVENT_SLAVE_BYTE_TRANSMITTED: //EV3
                        I2C_SendData(I2Cx, I2C_Regs[reg_idx++]);   
            break;
 
        case I2C_EVENT_SLAVE_ACK_FAILURE://End of transmission EV3_2           
            I2C_ClearITPendingBit(I2Cx, I2C_IT_AF);
            break;
 
        default:
            break;
    }
}
 
void I2C1_ER_IRQHandler(void)
{
        //GPIO_SetBits(GPIOD, RED);
        //Can't use nice switch statement, because no fxn available
        if(I2C_GetITStatus(I2Cx,        I2C_IT_SMBALERT)) {
        } else if(I2C_GetITStatus(I2Cx, I2C_IT_TIMEOUT)) {
        } else if(I2C_GetITStatus(I2Cx, I2C_IT_PECERR)) {
        } else if(I2C_GetITStatus(I2Cx, I2C_IT_OVR)) {
            //Overrun
            //CLK stretch disabled and receiving
            //DR has not been read, b4 next byte comes in
            //effect: lose byte
            //should:clear RxNE and transmitter should retransmit
 
            //Underrun
            //CLK stretch disabled and I2C transmitting
            //haven't updated DR since new clock
            //effect: same byte resent
            //should: make sure discarded, and write next
        } else if(I2C_GetITStatus(I2Cx, I2C_IT_AF)) {
            //Detected NACK
            //Transmitter must reset com
                //Slave: lines released
                //Master: Stop or repeated Start must must be generated
                //Master = MSL bit
            //Fixup
            I2C_ClearITPendingBit(I2Cx, I2C_IT_AF);
        } else if(I2C_GetITStatus(I2Cx, I2C_IT_ARLO)) {
            //Arbitration Lost
            //Goes to slave mode, but can't ack slave address in same transfer
            //Can after repeat Start though
        } else if(I2C_GetITStatus(I2Cx, I2C_IT_BERR)) {
            //Bus Error
            //In slave mode: data discarded, lines released, acts like restart
            //In master mode: current transmission continues
        }
}

I have spent a lot of time searching for an answer to this issue, and have studied the reference manual, but I can't see what I've missed in the I2C set up which means that I dodn't get the I2C_EVENT_SLAVE_BYTE_TRANSMITTED. I have watched the trace from master to slave on a logic analyser and can see the the transmitter is generating clocks, but the mcu is not sending anything.

Can someone please give me a hint as to what I've missed

Thank you

Andrew

Outcomes