cancel
Showing results for 
Search instead for 
Did you mean: 

SPI last bit problem

planeetmaa
Associate II
Posted on November 23, 2009 at 08:32

SPI last bit problem

8 REPLIES 8
planeetmaa
Associate II
Posted on May 17, 2011 at 13:30

And one thing more:

I also tried to change the clock polarity, the effect was exactly the same...

BR, Madis

planeetmaa
Associate II
Posted on May 17, 2011 at 13:30

Hello!

I have quite strange problem with the SPI bus on STM32F103ZEH. The problem is, that it seems to postpone the last bit to the next byte. I did the initialisation as follows:

SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;

SPI_InitStructure.SPI_Mode = SPI_Mode_Master;

SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;

SPI_InitStructure.SPI_CPOL = SPI_CLOCK_POL;

SPI_InitStructure.SPI_CPHA = SPI_MODE_1;

SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;

SPI_InitStructure.SPI_BaudRatePrescaler = SPI_SPEED;

SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;

SPI_InitStructure.SPI_CRCPolynomial = 7;

SPI_Init(SPI1, &SPI_InitStructure);

And read and write functions are quite straight forward (no interrupts nor DMA included):

SPI write (which functions properly):

while (uxNoData)

{

SPI_SendByte(Bank, *pucData++);

uxNoData--;

}

and SPI read:

while (uxNoData)

{

*pucData++= SPI_SendByte(Bank, 0);

uxNoData--;

}

And my send byte function, they both call:

u8 SPI_SendByte(u8 Bank, u8 byte)

{

/* Loop while DR register in not emplty */

while (SPI_I2S_GetFlagStatus((SPI_TypeDef *) PPSSPI[Bank], SPI_I2S_FLAG_TXE) == RESET);

/* Send byte through the SPI1 peripheral */

SPI_I2S_SendData((SPI_TypeDef *) PPSSPI[Bank], byte);

/* Wait to receive a byte */

while (SPI_I2S_GetFlagStatus((SPI_TypeDef *) PPSSPI[Bank], SPI_I2S_FLAG_RXNE) == RESET);

/* Return the byte read from the SPI bus */

return SPI_I2S_ReceiveData((SPI_TypeDef *) PPSSPI[Bank]);

}

Now, I wrote data 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00 to the EEPROM starting from the address 68(decimal). And when I read it back I get:

0xFE last bit is missing

0xFF all seems to be ok, but the missing bit is from the previous read

0x01 last 1 from previous 0xff

0x00

0xFE last missing again

0xFF

0x01

0x00

I attach also the picture of the signals. You can see from there that data seems to be quite correct on the bus. I added the signal labels and data actually read back by the STM.

BR, Madis

[ This message was edited by: Madis on 19-11-2009 13:20 ]

domen2
Associate III
Posted on May 17, 2011 at 13:30

SPI_InitStructure.SPI_CPOL = SPI_CLOCK_POL;

SPI_InitStructure.SPI_CPHA = SPI_MODE_1;

Where are these defines from?

in my spi.h, there's:

#define SPI_CPOL_Low ((u16)0x0000)

#define SPI_CPOL_High ((u16)0x0002)

#define SPI_CPHA_1Edge ((u16)0x0000)

#define SPI_CPHA_2Edge ((u16)0x0001)

Anyways, reading docs and selecting the right values should work. Or you could just try all four combinations, but I've been bitten by this before (worked 99.9% of the time :-P).

planeetmaa
Associate II
Posted on May 17, 2011 at 13:30

Sorry, I forgot to add those defines:

#define SPI_CLOCK_POL SPI_CPOL_Low //Low when idle

#define SPI_MODE_0 SPI_CPHA_1Edge //data read at rising clk edge

#define SPI_MODE_1 SPI_CPHA_2Edge //data read at falling clk edge

I tried SPI_CPOL_High also. I changed the 1Edge and 2Edge defines then in between. But no difference. But the clock polarity was changed while monitoring with scope, of course.

BR, Madis

armmcu
Associate II
Posted on May 17, 2011 at 13:30

What about the data sent from master, are they correct?

can you attach a picture?

planeetmaa
Associate II
Posted on May 17, 2011 at 13:30

Hi!

Yes, data sent by the master is correct. Its the last, red line (MOSI). First byte is READ command and the following two bytes are the address bytes from where to read. And as you can see, EEPROM programming should have been correct, it responds with correct data (FF, FF, 00, 00, FF, FF, 00, 00). But STM does not get it correct (I wrote the codes STM reads on the picture).

BR, Madis

[ This message was edited by: Madis on 20-11-2009 12:04 ]

planeetmaa
Associate II
Posted on May 17, 2011 at 13:30

Hi!

One more observation. I changed the SPI port from port 1 to port 2 (with some soldering and wires etc). And it seems to be that this specific problem exists only in the BGA package SPI1, as SPI2 functions like expected. Does anybody have the design with STM103ZEH6 (BGA) on board and has the ability to test SPI1 (and reading, writing seems to be ok)?

BR, Madis

planeetmaa
Associate II
Posted on May 17, 2011 at 13:30

Hi!

I havent been able to solve the problem so far. But I did some further testing. I wrote a very basic sw (only the SPI part) and tried it on two different boards. One was KEIL evaluation kit MCBSTM32 running on STM103RBT6 and another is our own hw running on STM103ZEH6. Evaluation board with QFP package is running fine. But our board with BGA is not. It is behaving the same as I described earlier. Lat bit is traveling to the next byte. Very strange. I wrote 01, 00, 55, 02, 00, 00, AA, 00 to the EEPROM and read it with both boards. Signals (SPI signals) look exactly the same on the scope. Out board reads:

00, 01, 54, 03, 00, 00, AA, 00 and KEIL evaluation board gets correct data (data is physically correct on both cases, as I observe it with scope). You can see how the last bit is traveling in our BGA package. If I write

00, 55, 03, 00

I get:

00, 54, 03, 01

So the last bit from 03 traveled to the next byte and 03 seems to be correct as it got the last bit from 55. But all those sequences function fine on KEIL board (same SPI port and exactly the same code). My code is as follows (writing part is commented out as I wrote data only once). And chip select is done over the shift register. But its the same for both boards, they connect to the same slave.

/*********************************************************************************

* DEFINES

*********************************************************************************/

//-------------Commands------------------

#define READ 0x03 //Read data from memory array beginning at selected address

#define WRITE 0x02 //Write data to memory array beginning at selected address

#define WRDI 0x04 //Reset the write enable latch (disable write operations)

#define WREN 0x06 //Set the write enable latch (enable write operations)

#define RDSR 0x05 //Read STATUS register

#define WRSR 0x01 //Write STATUS register

//#define CS_ON() GPIO_WriteBit(GPIOA, GPIO_Pin_4, Bit_RESET);

//#define CS_OFF() GPIO_WriteBit(GPIOA, GPIO_Pin_4, Bit_SET);

void SPI_TEST(void);

u8 SPI_T(u8 byte);

s32 xSPI_R(u8 *pucData, u32 uxNoData);

s32 xSPI_W(u8 *pucData, u32 uxNoData);

void CS_ON(void);

void CS_OFF(void);

/*********************************************************************************

* CS_ON

*********************************************************************************/

void CS_ON(void)

{

u32 uxCommand;

GPIO_WriteBit(GPIOA, GPIO_Pin_4, Bit_RESET);

//manipulate switch

uxCommand= 1<

uxCommand= ~uxCommand;

xSPI_W((u8*) &uxCommand, 1);

GPIO_WriteBit(GPIOA, GPIO_Pin_4, Bit_SET);

}

/*********************************************************************************

* CS_OFF

*********************************************************************************/

void CS_OFF(void)

{

u32 uxCommand;

GPIO_WriteBit(GPIOA, GPIO_Pin_4, Bit_RESET);

//manipulate switch

uxCommand= 0;

uxCommand= ~uxCommand;

xSPI_W((u8*) &uxCommand, 1);

GPIO_WriteBit(GPIOA, GPIO_Pin_4, Bit_SET);

}

/*********************************************************************************

* xSPIW

*********************************************************************************/

s32 xSPI_W(u8 *pucData, u32 uxNoData)

{

u8 i;

while (uxNoData)

{

i= SPI_T(*pucData++);

uxNoData--;

}

return 0;

}

/*********************************************************************************

* xSPIRead

*********************************************************************************/

s32 xSPI_R(u8 *pucData, u32 uxNoData)

{

while (uxNoData)

{

*pucData++= SPI_T(0);

uxNoData--;

}

return 0;

}

/*********************************************************************************

* SPI_T

*********************************************************************************/

u8 SPI_T(u8 byte)

{

/* Loop while DR register in not emplty */

while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET);

/* Send byte through the SPI1 peripheral */

SPI_I2S_SendData(SPI1, byte);

/* Wait to receive a byte */

while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET);

/* Return the byte read from the SPI bus */

return SPI_I2S_ReceiveData(SPI1);

}

/*********************************************************************************

* FUNCTIONS

*********************************************************************************/

void SPI_TEST(void)

{

GPIO_InitTypeDef GPIO_InitStructure;

SPI_InitTypeDef SPI_InitStructure;

u32 uxCommand;

volatile u8 *pucData, ucData[8];

RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);

//enable clock for IO pins

RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB |RCC_APB2Periph_GPIOC

| RCC_APB2Periph_GPIOD | RCC_APB2Periph_GPIOE | RCC_APB2Periph_GPIOF |

RCC_APB2Periph_GPIOG, ENABLE);

//configure SPI 1 IO pins

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7;

GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;

GPIO_Init(GPIOA, &GPIO_InitStructure);

//configure SPI CS pin

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;

GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;

GPIO_Init(GPIOA, &GPIO_InitStructure);

SPI_I2S_DeInit(SPI1);

SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;

SPI_InitStructure.SPI_Mode = SPI_Mode_Master;

SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;

SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;

SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;

SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;

SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256;

SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;

SPI_InitStructure.SPI_CRCPolynomial = 7;

SPI_Init(SPI1, &SPI_InitStructure);

SPI_Cmd(SPI1, ENABLE);

CS_OFF();

// //write some data to the address 69

// ucData[0]= 0x01;

// ucData[1]= 0x00;

// ucData[2]= 0x55;

// ucData[3]= 0x02;

// ucData[4]= 0x00;

// ucData[5]= 0x00;

// ucData[6]= 0xAA;

// ucData[7]= 0x00;

// //WREN

// CS_ON();

// uxCommand= WREN;

// xSPI_W((u8*) &uxCommand, 1);

// CS_OFF();

// CS_ON();

// pucData= (u8*) &uxCommand;

// *pucData++= (WRITE); //first command byte

// *pucData++= ((68 >> 8) & 0xFF); //second command byte- higher byte of the address

// *pucData++= ((68 >> 0) & 0xFF); //second command byte- lower byte of the address

// xSPI_W((u8*) &uxCommand, 3);

// xSPI_W(ucData, 8);

// CS_OFF();

while(1)

{

//read data from the EEPROM

CS_ON();

pucData= (u8*) &uxCommand;

*pucData++= (READ);

*pucData++= ((68 >> 8) & 0xFF);

*pucData++= ((68 >> 0) & 0xFF);

xSPI_W((u8*) &uxCommand, 3);

xSPI_R(ucData, 8);

CS_OFF();

}

}

BR, Madis