cancel
Showing results for 
Search instead for 
Did you mean: 

SPI read problem

_behn4m
Associate II
Posted on December 23, 2013 at 06:47

Hello

I want to set some parameters on W5100 chip and then read them. the parameters sets right, but when I want to read a register what I receive from SPI is value of past register address I've sent. My micro is STM32F103 and I use KEIL here is my codes, I use these functions too write and read SPI:

void W5100_write(u16 addr, u8 data)
{
//SPI_NSSInternalSoftwareConfig(SPI1, RESET); // enable the W5100 chip
GPIO_ResetBits(GPIOA, GPIO_Pin_4);
while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET);
SPI_I2S_SendData(SPI1, W5100_WRITE_OPCODE); // need to write a byte
while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET);
SPI_I2S_SendData(SPI1, (addr & 0xff00) >> 8); // send MSB of addr
while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET);
SPI_I2S_SendData(SPI1, (addr & 0xff)); // send LSB
while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET);
SPI_I2S_SendData(SPI1, data); // send the data
while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET);
//SPI_NSSInternalSoftwareConfig(SPI1, SET); // disable the W5100 chip // done with the chip
while( SPI1->SR & SPI_I2S_FLAG_BSY );
GPIO_SetBits(GPIOA, GPIO_Pin_4);
}
u8 W5100_read(u16 addr)
{
u8 data;
//SPI_NSSInternalSoftwareConfig(SPI1, RESET); // enable the W5100 chip
GPIO_ResetBits(GPIOA, GPIO_Pin_4);
while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET);
SPI_I2S_SendData(SPI1, W5100_READ_OPCODE); // need to write a byte
while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET);
SPI_I2S_SendData(SPI1, (addr & 0xff00) >> 8); // send MSB of addr
while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET);
SPI_I2S_SendData(SPI1, (addr & 0xff)); // send LSB
while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET);
SPI_I2S_SendData(SPI1, (0x00)); // send Dummy byte
while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET); 
while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET);
data = SPI_I2S_ReceiveData(SPI1); // done with the chip
while( SPI1->SR & SPI_I2S_FLAG_BSY );
GPIO_SetBits(GPIOA, GPIO_Pin_4);
return data;
}

here I write then read and send to pc by usart:

W5100_write(W5100_GAR + 0, pcfg->gtw_addr[0]); // set up the gateway address
W5100_write(W5100_GAR + 1, pcfg->gtw_addr[1]);
W5100_write(W5100_GAR + 2, pcfg->gtw_addr[2]);
W5100_write(W5100_GAR + 3, pcfg->gtw_addr[3]);
delay_ms(1);
while( !(USART1->SR & 0x00000040));
USART_SendData(USART1, W5100_read(W5100_SIPR + 0)); 
while( !(USART1->SR & 0x00000040));
USART_SendData(USART1, W5100_read(W5100_SIPR + 1));
while( !(USART1->SR & 0x00000040));
USART_SendData(USART1, W5100_read(W5100_SIPR + 2));
while( !(USART1->SR & 0x00000040));
USART_SendData(USART1, W5100_read(W5100_SIPR + 3));

I can't understand whats the problem, thank you. #spi #w5100 #stm32f103 #spi
10 REPLIES 10
jpeacock2399
Associate II
Posted on December 23, 2013 at 23:33

SPI is inherently bi-directional.  After every transmit the SPI also clocks in a data byte, which you have to clear with a dummy read.  Chances are you are overrunning the SPI RX buffer.

  Jack Peacock
jj2
Associate II
Posted on December 24, 2013 at 00:55

Jack makes a very valid point - but I disagree w/his conclusion.  You state that you ''read'' the address of the most recently sent data.  Suspect that what you'd prefer is the ''data'' contained in that target location - not the address. 

