본문 바로가기

Firmware/stm32

STM32 SPI ErrorCallback 처리

SPI Slave 동작 중에 가끔  HAL_SPI_ErrorCallback으로 진입하고 SPI는 멈추는 현상이 있다.

 

먼저 개발 스펙은 다음과 같다.

 

Develop Toolchain

Toolchain / IDE: STM32CubeIDE

Firmware Package Name and Version: STM32Cube FW_L1 V1.10.0

 

SPI Settings

Mode: FULL-Duplex Slave

Basic Parameters:

Frame Format

Motorola

Data Size

8 Bits

First Bit

MSB First

 

Clock Parameters:

Frequency

1MHz

Clock Polarity (CPOL)

Low

Clock Phase (CPHA)

2 Edge *

CRC Calculation

Disabled

NSS Signal Type

Input Hardware

 

문제 현상

데이터 수신 중 설정한 데이터 길이 보다 더 들어왔을 경우 ErrorCallback으로 진입한다.

ex)

데이터 수신 5Byte 설정

HAL_SPI_Receive_DMA(&hspi1, COMM_Struct.recvBuff, 5);

5개 이상 들어 왔을 시 문제 발생

 

문제 해결 방안

문제 발생 시 RXNE(Rx not empty) 레지스터와 OVR(Overrun) 레지스터가 set 되고 SPI_ErrorCallback 함수가 호출된다. RXNE FlagSPI->DR 레지스터 값을 읽어주면 자동으로 Clear 된다. 따라서 SPI_ErrorCallback에서 추가로 들어온 데이터에 대해 처리해주고 다시 SPI Receive Enable 해 줌으로써 문제를 해결한다(RXNE가 0으로 될때 까지 읽어주자)

 

 

SPI ERROR CallBack FlowChart

 

처리 코드

