cancel
Showing results for 
Search instead for 
Did you mean: 

SPI transfer problem

khalid2
Associate II
Posted on June 10, 2014 at 22:51

Hi all;

I'm trying to make two boards communicating with SPI. The Master is a board based on PIC µC and the slave is Discovery F3. The protocol that i have to establish is as follows: 1) The master sends a command to the slave then it sends a data command of 4 bytes : this part is working fine. 2) The master sends a command to the slave. The slave decodes this address and then it sends back a data of 4 bytes. The problem: data sent by the MISO line is shifted,that means it's not received by the master in the order expected.

I used a hardware chip select and it's activated with interruption.

Below is the code of both the Slave and Master.

The Slave SPI Handler 
/**
* @brief Hnadle the SPI interrupt 
*/
void SPI1_IRQHandler(void)
{
/* SPI in Slave Receiver mode--------------------------------------- */
if (SPI_I2S_GetITStatus(SPI1, SPI_I2S_IT_RXNE) == SET)
{ 
/*------- Master --> Slave */
if (CmdStatus == 0x00)
{
CmdReceived = SPI_ReceiveData8(SPI1);
Rx_Idx=0;
Tx_Idx=0;
switch(CmdReceived){
case 0x01:
receiveSPI=0x01;
CmdStatus = 0x01;
StartSend=0x00;
break;
case 0x82 :
if (StartSend)
{
SendSPI=0x01;
CmdStatus = 0x01;
Spi_Case=0x01;
if (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) != RESET) 
// prepare to send the first byte
SPI_SendData8(SPI1,RegistreStaus[Tx_Idx++]);
if (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) != RESET) 
SPI_ReceiveData8(SPI1); // clear pending RX
}
break;
case 0x83:
if (StartSend)
{
SendSPI=0x01;
Spi_Case=0x02;
CmdStatus = 0x01;
if (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) != RESET) 
// prepare to send the first byte
SPI_SendData8(SPI1,RegistreError[Tx_Idx++]); 
if (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) != RESET) 
SPI_ReceiveData8(SPI1); // clear pending RX 
}
break;
case 0x84:
if (StartSend)
{
SendSPI=0x01;
Spi_Case=0x03;
CmdStatus = 0x01; 
if (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) != RESET) 
// prepare to send the first byte
SPI_SendData8(SPI1,PostionRegister.NmIposition[Tx_Idx++]);
if (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) != RESET) 
SPI_ReceiveData8(SPI1); // clear pending RX
} 
break;
default:
SendSPI=0x00;
Spi_Case=0x00;
CmdStatus = 0x00;
receiveSPI=0x00; 
break; 
}// end of switch
}// end of cmdStatus =0x00
else
{ // if cmdStatus 
if(receiveSPI)
{
RegistreCommand[Rx_Idx++] = SPI_ReceiveData8(SPI1); // the array sent by the Master
} // end of receiveSPI
/*------- Master <----> Salve */
if (SendSPI)
{ 
if( Spi_Case==0x03)
{
while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET); // wait for Tx register to be empty 
SPI_SendData8(SPI1,PostionRegister.NmIposition[Tx_Idx++]);
DummyData[Rx_Idx++]= SPI_ReceiveData8(SPI1); // the array sent by the Master 
STM_EVAL_LEDToggle(LED3);
if(Tx_Idx==0x04)
CmdStatus=0x00; 
} // end of Spi_Case=0x03
if( Spi_Case==0x02)
{
while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET); // wait for Tx register to be empty 
SPI_SendData8(SPI1,RegistreError[Tx_Idx++]);
DummyData[Rx_Idx++]= SPI_ReceiveData8(SPI1); // the array sent by the Master 
STM_EVAL_LEDToggle(LED8);
if(Tx_Idx==0x04)
CmdStatus=0x00;
}// end of Spi_Case=0x02
if( Spi_Case==0x01)
{ 
while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET); // wait for Tx register to be empty 
SPI_SendData8(SPI1,RegistreStaus[Tx_Idx++]); 
DummyData[Rx_Idx++]= SPI_ReceiveData8(SPI1); // the array sent by the Master 
STM_EVAL_LEDToggle(LED9);
if(Tx_Idx==0x04)
CmdStatus=0x00;
} // end of Spi_Case=0x01 
}// end os sendSPI
}// end of cmdStatus =0x01
}// end of RXNE ineterruption
} // end of SPI handler

