STM32 leyendo datos de digimatic SPC y comunicación a través de I2C al mismo tiempo

Estoy trabajando en una aplicación que se ejecuta en STM32, cuyo objetivo es leer datos del protocolo digimatic spc (dispositivo mitutoyo) y luego enviar los datos a la frambuesa pi a través del bus I2C. El Raspberry pi es el maestro en el bus I2C y el STM32 es el esclavo.

STM32 lee los datos del protocolo digimatic en un ciclo. I2C en STM32 opera sobre una interrupción. Entonces, cuando llega una solicitud de raspberry en STM32, se activa una interrupción y se atiende de inmediato. El problema es que se interrumpe la lectura de datos del digimatic, por lo que se envían datos incorrectos a través de I2C. Tan pronto como el programa vuelve al lugar donde terminó antes de la interrupción, la lectura ya está en otra fase y la lectura de los datos se completa con un error.

¿Alguien ha solucionado un problema similar?

Aquí está el código para leer los datos.

int main(void)
{
  HAL_Init();
  SystemClock_Config();

  MX_GPIO_Init();
  MX_I2C1_Init();
  MX_TIM2_Init();

  HAL_I2C_EnableListen_IT(&hi2c1);

  while (1)
  {
      //reading data
      RQST_LOW();
      HAL_Delay(5);
      RQST_HIGH();
      uint32_t timeout=200;

      time=0;
      TIM2->CNT=0;
      HAL_TIM_Base_Start_IT(&htim2);

      for(uint8_t i = 0; i < 13; i++ )
      {
          uint8_t k=0;
        for (uint8_t j = 0; j < 4; j++)
        {
          while(HAL_GPIO_ReadPin(DG_CLK_GPIO_Port,DG_CLK_Pin) == false && timeout>time)
          {
              time=(uint32_t)TIM2->CNT;
          }
          while( HAL_GPIO_ReadPin(DG_CLK_GPIO_Port,DG_CLK_Pin) == true && timeout>time)
          {
              time=(uint32_t)TIM2->CNT;
          }
          bitWrite(k, j, (HAL_GPIO_ReadPin(DG_DATA_GPIO_Port,DG_DATA_Pin) & 0x1));
        }
        rawdata[i] = k;
      }

      if(!(timeout>time))
      {
          aTxBuffer[0]=' ';
          aTxBuffer[1]=' ';
          aTxBuffer[2]=' ';
          aTxBuffer[3]=' ';
          aTxBuffer[4]=' ';
          aTxBuffer[5]=' ';
          aTxBuffer[6]=' ';
          aTxBuffer[7]=' ';
      }
      else
      {
          HAL_TIM_Base_Stop_IT(&htim2);
          char buf[7];
          for(int lp=0;lp<6;lp++)
          {
            buf[lp]=rawdata[lp+5]+'0';
          }
          uint64_t cur_value_int =atoi(buf);
          char buf_dec[2];
          buf_dec[0] = rawdata[11]+'0';
          decimal = atoi(buf_dec);
          float cur_value = (float)cur_value_int*(float)pow(10,-decimal);
          char buf_sign[2];
          buf_sign[0] = rawdata[4]+'0';
          int32_t temp = atoi(buf_sign);
          if(rawdata[4]==8)
          {
            cur_value = -cur_value;
          }
          char buf_unit[2];
          buf_unit[0] = rawdata[12]+'0';
          temp = atol(buf_unit);
          units = (bool)temp;
          RQST_LOW();
          HAL_Delay(50);
          float nearest = roundf(cur_value * 100) / 100;
          char array[8] = {0};
          sprintf(aTxBuffer, "%.2f", nearest);
      }
      HAL_Delay(300);
  }
}

Aquí está el código del controlador de interrupciones I2C

void HAL_I2C_AddrCallback(I2C_HandleTypeDef *hi2c, uint8_t TransferDirection, uint16_t AddrMatchCode)
{
  UNUSED(AddrMatchCode);

  if(hi2c->Instance==I2C1)
  {
      if(TransferDirection == TRANSFER_DIR_READ)
      {
          if(HAL_I2C_Slave_Seq_Receive_IT(&hi2c1, (uint8_t *)aRxBuffer, RXBUFFERSIZE, I2C_NEXT_FRAME)!=HAL_OK)
          {
              Error_Handler();
          }
      }
      else
      {
          HAL_I2C_Slave_Seq_Transmit_IT(&hi2c1, (uint8_t*)aTxBuffer, 8, I2C_LAST_FRAME);
      }
  }
}

void HAL_I2C_ListenCpltCallback(I2C_HandleTypeDef *hi2c)
{
    HAL_I2C_EnableListen_IT(&hi2c1); // Restart
}

void HAL_I2C_ErrorCallback(I2C_HandleTypeDef *I2cHandle)
{
  if (HAL_I2C_GetError(I2cHandle) != HAL_I2C_ERROR_AF)
  {
      Error_Handler();
  }
}

Estaré feliz por cualquier consejo.

Bueno, ¿qué es un "spc digimatic" y qué protocolo utiliza?

Respuestas (1)

Este enfoque puede ser trabajo.

En la interrupción IC2;

void HAL_I2C_AddrCallback(I2C_HandleTypeDef *hi2c, uint8_t TransferDirection, uint16_t AddrMatchCode)
{
  UNUSED(AddrMatchCode);

  if(hi2c->Instance==I2C1)
  {
      if(TransferDirection == TRANSFER_DIR_READ)
      {
          .
          .
          .
      }
      else
      {
         sendData = 1;
      }
  }
}

Después de leer los datos del digimatic;

// After reading data
if(sendData)
{
  HAL_I2C_Slave_Seq_Transmit_IT(&hi2c1, (uint8_t*)aTxBuffer, 8, I2C_LAST_FRAME);
  sendData = 0;
}