STM32 liest Daten von Digimatic SPC und kommuniziert gleichzeitig über I2C

Ich arbeite an einer Anwendung, die auf STM32 läuft und darauf abzielt, Daten aus dem Digimatic-SPC-Protokoll (Mitutoyo-Gerät) zu lesen und die Daten dann über den I2C-Bus an den Himbeer-Pi zu senden. Der Raspberry Pi ist der Master auf dem I2C-Bus und der STM32 ist der Slave.

STM32 liest zyklisch die Daten aus dem Digimatic-Protokoll. I2C in STM32 arbeitet über einen Interrupt. Wenn also eine Anfrage von Himbeere in STM32 kommt, wird ein Interrupt ausgelöst und sofort bedient. Das Problem ist, dass das Lesen von Daten von der Digimatic unterbrochen wird, sodass schlechte Daten über I2C gesendet werden. Sobald das Programm an die Stelle zurückkehrt, an der es vor der Unterbrechung endete, befindet sich das Lesen bereits in einer anderen Phase und das Lesen der Daten wird mit einem Fehler beendet.

Hat jemand ein ähnliches Problem gelöst?

Hier ist der Code zum Auslesen der Daten

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);
  }
}

Hier ist der I2C-Interrupt-Handler-Code

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();
  }
}

Ich freue mich über jeden Rat

Nun, was ist ein "digimatic spc" und welches Protokoll verwendet es?

Antworten (1)

Dieser Ansatz kann Arbeit sein.

Im IC2-Interrupt;

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;
      }
  }
}

Nach dem Lesen von Daten aus der Digimatic;

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