/* The Slave Chip select Routine */

/**
* @brief This interrupt handler detects rising and falling edges of the slave select line
*/
void EXTI15_10_IRQHandler(void)
{
/* Handle the external interrupt for the SPI chip select (from PIC of the microcontroller) */
if(EXTI_GetITStatus(EXTI_Line15)==SET)
{
/*Clear pending bit */
EXTI_ClearITPendingBit(EXTI_Line15);
if(GPIOA->IDR & GPIO_Pin_15)
{
STM_EVAL_LEDToggle(LED10); 
if(receiveSPI==0x01)
{ 
receiveSPI=0x00;
/* Waiting until RX FIFO is empty */
while (SPI_GetReceptionFIFOStatus(SPI1) != SPI_ReceptionFIFOStatus_Empty)
{}
/* Wait busy flag */
while(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_BSY) == SET)
{}
/* Waiting until TX FIFO is empty */
while (SPI_GetTransmissionFIFOStatus(SPI1) != SPI_TransmissionFIFOStatus_Empty)
{} 
/* Disable the SPI interrupt */
SPI_I2S_ITConfig(SPI1, SPI_I2S_IT_RXNE, DISABLE);
SPI_I2S_ITConfig(SPI1, SPI_I2S_IT_ERR, DISABLE);
StartSend=0x01;
}else if (SendSPI==0x01)
{
/* Waiting until RX FIFO is empty */
while (SPI_GetReceptionFIFOStatus(SPI1) != SPI_ReceptionFIFOStatus_Empty)
{}
/* Wait busy flag */
while(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_BSY) == SET)
{}
SendSPI=0x00; 
Spi_Case=0x00;
/* Disable the SPI interrupt */
SPI_I2S_ITConfig(SPI1, SPI_I2S_IT_RXNE, DISABLE);
SPI_I2S_ITConfig(SPI1, SPI_I2S_IT_ERR, DISABLE);
STM_EVAL_LEDToggle(LED7);
}
}else if (!(GPIOA->IDR & GPIO_Pin_15))
{
/* Enable the Rx buffer not empty interrupt */
SPI_I2S_ITConfig(SPI1, SPI_I2S_IT_RXNE, ENABLE);
/* Enable the SPI Error interrupt */
SPI_I2S_ITConfig(SPI1, SPI_I2S_IT_ERR, ENABLE); 
STM_EVAL_LEDToggle(LED5); 
} 
}// end of if EXTILine

/* The Master part */

void vInterferoAxe1R(unsigned char ucRegister, unsigned long *pulValue)
{
ucRegister = ucRegister + (READ<<7); //Command send to the slave
SS_CPT1 = 1;
__delay_us(1);
cSPI1RW(ucRegister);
__delay_us(1);
*pulValue = cSPI1RW(0x00); //Read MSB B3
*pulValue = *pulValue<<8;
*pulValue += cSPI1RW(0x00); //Read B2
*pulValue = *pulValue<<8;
*pulValue += cSPI1RW(0x00); //Read B1
*pulValue = *pulValue<<8;
*pulValue += cSPI1RW(0x00); // Read LSB B0
__delay_us(1);
SS_CPT1 = 0;
}

Please any help would be appreciated, i spent a lot of time to resolve the problem but with no success. If someone has an example to communicate two board with SPI using interruption, please share it to have inspiration. Best Regards,
1 REPLY 1
khalid2
Associate II
Posted on June 11, 2014 at 15:50

I understand what causes my problem but I can't find a solution.

In fact, in the Slave board I don't have control of the clock that is demanding data, so it's intolerant of any latency.

This why I have to serve any requests very quickly,

I attached the chip select signal received from the Master :

I think it's very tight that the Slave could send data to the Master during Tl=5 µs.

Do you have any suggestion how can I do this stuff ?

Thanks in advance.

________________

Attachments :

Sans_titre.bmp : https://st--c.eu10.content.force.com/sfc/dist/version/download/?oid=00Db0000000YtG6&ids=0680X000006I0jJ&d=%2Fa%2F0X0000000bgH%2FYYLeZHoKZ7RawZUnUhdVcMTc8kapDIGHhypq5TlDWsA&asPdf=false