cancel
Showing results for 
Search instead for 
Did you mean: 

I2C slave action to depend on 1st byte of unspecified-length message

HF
Associate

I2C slave that needs to act differently depending on the first written byte in a write request with unspecified length [1 or 3 bytes]

Hi!

I am trying to emulate MCU master to I2C slave devices using two "black-pill" MCUs  (STM32F411CEU6 @100MHz) and STM32CubeIDE (STM32Cube_FW_F4 V1.28.1).

I have mainly studied the following I2C tutorials (part1 - part6): https://controllerstech.com/stm32-as-i2c-slave-part-1/  

I have managed to get the following scenarios to work as expected(M: Master, S: Slave, the slave operates in interrupt mode):

  1. M perform a simple read from S 
    1. M [Read Request - 2B] -> S[Detects Read Request and answers with 2B or more if M does not stop]
  2. M reads 3 times from Slave with different offsets (S continues to send incremented data with offset until M stops)
    1. M[Write offset 1 -> 2B] -> S[Detects/Determines offset and Transmits data correctly]
    2. M[Write offset 2 -> 2B] -> S[Detects/Determines offset and Transmits data correctly]
    3. M[Write offset 3 -> 2B] -> S[Detects/Determines offset and Transmits data correctly]

However I have run into a dead-end for a solution for my third scenario...

I want to be able emulate register writes and device reads using the following high level protocol(hopefully by using existing APIs):

12C Device Write: W[1B write configuration + 2B data]
12C Device Read: W[1B read configuration] + R[12B data]

The main problem is to obtain the first byte in the potential sequence and act accordingly.

I basically end up with the following pseudo code:

static uint8_t g_hi2c3_rx_bytes = 0;
static uint8_t g_hi2c3_rx_data[3] = {0};
static uint8_t g_hi2c3_read_cfg = 0xFF; /* Invalid */

void HAL_I2C_SlaveRxCpltCallback(I2C_HandleTypeDef *hi2c)
{
   /* We have received a new byte (also serves as the next index) */
   g_hi2c3_rx_bytes++;
   
   /* Is it the configuration byte? */
   if (g_hi2c3_rx_bytes == 1)
   {
       /* Act differently depending on the configuration value (the first written data byte/value) */
       uint8_t w_cfg_data = g_hi2c3_rx_data[0];
       if (w_cfg_data == 0x01 )
       {
           /* Write request (we expect 2 more bytes of data) */
           HAL_I2C_Slave_Seq_Receive_IT(&hi2c3,
                                         &g_hi2c3_rx_data[g_hi2c3_rx_bytes],
                                         1, /* Hard coded for now */
                                         I2C_NEXT_FRAME);   
       } 
       else /* Everything but 0x01 is considered a read request */
       {
           /* Save last written read cfg (to be used later) */
           g_hi2c3_read_cfg = w_cfg_data;
           
           /* Read request - send no more frames (i.e. I should already have sent I2C_LAST_FRAME)*/
           // What to do here?
       }
   }
   else
   {
       /* We will allways send the 'last_frame' here since we are about to receive the 3rd byte */
       HAL_I2C_Slave_Seq_Receive_IT(&hi2c3,
                                    &g_hi2c3_rx_data[g_hi2c3_rx_bytes],
                                    1, /* Hard coded for now */
                                    I2C_LAST_FRAME);
   }
}

void HAL_I2C_AddrCallback(I2C_HandleTypeDef *hi2c, uint8_t TransferDirection, uint16_t AddrMatchCode)
{
    if (TransferDirection == I2C_DIRECTION_TRANSMIT)
    {
       /* Indicate that we have received 0 bytes */
       g_hi2c3_rx_bytes = 0;

       /* Invalidate read configuration */
       g_hi2c3_read_cfg = 0xFF;

       /* How to determine I2C_FIRST_FRAME vs I2C_FIRST_AND_LAST_FRAME? */
       HAL_I2C_Slave_Seq_Receive_IT(&hi2c3,
                                    &g_hi2c3_rx_data[g_hi2c3_rx_bytes],
                                    1,
                                    I2C_FIRST_FRAME /* I2C_FIRST_AND_LAST_FRAME */);     
    }
    else
    {
        /* Do nothing for now */
        // 'g_hi2c3_read_cfg' needs to be known (not 0xFF)
        // switch (g_hi2c3_read_cfg)
        // {
        //    case 0x00:
        //        do_something_read(); break;
        //    case 0x0F:
        //        do_something_else_read(); break;
        //    default:
        //        do_something_default_read(); break;
        // }
    }
}

 

I have tried to read the first 'configuration byte' immediately in 'HAL_I2C_AddrCallback' via interrupt or polling and act according but both options makes the MCU get stuck in some kind of interrupt/pending loop.

Hence I have to ask for some assistance/feedback here, how would you solve the issue at hand?

 

 

 

0 REPLIES 0