cancel
Showing results for 
Search instead for 
Did you mean: 

HAL I2C Slave

Chuev.Vladimir
Associate III
Posted on April 24, 2018 at 12:08

I'm trying to make I2C Slave using examples from Cube.

The wizard can write the register, but when reading the HAL_I2C_ListenCpltCallback  is called only once.

Can someone share their working code with me?  I don't understand how this should work.

uint8_t i2cSlavDirection;

uint8_t i2cSlaveTransmitBuffer;

uint8_t i2cSlaveReceiveBuffer[2];

// Never called

void HAL_I2C_ErrorCallback(I2C_HandleTypeDef *i2cHandle) {

    _Error_Handler(__FILE__, __LINE__);

}

// Never called

void HAL_I2C_SlaveTxCpltCallback(I2C_HandleTypeDef *i2cHandle) { }

// Never called

void HAL_I2C_SlaveRxCpltCallback(I2C_HandleTypeDef *i2cHandle) { }

void HAL_I2C_ListenCpltCallback(I2C_HandleTypeDef *i2cHandle) {

    HAL_GPIO_TogglePin(GPIOB, LED_GREEN_Pin);

    switch (i2cSlavDirection) {

        case I2C_DIRECTION_TRANSMIT: { // master write

            // ... reg write ...

        }

        break;

        case I2C_DIRECTION_RECEIVE: { // master read

            // ... get reg value and write to i2cSlaveTransmitBuffer ...

            if(HAL_I2C_Slave_Sequential_Transmit_IT(i2cHandle, (uint8_t*)&i2cSlaveTransmitBuffer, 1, I2C_FIRST_AND_LAST_FRAME) != HAL_OK){

                _Error_Handler(__FILE__, __LINE__);

            }

        }

        break;

    }

    // Restarting

    if(HAL_I2C_EnableListen_IT(i2cHandle) != HAL_OK){

        _Error_Handler(__FILE__, __LINE__);

    }

}

void HAL_I2C_AddrCallback(I2C_HandleTypeDef *i2cHandle, uint8_t transferDirection, uint16_t addrMatchCode) {

    i2cSlave.transferDirection = transferDirection;

    // 2 - master write, 1 - master read

    uint8_t receiveSize = transferDirection == I2C_DIRECTION_TRANSMIT ? 2 : 1;

    if(HAL_I2C_Slave_Sequential_Receive_IT(i2cHandle, (uint8_t*)i2cSlaveReceiveBuffer, receiveSize, I2C_FIRST_FRAME) != HAL_OK){

        _Error_Handler(__FILE__, __LINE__);

    }

}

void StartDefaultTask(void const * argument) {

    if(HAL_I2C_EnableListen_IT(&hi2c1) != HAL_OK) {

        _Error_Handler(__FILE__, __LINE__);

    }

    while (1);

}

#hal #i2c-slave #hal_i2c
5 REPLIES 5
Frank CA
Associate III
Posted on April 24, 2018 at 13:20

Ok, in order for me to try to help please supply the following additional info

- chip or board you are using

- which Cube example are you using

- what are you using as master I2C

- IDE and link you are using

I will try to replicate your setup.

Frank.

Posted on April 25, 2018 at 12:24

 ,

 ,

I use trueSTUDIO and STM32F101C8U

I looked at an example in , F0_V1.8.0\Projects\STM32F072RB-Nucleo\Examples\I2C\I2C_TwoBoards_RestartAdvComIT

I don't understand anything, now my call stack is like this:

♯ RESTART_LISTEN

 ,

♯ MASTER_WIRE

 ,

♯ RESTART_LISTEN

 ,

♯ MASTER_WIRE

 ,

♯ MASTER_READ

Slave code:

void HAL_I2C_AddrCallback(I2C_HandleTypeDef *hi2c, uint8_t transferDirection, uint16_t addrMatchCode) {

 ,

 , ,  ,if(transferDirection == I2C_DIRECTION_TRANSMIT) {

 ,

 ,

 , ,  , , ,  ,// ♯ MASTER_WIRE

 ,

 ,

 , ,  , , ,  ,if(HAL_I2C_Slave_Sequential_Receive_IT(&,hi2c1, (uint8_t *)&,(i2cSlaveReceiveBuffer[receiveIndex++]), 1, I2C_FIRST_FRAME) != HAL_OK) {

 ,

 , ,  , , ,  , , ,  ,Error_Handler(),

 ,

 , ,  , , ,  ,}

 ,

 , ,  ,} else {

 ,

 , ,  , , ,  ,// ♯ MASTER_READ

 ,

 ,

 , ,  , , ,  ,receiveIndex = 0,

 ,

 ,

 , ,  , , ,  ,// ... get reg value and write to i2cSlaveTransmitBuffer ...

 ,

 ,

 , ,  , , ,  ,if(HAL_I2C_Slave_Sequential_Transmit_IT(&,hi2c1, (uint8_t*)&,i2cSlaveTransmitBuffer, 1, I2C_LAST_FRAME) != HAL_OK) {

 ,

 , ,  , , ,  , , ,  ,Error_Handler(),

 ,

 , ,  , , ,  ,}

 ,

 , ,  ,}

 ,

}

 ,

void StartDefaultTask(void const *argument) {

 ,

 , ,  ,receiveIndex = 0,

 , ,  ,while (1) {

 ,

 , ,  , , ,  ,// ♯ RESTART_LISTEN

 ,

 , ,  , , ,  ,if (HAL_I2C_EnableListen_IT(&,hi2c1) != HAL_OK) {

 ,

 , ,  , , ,  , , ,  ,Error_Handler(),

 ,

 , ,  , , ,  ,}

 , ,  , , ,  ,while(HAL_I2C_GetState(&,hi2c1) != HAL_I2C_STATE_READY),

 , ,  , , ,  ,if(receiveIndex == 2) {

 ,

 , ,  , , ,  , , ,  ,receiveIndex = 0,

 ,

 ,

 , ,  , , ,  , , ,  , // ... reg update ...

 ,

 , ,  , , ,  ,}

 ,

 , ,  ,}

 ,

}

Master code:

 , , , uint8_t reg = 3,

 ,

 , ,  ,uint8_t data = 50,

 ,

 , ,  ,uint8_t read,

 ,

 , ,  ,uint8_t slave = 0x20 <,<, 1,

 , ,  ,HAL_I2C_Mem_Write(&,hi2c3, slave, reg, 1, &,data, 1, 100),

 ,

 , ,  ,HAL_Delay(50),

 , ,  ,HAL_I2C_Mem_Read(&,hi2c3, slave, reg, 1, &,read, 1, 100),

 ,

 , ,  ,HAL_Delay(50),
Posted on April 27, 2018 at 23:37

To let you know, I built the example project on 2 boards (not Nucleo - my own hardware) and it works fine. 

Its not clear why your call stack looks the way it does. Just a shot in the dark - in your slave code did you enable address listen mode using HAL_I2C_EnableListen_IT() ? You dont show it in your code. EDIT: correction, it is there.

May be worth getting a logic analyzer hooked onto the bus. Below a trace of some of the master -> slave transmit data from the example.

0690X00000604cYQAQ.jpg
Frank CA
Associate III
Posted on April 28, 2018 at 21:55

Look also at

https://github.com/cnoviello/mastering-stm32/blob/master/nucleo-f103RB/src/ch14/main-ex2.c

, it is in line with what you are trying to do.

In line 88, data is passed to the master.

But what if the master will write? How to find out in advance will be written or read the second byte?