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 Flag는 SPI->DR 레지스터 값을 읽어주면 자동으로 Clear 된다. 따라서 SPI_ErrorCallback에서 추가로 들어온 데이터에 대해 처리해주고 다시 SPI Receive를 Enable 해 줌으로써 문제를 해결한다(RXNE가 0으로 될때 까지 읽어주자)
처리 코드
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);
이런식으로 해도 괜찮을듯 하다.
물론 송수신 메시지 포맷에 따라 완전히 달라진다.
'Firmware > stm32' 카테고리의 다른 글
NanoPB - Stm32 (0) | 2021.04.04 |
---|---|
STM32 FREERTOS Mail Queue 구현 (0) | 2021.02.11 |
STM32 SPI Slave 동작 시 데이터 송수신 이상 현상 (0) | 2020.10.14 |
STM32 SPI Slave로 Interrupt DMA Transmit/Receive 구현하기 (1) | 2020.07.24 |
STM32 Bootloader 메뉴 FLASH_If_WriteProtectionConfig 문제 (0) | 2020.07.06 |