Edit - upon a 2nd read of your post - I find the description of your read to be imprecise.  (i.e. could mean that you recover the address of past write - or the ''data'' of past write.  And - if it is the ''data'' - then Jack's comment is spot on.  And - if that's the case - my sense is that you'd have to, ''readdress'' the slave to recover the data @ that specific address.  (also - many such devices enable a sequential ''dump'' of such data - after you specify some starting register and/or address) 

Might the command for, ''data read'' differ from that for, ''address read?''  If so - isn't it likely that you are not sending the proper command to recover data?  As you must first, ''clock in'' the data - simultaneous reads seem not to the the issue.  You may have to first specify the target data's address - and then issue a HW or SW (or both) toggle to recover the desired data.

Suggest a deeper read of the slave SPI device data manual is in order - and then you must align your MCU code to comply with the slave's specification.
lowpowermcu
Associate II
Posted on December 24, 2013 at 10:04

Hi,

Can you provide us the how SPI is configured?

_behn4m
Associate II
Posted on December 25, 2013 at 14:56

thank you for your response, I have done it by a DUMMY read.

in datasheet said that after sending address, the value of that comes on SPI, and I send a 0x00 byte too read the Value, but its value of previous address I sent in previous session!

_behn4m
Associate II
Posted on December 25, 2013 at 15:51

thank you a lot for you'r attention

that's what exacly happening: I write on 4 addresses, and then I want too read them to make sure that I'm doing right. I read 4 addresses with read function, but at every SPI session, my received data is value of previous session address!

In data sheet said do what I'm doing with my read and write functions! here is the SPI signallimg diagram in datasheet:0690X00000602kaQAA.jpg

_behn4m
Associate II
Posted on December 25, 2013 at 15:55

here it is, Thank you:

void config_SPI1()
{
SPI_InitTypeDef SPI_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
/* GPIOA Periph clock enable */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
/* Configure PA5, PA7 in AF pushpool mode */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_7;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
/* Initialize GPIOA */ 
GPIO_Init(GPIOA, &GPIO_InitStructure); 
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
/* Initialize GPIOA */ 
GPIO_Init(GPIOA, &GPIO_InitStructure); 
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
/* Initialize GPIOA */ 
GPIO_Init(GPIOA, &GPIO_InitStructure); 
// RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE); 
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE); 
//GPIO_PinRemapConfig(GPIO_Remap_SPI1, ENABLE);
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_8;
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
SPI_InitStructure.SPI_CRCPolynomial = 7;
/* Initialize SPI1 */ 
SPI_Init(SPI1, &SPI_InitStructure);
/* enable SPI1 */
SPI_Cmd(SPI1, ENABLE); 
}

lowpowermcu
Associate II
Posted on December 25, 2013 at 19:30

Hi Beh,

Can you give us the value of status register ''SPI_SR'' when you exit

W5100_read() 

?

I am suspecting an overrun condition...

_behn4m
Associate II
Posted on December 25, 2013 at 20:02

it is 0x43!

lowpowermcu
Associate II
Posted on December 25, 2013 at 20:17

Hi Beh,

As you are using SPI in Full Duplex you must read data every times you write in data register (even if you do not need it). The writing sequence should be something like the code below:

  /*!< Wait until the transmit buffer is empty */

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

  /*!< Send the byte */

  SPI_I2S_SendData(SPIx, Data);

  /*!< Wait to receive a byte*/

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

  readata =  (uint8_t)SPI_I2S_ReceiveData(SD_SPI);

Consequently, you code will be:

void  W5100_write(u16  addr, u8  data)

{

 u8 dummy;

    //SPI_NSSInternalSoftwareConfig(SPI1, RESET);                   // enable the W5100 chip

    GPIO_ResetBits(GPIOA, GPIO_Pin_4);

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

    SPI_I2S_SendData(SPI1, W5100_WRITE_OPCODE);                         // need to write a byte

    /*!< Wait to receive a byte*/

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

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

    dummy = (uint8_t)SPI_I2S_ReceiveData(SD_SPI);

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

    SPI_I2S_SendData(SPI1, (addr & 0xff00) >> 8);                       // send MSB of addr

    /*!< Wait to receive a byte*/

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

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

    dummy = (uint8_t)SPI_I2S_ReceiveData(SD_SPI);

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

    SPI_I2S_SendData(SPI1, (addr & 0xff));                                  // send LSB

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

    /*!< Wait to receive a byte*/

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

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

    dummy = (uint8_t)SPI_I2S_ReceiveData(SD_SPI);

    SPI_I2S_SendData(SPI1, data);                                                       // send the data

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

    /*!< Wait to receive a byte*/

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

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

    dummy = (uint8_t)SPI_I2S_ReceiveData(SD_SPI);

    //SPI_NSSInternalSoftwareConfig(SPI1, SET);                     // disable the W5100 chip                                    // done with the chip

    while( SPI1->SR & SPI_I2S_FLAG_BSY );

    GPIO_SetBits(GPIOA, GPIO_Pin_4);

}

 

u8  W5100_read(u16  addr)

{

    u8 data;

    //SPI_NSSInternalSoftwareConfig(SPI1, RESET);                   // enable the W5100 chip

    GPIO_ResetBits(GPIOA, GPIO_Pin_4);

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

    SPI_I2S_SendData(SPI1, W5100_READ_OPCODE);                          // need to write a byte

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

    /*!< Wait to receive a byte*/

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

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

    dummy = (uint8_t)SPI_I2S_ReceiveData(SD_SPI);

    SPI_I2S_SendData(SPI1, (addr & 0xff00) >> 8);                       // send MSB of addr

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

    SPI_I2S_SendData(SPI1, (addr & 0xff));                                  // send LSB

    /*!< Wait to receive a byte*/

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

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

    dummy = (uint8_t)SPI_I2S_ReceiveData(SD_SPI);

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

    SPI_I2S_SendData(SPI1, (0x00));                                             // send Dummy byte

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

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

    data = SPI_I2S_ReceiveData(SPI1);                       // done with the chip

    while( SPI1->SR & SPI_I2S_FLAG_BSY );

    GPIO_SetBits(GPIOA, GPIO_Pin_4);

    return data;

}