1
\$\begingroup\$

I have a master board with STM32F030R8 and two daughter boards with STM32F030C6. The objective is to communicate parameters between the boards periodically and also on-demand. With some effort I configured I2C in normal mode and both boards and got the communication to work. But then I merged the I2C part with my main code and things started misbehaving. It seemed as if I needed to synchronize the HAL_I2C_MasterTransmit and HAL_I2C_SlaveRecieve. The communication works once when I reset the boards together, otherwise it fails. Then I implemented a timer which resets the I2C peripheral after a few seconds if communication has failed. Which worked somewhat and I was receiving data from slave almost constantly without fail. But then I had to connect the second daughter board and now it takes about 15 seconds to properly transmit data once.

I am really dispirited by the amount of work that had to be done and even then with no stable results. I thought the peripheral would manage the synchronization and bus allocation and so on, but now I feel like have to do it all manually in the code. So, the question is, what is a robust way to implement this system so that I can get updates on the master instantaneously?

Notes:

  • I'm using the TXCplt and RXCplt callbacks to see if communication was successful or not before attempting the next board.

  • I do it piece by piece. First I send a transfer request to slave, then the slave has to acknowledge the transfer before it sends the data.

Also: How to properly restart I2C communication? Currently I'm using __HAL_I2C_Disable and then calling MX_I2C_Init to reinit communications.

What could be an optimum time delay for restart? Code for reference:

void I2C_Timer() {
if(i2cFlag) i2cTimer++; 
else i2cTimer = 0;
if(i2cTimer > 3) {
    // Reset I2C
    __HAL_I2C_DISABLE(&hi2c1);
    MX_I2C1_Init();
    bTransferRequest = prevTransferRequest;
    i2cTimer = 0;
    i2cFlag = 0;
    comComplete = 0;

    switch(bTransferRequest) {
        case MASTER_REQ_READ:
            if(comCount < 2) {
                /* If comm fails to complete, restart com to the same board */
                switch(comIndex) {
                    case 0: case 1: comIndex = 0; break; // Chiller
                    case 2: case 3: comIndex = 2; break; // Discharge
                }
            }
            else {
                /* Switching to the next board if prev board comm fails for more than 2 tries */
                switch(comIndex) {
                    case 0: case 1: comIndex = 2; break; // Chiller
                    case 2: case 3: comIndex = 0; break; // Discharge
                }
                comComplete = 1;
                comCount = 0;
            }
        break;
        case MASTER_REQ_WRITE:

        // case MASTER_REQ_MASSWRITE:
    }
    if(comCount == 4) {

    }
    comCount++;
}

}

