cancel
Showing results for 
Search instead for 
Did you mean: 

SPI CS problem

avi23
Associate II
Posted on September 12, 2014 at 09:46

Hi, everyone!

I am working with communication between stm32F4 SPI2 to small A/D read only. The reading process is only one 16 bit word so I using SPI2 as a Master and my configuration looks like this:

  SPI_InitTypeDef  SPI_InitStructure; 

  SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_RxOnly;

  SPI_InitStructure.SPI_Mode = SPI_Mode_Master;

  SPI_InitStructure.SPI_DataSize = SPI_DataSize_16b;

  SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;

  SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;

  SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;

  SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_64;//64;

  SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;

  SPI_InitStructure.SPI_CRCPolynomial = 7;

  SPI_Init(SPIx_APIT, &SPI_InitStructure);

When I processing read command I am using this :

uint16_t Get (void)

{   

 uint16_t val1 = 0;  

 ADCx_TRIG_LOW();

 ADCx_TRIG_HIGH();

 DelayPit(20);

 SPIx_APIT_CS_LOW();

 /*!< Wait to receive a byte */

 SPI_Cmd(SPIx_APIT, ENABLE);

while( !(SPI2->SR & SPI_I2S_FLAG_RXNE) ); // wait until receive complete

SPIx_APIT_CS_HIGH();

Val1 = SPI_I2S_ReceiveData(SPIx_APIT);  

SPI_Cmd(SPIx_APIT, DISABLE);

DelayPit(1);

return (uint16_t)(val1);

}

When ADCx_TRIG is an I/O that initiated sample from the A/D and the SPIx_APIT_CS config as a I/O.

This code is working good as you see in the first figure (yellow is clk, grin is CS and blue is trig for A/D)

Bat sometime (one in 300) the CS is up before time see the second figure and then I get fault data in my reading.

0690X00000602qeQAA.bmp

0690X00000602xnQAA.jpg

Is there anyone that can help me?

4 REPLIES 4
stm322399
Senior
Posted on September 12, 2014 at 11:08

SPI Rx-only is not easy to deal with because bits are clocked as soon as SPE is set. There is a paragraph in the RM that explain what you must do to stop the transfer properly.

Strictly following the manual will lead you to poll the start of the transfer and clear SPE before RXNE changes to 1. That way the SPI will not clock more bits in. Given the speed, and if you lucky enough not to be interrupted by interrupts, clearing SPE immediately after RXNE becomes 1 could be enough for the vast majority of transfer (299/300). Simply calling SPI_cmd(xxx,DISABLE) immediately after the while !(...RXNE), could improve your success rate in reading the ADC. But this is not 100% perfect.

To be 100% perfect, I will recommend you to drop the RX-only mode, use regular full-duplex. Hopefully you did not configured for 1 bidirectionnal line, so that you normally use MISO for data input. Do not care about the MOSI line, bits will be clocked out to MOSI, but as long as the SPI is not connected to any GPIO, it does not hurt. The big advantage of this solution is that you have now the control of SCLK, by writing into data register, so you are sure not to clock extra bits that will mess your ADC.

avi23
Associate II
Posted on September 14, 2014 at 08:17

thanks for your response.

but my problem is not overclocking, the problem is that the cs go high

before the time, the processor does not stay inside the while and gmp to the next line.

stm322399
Senior
Posted on September 14, 2014 at 19:57

OK, I'll try to make it more simple.

If the processor do not stay into the while, it is because there is already a received char as soon as you enable SPI. How is this possible ? Certainly because the extra character has been arrived with the previous frame (try to catch the previous frame with your scope). Use an assert before enabling the SPI to check that the SPI has no character inside the RX buffer, when it has one, just read it to clear RXNE.

avi23
Associate II
Posted on September 29, 2014 at 14:28

ok it's working.

thanks