void HAL_SPI_ErrorCallback(SPI_HandleTypeDef *hspi)
{
  uint8_t recv_length, before_rxne, current_rxne, checksum;
  unsigned int loop_count;

  static unsigned int callback_num = 0;
  static unsigned int max_count = 5;

  recv_length = 5;
  before_rxne = 3;
  checksum = 0;

  callback_num++;

#ifdef DEBUG_PRINTF
  printf("\r\n");
  printf("SPI Error CallBack \r\n");
  printf("SPI log\r\n");
  printf("SPI_CR2_RXDMAEN Register : 0x%x \r\n",
      (unsigned int) READ_BIT(SPI1->CR2, SPI_CR2_RXDMAEN));
  printf("SPI_CR2_TXDMAEN Register : 0x%x \r\n",
      (unsigned int) READ_BIT(SPI1->CR2, SPI_CR2_TXDMAEN));
  printf("SPI_CR2_TXEIE Register   : 0x%x \r\n", (unsigned int) READ_BIT(SPI1->CR2, SPI_CR2_TXEIE));
  printf("SPI_CR2_RXNEIE Register  : 0x%x \r\n",
      (unsigned int) READ_BIT(SPI1->CR2, SPI_CR2_RXNEIE));
  printf("SPI_CR2_ERRIE Register   : 0x%x \r\n", (unsigned int) READ_BIT(SPI1->CR2, SPI_CR2_ERRIE));
  printf("SPI_SR_BSY Register      : 0x%x \r\n", (unsigned int) READ_BIT(SPI1->SR, SPI_SR_BSY));
  printf("SPI_SR_OVR Register      : 0x%x \r\n", (unsigned int) READ_BIT(SPI1->SR, SPI_SR_OVR));
  printf("SPI SR REG               : 0x%x \r\n", (unsigned int) READ_REG(SPI1->SR));
  printf("SPI CR1 REG              : 0x%x \r\n", (unsigned int) READ_REG(SPI1->CR1));
  printf("SPI CR2 REG              : 0x%x \r\n", (unsigned int) READ_REG(SPI1->CR2));
  printf("hspi1 error code         : 0x%x \r\n", (unsigned int) hspi1.ErrorCode);

  printf("\r\n");
  printf("hspi1 rx \r\n");
  printf("hspi1.Init NSS           : 0x%x\r\n", (unsigned int) (hspi1.Init.NSS));
  printf("hspi1.RxXferSize         : 0x%x\r\n", (unsigned int) (hspi1.RxXferSize));
  printf("hspi1.RxXferCount        : 0x%x\r\n", (unsigned int) (hspi1.RxXferCount));
  printf("hspi1.hdmarx->Init.Mode  : 0x%x\r\n", (unsigned int) (hspi1.hdmarx->Init.Mode));
  printf("hspi1.hdmarx->Lock       : 0x%x\r\n", (unsigned int) (hspi1.hdmarx->Lock));
  printf("hspi1.hdmarx->ErrorCode  : 0x%x\r\n", (unsigned int) (hspi1.hdmarx->ErrorCode));

  printf("\r\n");
  printf("hspi1 tx \r\n");
  printf("hspi1.TxXferSize         : 0x%x\r\n", (unsigned int) (hspi1.TxXferSize));
  printf("hspi1.TxXferCount        : 0x%x\r\n", (unsigned int) (hspi1.TxXferCount));
  printf("hspi1.hdmatx->Init.Mode  : 0x%x\r\n", (unsigned int) (hspi1.hdmatx->Init.Mode));
  printf("hspi1.hdmatx->Lock       : 0x%x\r\n", (unsigned int) (hspi1.hdmatx->Lock));
  printf("hspi1.hdmatx->ErrorCode  : 0x%x\r\n", (unsigned int) hspi1.hdmatx->ErrorCode);
  printf("hspi.state               : 0x%x\r\n", (unsigned int) hspi1.State);
  printf("\r\n\r\n");

#endif


  for (loop_count = 0;; loop_count++)
  {
    current_rxne = READ_BIT(SPI1->SR, SPI_SR_RXNE);
    if (before_rxne != current_rxne && current_rxne != 0)
    {
      COMM_Struct.recvBuff[recv_length] = SPI1->DR;
      recv_length++;
    }
    before_rxne = current_rxne;

    if (current_rxne == 0)
    {
      max_count = max_count < recv_length ? recv_length : max_count;
      break;
    }

  }
  recv_length = recv_length - 5;

  for (int i = 0; i < 5; i++)
  {
    COMM_Struct.recvBuff[i] = COMM_Struct.recvBuff[i + recv_length];
  }

  COMM_Struct.checkSum = COMM_Struct.recvBuff[4];

  COMM_Struct.pMsg = &COMM_Struct.recvBuff[1];

  checksum = get_checksum(COMM_Struct.recvBuff, 4);

  printf("callback number : 0x%x\r\n", callback_num);
  printf("func opCode : 0x%x\r\n", (unsigned int) message.opcode);
  printf("max_count : 0x%x\r\n", (unsigned int) max_count);
  printf("loop_count : 0x%x\r\n", loop_count);

  if (checksum != COMM_Struct.checkSum)
  {
    printf("Check sum error \r\n");
    Comm_response_ack((uint32_t) 0x0, (uint8_t*) NULL, RF_RET_ERR_COM);  // Status pin set Checksum Error
    return;
  }
  else if (COMM_Struct.pMsg != 0)
  {
    message.door = SPI_KEY;
    message.opcode = COMM_Struct.recvBuff[0];
    COMM_Struct.lock = COMM_UNLOCKED;
  }

}

ㅇ코드가 복잡해 보이는데 간단히 SPI를 Enable 시킬려면

 

while(READ_BIT(SPI1->SR, SPI_SR_RXNE)

{

  buf = SPI1->DR;

}

HAL_SPI_Receive_DMA(&hspi1, Buff, 5);

 

이런식으로 해도 괜찮을듯 하다.

 

물론 송수신 메시지 포맷에 따라 완전히 달라진다.