void I2C_Routine(void) {
        if(i2cFlag == 0) {
            switch(bTransferRequest) {
                if(HAL_I2C_GetState(&hi2c1) == HAL_I2C_STATE_READY) {
                case MASTER_REQ_READ:
                    switch(comIndex) {
                        case 0: 
                            i2cTimerFlag = 1;
                            if(HAL_I2C_Master_Transmit_DMA(&hi2c1, (uint16_t)I2C_ADD_CHILLER, &bTransferRequest, 1)!= HAL_OK) {
                                /* Error_Handler() function is called when error occurs. */
                                Error_Handler();                
                            } 
                            i2cFlag = 1;
                            comComplete=0;
                            break;
                        case 1:
                            // memset(aRxBuffer, 0, RECEIVE_BYTES);
                            if(HAL_I2C_Master_Receive_DMA(&hi2c1, (uint16_t)I2C_ADD_CHILLER, (uint8_t *)aChillrRxBuffer, CHILLR_RECEIVE_BYTES)!= HAL_OK) {
                                /* Error_Handler() function is called when error occurs. */
                                Error_Handler();                
                            }
                            i2cFlag = 1;
                            comComplete = 1;
                            break;
                        case 2: 
                            if(HAL_I2C_Master_Transmit_DMA(&hi2c1, (uint16_t)I2C_ADD_DISCHARGE, &bTransferRequest, 1)!= HAL_OK) {
                                /* Error_Handler() function is called when error occurs. */
                                Error_Handler();                
                            } 
                            i2cFlag = 1;
                            comComplete = 0;
                            break;
                        case 3: 
                            if(HAL_I2C_Master_Receive_DMA(&hi2c1, (uint16_t)I2C_ADD_DISCHARGE, (uint8_t *)aDischRxBuffer, DISCH_RECEIVE_BYTES)!= HAL_OK) {
                                /* Error_Handler() function is called when error occurs. */
                                Error_Handler();                
                            }
                            i2cFlag = 1;
                            comComplete = 1;
                            break;
                    }
                    prevTransferRequest = MASTER_REQ_READ;
                    bTransferRequest = MASTER_REQ_READ;
                    break;
                case MASTER_REQ_WRITE:
                    if(i2cWriteParamFlag == SET) {
                        switch(comIndex) {
                            case 0: 
                                comComplete=0;
                                if(HAL_I2C_Master_Transmit_DMA(&hi2c1, (uint16_t)I2C_Address, &bTransferRequest, 1)!= HAL_OK) {
                                    /* Error_Handler() function is called when error occurs. */
                                    Error_Handler();                
                                } 
                                i2cFlag = 1;
                                break;
                            case 1:
                                if(HAL_I2C_Master_Receive_DMA(&hi2c1, (uint16_t)I2C_Address, &bTransferAck, 1)!= HAL_OK) {
                                    /* Error_Handler() function is called when error occurs. */
                                    Error_Handler();                
                                } 
                                i2cFlag = 1;
                                break;
                            case 2:
                                if(bTransferAck == MASTER_REQ_WRITE) {
                                    while(HAL_I2C_GetState(&hi2c1) == HAL_I2C_STATE_BUSY);
                                    HAL_Delay(20);
                                    if(HAL_I2C_Master_Transmit_DMA(&hi2c1, (uint16_t)I2C_Address, (uint8_t *)aTxBuffer, 3)!= HAL_OK) {
                                        /* Error_Handler() function is called when error occurs. */
                                        Error_Handler();                
                                    }
                                    i2cFlag = 1;
                                    i2cWriteParamFlag = RESET;
                                    comComplete=1;
                                }
                            }
                    }
                prevTransferRequest = MASTER_REQ_WRITE;
                bTransferRequest = MASTER_REQ_READ;
                break;
                case MASTER_REQ_MASSWRITE:
                    switch(comIndex) {
                        case 0: 
                            if(HAL_I2C_Master_Transmit_DMA(&hi2c1, (uint16_t)I2C_ADD_CHILLER, &bTransferRequest, 1)!= HAL_OK) {
                                /* Error_Handler() function is called when error occurs. */
                                Error_Handler();                
                            } 
                            i2cFlag = 1;
                            break;
                        case 1:
                            if(HAL_I2C_Master_Transmit_DMA(&hi2c1, (uint16_t)I2C_ADD_CHILLER, (uint8_t *)aMassTxBuffer, CHILLER_TRANSMIT_BYTES)!= HAL_OK) {
                                /* Error_Handler() function is called when error occurs. */
                                Error_Handler();                
                            }
                            i2cFlag = 1;
                            break;
                        case 2: 
                            if(HAL_I2C_Master_Transmit_DMA(&hi2c1, (uint16_t)I2C_ADD_DISCHARGE, &bTransferRequest, 1)!= HAL_OK) {
                                /* Error_Handler() function is called when error occurs. */
                                Error_Handler();                
                            } 
                            i2cFlag = 1;
                            break;
                        case 3:
                            if(HAL_I2C_Master_Transmit_DMA(&hi2c1, (uint16_t)I2C_ADD_DISCHARGE, (uint8_t *)aMassTxBuffer, DISCHARGE_TRANSMIT_BYTES)!= HAL_OK) {
                                /* Error_Handler() function is called when error occurs. */
                                Error_Handler();                
                            }
                            i2cFlag = 1;
                            break;
                    }
                    prevTransferRequest = MASTER_REQ_MASSWRITE;
                    bTransferRequest = MASTER_REQ_READ;
                    break;
                }
            }
        }
}

