2024-11-20 03:42 PM - edited 2024-11-20 03:43 PM
I am using a Nucleo-H743ZI as a SPI slave device for the following coms method:
Master Pulls SS low, Delay 1ms.
Master Transmit/Receive 1 Byte (Wait for high busy line)
Slave RXP Interrupt-> Lower Busy Line
Slave Transmit/Receive 1 Byte
Slave Process Byte, Set next transmit byte
Slave Raise Busy Line
Master Transmit/Receive 1 Byte
Repeat untilldata is done
Master Raises SS
The Master is acting properly and the slave receive is correct; however, the slave transmit is two bytes behind. For now I have hard coded the transmit to send 5. All the data is received correctly by the slave in this time but the slave does not transmit 5 until the third byte is received.
SLAVE SETUP:
hspi1.Instance = SPI1;
hspi1.Init.Mode = SPI_MODE_SLAVE;
hspi1.Init.Direction = SPI_DIRECTION_2LINES;
hspi1.Init.DataSize = SPI_DATASIZE_8BIT;
hspi1.Init.CLKPolarity = SPI_POLARITY_LOW;
hspi1.Init.CLKPhase = SPI_PHASE_2EDGE;
hspi1.Init.NSS = SPI_NSS_SOFT;
hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;
hspi1.Init.TIMode = SPI_TIMODE_DISABLE;
hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
hspi1.Init.CRCPolynomial = 0x0;
hspi1.Init.NSSPMode = SPI_NSS_PULSE_DISABLE;
hspi1.Init.NSSPolarity = SPI_NSS_POLARITY_LOW;
hspi1.Init.FifoThreshold = SPI_FIFO_THRESHOLD_01DATA;
hspi1.Init.TxCRCInitializationPattern = SPI_CRC_INITIALIZATION_ALL_ZERO_PATTERN;
hspi1.Init.RxCRCInitializationPattern = SPI_CRC_INITIALIZATION_ALL_ZERO_PATTERN;
hspi1.Init.MasterSSIdleness = SPI_MASTER_SS_IDLENESS_00CYCLE;
hspi1.Init.MasterInterDataIdleness = SPI_MASTER_INTERDATA_IDLENESS_00CYCLE;
hspi1.Init.MasterReceiverAutoSusp = SPI_MASTER_RX_AUTOSUSP_DISABLE;
hspi1.Init.MasterKeepIOState = SPI_MASTER_KEEP_IO_STATE_ENABLE;
hspi1.Init.IOSwap = SPI_IO_SWAP_DISABLE;
if (HAL_SPI_Init(&hspi1) != HAL_OK)
{
Error_Handler();
}
//MY INIT:
HAL_GPIO_WritePin(nFPINT_GPIO_Port, nFPINT_Pin, GPIO_PIN_SET); //raise /busy line
__HAL_SPI_DISABLE(&hspi1);
hspi1.Instance->UDRDR = 0xA5;
__HAL_SPI_CLEAR_OVRFLAG(&hspi1);
__HAL_SPI_CLEAR_EOTFLAG(&hspi1);
__HAL_SPI_CLEAR_FREFLAG(&hspi1);
__HAL_SPI_DISABLE_IT(&hspi1, SPI_IT_TXP);
__HAL_SPI_ENABLE_IT(&hspi1, SPI_IT_RXP);
HAL_NVIC_EnableIRQ(SPI1_IRQn);
// /CS handler
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) {
if (GPIO_Pin == GPIO_PIN_14) {
if(HAL_GPIO_ReadPin(nCS_GPIO_Port, nCS_Pin) == GPIO_PIN_RESET){
__HAL_SPI_DISABLE(&hspi1);
__HAL_SPI_ENABLE(&hspi1);
txBuffer = 0; //transmit 0 for first byte
}
}
__HAL_GPIO_EXTI_CLEAR_IT(GPIO_Pin);
}
void spiISRSTM(SPI_HandleTypeDef *hspi) {
HAL_GPIO_WritePin(nFPINT_GPIO_Port, nFPINT_Pin, GPIO_PIN_RESET); //Lower /Busy
if (hspi->Instance->SR & SPI_FLAG_TXP) {
(*(__IO uint8_t *)&hspi->Instance->TXDR) = 5; // transmit
}
//Receive if ready
if (hspi->Instance->SR & SPI_FLAG_RXP) {
rxBuffer = (*(__IO uint8_t *)&hspi->Instance->RXDR);
ProcessSPI(); //Process SPI data
}
__HAL_SPI_CLEAR_UDRFLAG(hspi);
__HAL_SPI_CLEAR_OVRFLAG(hspi);
__HAL_SPI_CLEAR_EOTFLAG(hspi);
__HAL_SPI_CLEAR_FREFLAG(hspi);
}
Solved! Go to Solution.
2024-11-25 02:28 PM
The issue was an underrun after the first byte. Disabling and reenabling spi after read and before transmit solved the issue.
sr = hspi->Instance->SR;
if ((sr & (SPI_FLAG_RXP | SPI_FLAG_TXC)) == (SPI_FLAG_RXP | SPI_FLAG_TXC)) {
HAL_GPIO_WritePin(nFPINT_GPIO_Port, nFPINT_Pin, GPIO_PIN_RESET); //Lower nFPINT
rxBuffer = (*(__IO uint8_t *)&hspi->Instance->RXDR);
__HAL_SPI_DISABLE(&hspi1);
__HAL_SPI_ENABLE(&hspi1);
pPacketSlave->ProcessSPI();
(*(__IO uint8_t *)&hspi->Instance->TXDR) = txBuffer;
}
2024-11-21 03:01 AM
Hello @EthanMankins
To ensure efficient SPI transmit/receive, you should fill the TX FIFO before enabling TXP and RXP interrupts. Here is a code snippet to guide you:
// Initialization code
void SPI_Init(void) {
// Other initialization code..
// Fill the TX FIFO before enabling interrupts
while (__HAL_SPI_GET_FLAG(&hspi, SPI_FLAG_TXP)) {
// Fill the TX FIFO with data
*((__IO uint8_t *)&hspi.Instance->TXDR) = *pTxData++;
}
// Enable the TXP interrupt
__HAL_SPI_ENABLE_IT(&hspi, SPI_IT_TXP);
// Enable the RXP interrupt
__HAL_SPI_ENABLE_IT(&hspi, SPI_IT_RXP);
// Enable the SPI
__HAL_SPI_ENABLE(&hspi);
}
// Interrupt Service Routine (ISR)
void SPI_IRQHandler(void) {
// Check the TXP flag
if (__HAL_SPI_GET_FLAG(&hspi, SPI_FLAG_TXP)) {
// Transmit data
*((__IO uint8_t *)&hspi.Instance->TXDR) = *pTxData++;
}
// Check the RXP flag
if (__HAL_SPI_GET_FLAG(&hspi, SPI_FLAG_RXP)) {
// Receive data
*pRxData++ = *((__IO uint8_t *)&hspi.Instance->RXDR);
}
// Other ISR code...
}
2024-11-21 09:36 AM
Hi @Saket_Om ,
I just gave this a shot, and starting with pTxData = 0, it transmits 16, 17, 18... Based on the definition of a FIFO I would have expected it to transmit 0, 1, 2, 3... Why would it start with the last in 16 instead of first in 0?
2024-11-21 02:58 PM
@Saket_Om I have found that filling the buffer does not effect the operation. The same issue persists
2024-11-22 12:34 AM - edited 2024-11-22 12:34 AM
Hello @EthanMankins
Could you please share the complete code for both the master and slave devices, including the main function, so that we can assist you more efficiently?
Could you please check with the HAL API to see if it works fine for your application? If it does, you can use it as inspiration to customize your SPI functions.
2024-11-22 09:03 AM
SLAVE:
/* SPI1 parameter configuration*/
hspi1.Instance = SPI1;
hspi1.Init.Mode = SPI_MODE_SLAVE;
hspi1.Init.Direction = SPI_DIRECTION_2LINES;
hspi1.Init.DataSize = SPI_DATASIZE_8BIT;
hspi1.Init.CLKPolarity = SPI_POLARITY_LOW;
hspi1.Init.CLKPhase = SPI_PHASE_2EDGE;
hspi1.Init.NSS = SPI_NSS_SOFT;
hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;
hspi1.Init.TIMode = SPI_TIMODE_DISABLE;
hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
hspi1.Init.CRCPolynomial = 0x0;
hspi1.Init.NSSPMode = SPI_NSS_PULSE_DISABLE;
hspi1.Init.NSSPolarity = SPI_NSS_POLARITY_LOW;
hspi1.Init.FifoThreshold = SPI_FIFO_THRESHOLD_01DATA;
hspi1.Init.TxCRCInitializationPattern = SPI_CRC_INITIALIZATION_ALL_ZERO_PATTERN;
hspi1.Init.RxCRCInitializationPattern = SPI_CRC_INITIALIZATION_ALL_ZERO_PATTERN;
hspi1.Init.MasterSSIdleness = SPI_MASTER_SS_IDLENESS_00CYCLE;
hspi1.Init.MasterInterDataIdleness = SPI_MASTER_INTERDATA_IDLENESS_00CYCLE;
hspi1.Init.MasterReceiverAutoSusp = SPI_MASTER_RX_AUTOSUSP_DISABLE;
hspi1.Init.MasterKeepIOState = SPI_MASTER_KEEP_IO_STATE_ENABLE;
hspi1.Init.IOSwap = SPI_IO_SWAP_DISABLE;
if (HAL_SPI_Init(&hspi1) != HAL_OK)
{
Error_Handler();
}
HAL_GPIO_WritePin(nFPINT_GPIO_Port, nFPINT_Pin, GPIO_PIN_SET);
__HAL_SPI_DISABLE(&hspi1);
hspi1.Instance->UDRDR = 0xA5;
__HAL_SPI_CLEAR_OVRFLAG(&hspi1);
__HAL_SPI_CLEAR_EOTFLAG(&hspi1);
__HAL_SPI_CLEAR_FREFLAG(&hspi1);
HAL_NVIC_EnableIRQ(SPI1_IRQn);
// /CS handler
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) {
if (GPIO_Pin == GPIO_PIN_14) {
if(HAL_GPIO_ReadPin(nCS_GPIO_Port, nCS_Pin) == GPIO_PIN_RESET){
HAL_GPIO_WritePin(nFPINT_GPIO_Port, nFPINT_Pin, GPIO_PIN_RESET);
txBuffer = 2;
*((__IO uint8_t *)&hspi1.Instance->TXDR) = txBuffer;
__HAL_SPI_ENABLE(&hspi1);
__HAL_SPI_ENABLE_IT(&hspi1, SPI_IT_RXP);
HAL_GPIO_WritePin(nFPINT_GPIO_Port, nFPINT_Pin, GPIO_PIN_SET);
}
if(HAL_GPIO_ReadPin(nCS_GPIO_Port, nCS_Pin) == GPIO_PIN_SET){
__HAL_SPI_DISABLE_IT(&hspi1, SPI_IT_RXP);
__HAL_SPI_DISABLE(&hspi1);
hspi1.Instance->UDRDR = 0xA5;
__HAL_SPI_CLEAR_OVRFLAG(&hspi1);
__HAL_SPI_CLEAR_EOTFLAG(&hspi1);
__HAL_SPI_CLEAR_FREFLAG(&hspi1);
}
}
__HAL_GPIO_EXTI_CLEAR_IT(GPIO_Pin);
}
void spiISRSTM(SPI_HandleTypeDef *hspi) {
//Receive if ready
if (hspi->Instance->SR & SPI_FLAG_RXP) {
HAL_GPIO_WritePin(nFPINT_GPIO_Port, nFPINT_Pin, GPIO_PIN_RESET); //Lower nFPINT
rxBuffer = (*(__IO uint8_t *)&hspi->Instance->RXDR);
(*(__IO uint8_t *)&hspi->Instance->TXDR) = 1;
HAL_GPIO_WritePin(nFPINT_GPIO_Port, nFPINT_Pin, GPIO_PIN_SET);
}
__HAL_SPI_CLEAR_UDRFLAG(hspi);
__HAL_SPI_CLEAR_OVRFLAG(hspi);
__HAL_SPI_CLEAR_EOTFLAG(hspi);
__HAL_SPI_CLEAR_FREFLAG(hspi);
}
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_USART3_UART_Init();
MX_USB_OTG_FS_PCD_Init();
MX_USART2_UART_Init();
MX_SPI1_Init();
MX_TIM2_Init();
HAL_GPIO_WritePin(nFPINT_GPIO_Port, nFPINT_Pin, GPIO_PIN_SET);
__HAL_SPI_DISABLE(&hspi1);
hspi1.Instance->UDRDR = 0xA5;
__HAL_SPI_CLEAR_OVRFLAG(&hspi1);
__HAL_SPI_CLEAR_EOTFLAG(&hspi1);
__HAL_SPI_CLEAR_FREFLAG(&hspi1);
HAL_NVIC_EnableIRQ(SPI1_IRQn);
while (1)
{
}
}
MASTER:
hspi2.Instance = SPI2;
hspi2.Init.Mode = SPI_MODE_MASTER;
hspi2.Init.Direction = SPI_DIRECTION_2LINES;
hspi2.Init.DataSize = SPI_DATASIZE_8BIT;
hspi2.Init.CLKPolarity = SPI_POLARITY_LOW;
hspi2.Init.CLKPhase = SPI_PHASE_2EDGE;
hspi2.Init.NSS = SPI_NSS_SOFT;
hspi2.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_256;
hspi2.Init.FirstBit = SPI_FIRSTBIT_MSB;
hspi2.Init.TIMode = SPI_TIMODE_DISABLE;
hspi2.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
hspi2.Init.CRCPolynomial = 0x0;
hspi2.Init.NSSPMode = SPI_NSS_PULSE_DISABLE;
hspi2.Init.NSSPolarity = SPI_NSS_POLARITY_LOW;
hspi2.Init.FifoThreshold = SPI_FIFO_THRESHOLD_01DATA;
hspi2.Init.TxCRCInitializationPattern = SPI_CRC_INITIALIZATION_ALL_ZERO_PATTERN;
hspi2.Init.RxCRCInitializationPattern = SPI_CRC_INITIALIZATION_ALL_ZERO_PATTERN;
hspi2.Init.MasterSSIdleness = SPI_MASTER_SS_IDLENESS_00CYCLE;
hspi2.Init.MasterInterDataIdleness = SPI_MASTER_INTERDATA_IDLENESS_00CYCLE;
hspi2.Init.MasterReceiverAutoSusp = SPI_MASTER_RX_AUTOSUSP_DISABLE;
hspi2.Init.MasterKeepIOState = SPI_MASTER_KEEP_IO_STATE_ENABLE;
hspi2.Init.IOSwap = SPI_IO_SWAP_DISABLE;
if (HAL_SPI_Init(&hspi2) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN SPI2_Init 2 */
__HAL_SPI_ENABLE(&hspi2);
HAL_GPIO_WritePin(GPIOI, GPIO_PIN_0, GPIO_PIN_RESET); // Pull CS low
HAL_Delay(1);
while(nOutputByte != -1)
{
int nReceiveByte = STM_SPI_Xmit(&hspi2, nOutputByte);
nOutputByte = SpiISR_Packet(NULL, (DWORD)this, nReceiveByte); //delay untilnFPINT line is high
}
HAL_GPIO_WritePin(GPIOI, GPIO_PIN_0, GPIO_PIN_SET); // Pull CS high
volatile uint8_t rxBuffer;
volatile uint8_t txBuffer;
volatile uint8_t byteRd = 0;
volatile uint8_t byteXd = 0;
int STM_SPI_Xmit(SPI_HandleTypeDef *hspi, int nOutputByte){
txBuffer = (uint8_t) nOutputByte;
__HAL_SPI_ENABLE(hspi);
__HAL_SPI_ENABLE_IT(hspi, SPI_IT_TXP); // Enable TXP untill byte is sent
while(!byteXd){}
byteXd = 0; // Clear byte is sent flag
while (!byteRd){} // Poll while no byte is Received
byteRd = 0;
return (int) rxBuffer;
}
void spiISRSTM(SPI_HandleTypeDef *hspi) {
if (hspi->Instance->SR & SPI_FLAG_TXP) {
SET_BIT(hspi->Instance->CR1, SPI_CR1_CSTART); // start SPI master
(*(__IO uint8_t *)&hspi->Instance->TXDR) = txBuffer; // transmit
__HAL_SPI_DISABLE_IT(hspi, SPI_IT_TXP); // disable TXP
while(!__HAL_SPI_GET_FLAG(hspi, SPI_FLAG_TXC)){}
// printf("|%u ", (uint8_t)txBuffer);
byteXd = 1;
}
//Receive if ready
if (hspi->Instance->SR & SPI_FLAG_RXP) {
rxBuffer = (*(__IO uint8_t *)&hspi->Instance->RXDR);
// printf("%u|", (uint8_t)rxBuffer);
byteRd = 1;
__HAL_SPI_DISABLE_IT(hspi, SPI_IT_RXP);
}
__HAL_SPI_DISABLE(hspi);
__HAL_SPI_CLEAR_UDRFLAG(hspi);
__HAL_SPI_CLEAR_OVRFLAG(hspi);
__HAL_SPI_CLEAR_EOTFLAG(hspi);
__HAL_SPI_CLEAR_FREFLAG(hspi);
}
2024-11-22 09:05 AM
I have tire the HALAPI however, I could not get it to work with transferring one byte at a time and was told it would likely not work with HALAPI.
2024-11-25 06:26 AM
Hello @EthanMankins
On the slave side in the main function, you are disabling the SPI peripheral just after setting the nFPINT_Pin to hight.
This will notify the master device to send data when the slave still disabled until EXTIcallback be called.
To debug more efficiently your issue, please flow try with snippet code below:
#include "main.h"
volatile uint8_t rxBuffer;
volatile uint8_t txBuffer;
void SystemClock_Config(void);
void MX_GPIO_Init(void);
void MX_SPI1_Init(void);
void Error_Handler(void);
SPI_HandleTypeDef hspi1;
void SPI_start(void) {
// Set the value of txBuffer
txBuffer = 2;
// Fill the FIFO with the value of txBuffer
for (int i = 0; i < 16; i++) { // Fill FIFO with 16 bytes of data
*((__IO uint8_t *)&hspi1.Instance->TXDR) = txBuffer;
}
// Set the interrupts and start SPI process
__HAL_SPI_ENABLE(&hspi1);
__HAL_SPI_ENABLE_IT(&hspi1, SPI_IT_RXP);
}
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) {
if (GPIO_Pin == GPIO_PIN_14) {
if (HAL_GPIO_ReadPin(nCS_GPIO_Port, nCS_Pin) == GPIO_PIN_RESET) {
HAL_GPIO_WritePin(nFPINT_GPIO_Port, nFPINT_Pin, GPIO_PIN_RESET);
SPI_start();
HAL_GPIO_WritePin(nFPINT_GPIO_Port, nFPINT_Pin, GPIO_PIN_SET);
} else if (HAL_GPIO_ReadPin(nCS_GPIO_Port, nCS_Pin) == GPIO_PIN_SET) {
__HAL_SPI_DISABLE_IT(&hspi1, SPI_IT_RXP);
__HAL_SPI_DISABLE(&hspi1);
__HAL_SPI_CLEAR_OVRFLAG(&hspi1);
__HAL_SPI_CLEAR_EOTFLAG(&hspi1);
__HAL_SPI_CLEAR_FREFLAG(&hspi1);
}
}
__HAL_GPIO_EXTI_CLEAR_IT(GPIO_Pin);
}
void spiISRSTM(SPI_HandleTypeDef *hspi) {
if (hspi->Instance->SR & SPI_FLAG_RXP) {
HAL_GPIO_WritePin(nFPINT_GPIO_Port, nFPINT_Pin, GPIO_PIN_RESET);
rxBuffer = (*(__IO uint8_t *)&hspi->Instance->RXDR);
(*(__IO uint8_t *)&hspi->Instance->TXDR) = 1;
HAL_GPIO_WritePin(nFPINT_GPIO_Port, nFPINT_Pin, GPIO_PIN_SET);
}
__HAL_SPI_CLEAR_UDRFLAG(hspi);
__HAL_SPI_CLEAR_OVRFLAG(hspi);
__HAL_SPI_CLEAR_EOTFLAG(hspi);
__HAL_SPI_CLEAR_FREFLAG(hspi);
}
int main(void) {
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_SPI1_Init();
HAL_NVIC_EnableIRQ(SPI1_IRQn);
while (1) {
// Main loop
}
}
On the master side add a while loop in the main function to wait until the nFPINT_Pin is set before starting the transmission. This ensures that the master does not start transmitting until the slave is ready.
The transmission can be triggered and stopped by pressing the EXTI button on slave side.
2024-11-25 02:28 PM
The issue was an underrun after the first byte. Disabling and reenabling spi after read and before transmit solved the issue.
sr = hspi->Instance->SR;
if ((sr & (SPI_FLAG_RXP | SPI_FLAG_TXC)) == (SPI_FLAG_RXP | SPI_FLAG_TXC)) {
HAL_GPIO_WritePin(nFPINT_GPIO_Port, nFPINT_Pin, GPIO_PIN_RESET); //Lower nFPINT
rxBuffer = (*(__IO uint8_t *)&hspi->Instance->RXDR);
__HAL_SPI_DISABLE(&hspi1);
__HAL_SPI_ENABLE(&hspi1);
pPacketSlave->ProcessSPI();
(*(__IO uint8_t *)&hspi->Instance->TXDR) = txBuffer;
}