void I2C_Read() {
    bTransferRequest = MASTER_REQ_READ;
    comIndex = 0;
}


void I2C_Write(uint8_t Id) { 
    bTransferRequest = MASTER_REQ_WRITE;
    // Id is chiller parameter
    I2C_Address = I2C_ADD_CHILLER;
    aTxBuffer[0] = Id - ChillerStartAddr - 0x98;
// Id is discharge parameter
//  I2C_Address = I2C_ADD_DISCHARGE;
//  aTxBuffer[0] = Id - DichargeStartAddr;

//  Discharge and chiller parameter ranges
    EEPROM_Unlock();
    int16_t Val =  EEPROM_ReadParam(Id);
    EEPROM_Lock();
    aTxBuffer[1] = (Val & 0xFF00) >> 8;
    aTxBuffer[2] = (Val & 0x00FF);
    i2cWriteParamFlag = SET;
    comIndex = 0;
    i2cFlag = 0;
}

void I2C_MassWrite() {
    bTransferRequest = MASTER_REQ_MASSWRITE;
    comIndex = 0;
    // Fill aMassRxBuffer_Chiller
    // Fill aMassRxBuffer_Discharge
}

void HAL_I2C_MasterTxCpltCallback(I2C_HandleTypeDef *I2cHandle) {
    switch(bTransferRequest) {
        case MASTER_REQ_READ: 
            switch(comIndex) {
                case 0: comIndex = 1; break;
                case 2: comIndex = 3; comComplete = 1; break;
            }
        break;
        case MASTER_REQ_WRITE:
            switch(comIndex) {
                case 0: comIndex = 1; comComplete = 1; break;
                case 2: comIndex = 0; comComplete = 1; break;
            }
        break;
    }
    // i2cTimer = 0;
    i2cFlag=0;
}

void HAL_I2C_MasterRxCpltCallback(I2C_HandleTypeDef *I2cHandle) {
    switch(bTransferRequest) {
        case MASTER_REQ_READ: 
            switch(comIndex) {
                case 1: 
                    for(uint8_t i = 0, j = 0; i < (i2cChillerParamCount*2) ; i+=2, j++) {
                        uint8_t ValHigh = aChillrRxBuffer[i];
                        uint8_t ValLow = aChillrRxBuffer[i + 1];
                        uint16_t Val = (ValHigh << 8) | ValLow;
                        PARAM_SetVal(i2CChillerArray[j], Val*(0.1));
                    }
                    comIndex = 2; break; // To read Discharge board
                case 3:
                    for(uint8_t i = 0, j = 0; i < (i2cDichargeParamCount*2) ; i+=2, j++) {
                        uint8_t ValHigh = aDischRxBuffer[i];
                        uint8_t ValLow = aDischRxBuffer[i + 1];
                        uint16_t Val = (ValHigh << 8) | ValLow;
                        PARAM_SetVal(i2CDischrArray[j], Val*(0.1));
                    }
                    comIndex = 0; break; // To read Chiller board
            }
            break;
        case MASTER_REQ_WRITE:
            switch(comIndex) {
                case 1: comIndex = 2; break;
            }
            break;
    }
    // i2cTimer = 0;
    i2cFlag = 0;
}
\$\endgroup\$
  • \$\begingroup\$ This is not directly an answer to your question, but I would strongly recommend using an oscilloscope and understanding how the I2C protocol works on the wire. Otherwise it can be very hard to get a good grasp of how the code you're writing relates to what the devices are actually sending and receiving, especially since different I2C libraries use inconsistent terminology. \$\endgroup\$ – Glenn Willen May 25 at 4:50
  • \$\begingroup\$ The posted code does not compile! When asking a question about a run time problem, as this question is doing, please post a [mcve] so we can reproduce the problem and help you debug it. \$\endgroup\$ – user3629249 May 26 at 16:59
  • \$\begingroup\$ for a thorough understanding of the I2C protocol especially the section: 2.1GeneralI2C Operation \$\endgroup\$ – user3629249 May 26 at 17:21

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.