cancel
Showing results for 
Search instead for 
Did you mean: 

SPI Communication Issues

Posted on March 29, 2013 at 23:57

I am using the stm32l151RB microcontroller. It is running on an external clock source at 14.7456 MHz. I am communicating with a Micron M25P16 serial flash memory. This device states that it is compatible with CPOL/CPHA configurations of 0/0 and 1/1.

I am currently in the hardware validation phase writing simple blocks of code just to make sure the layout is correct. I was able to read the manufacturer id, memory type and memory capacity off of the device using a CPOL/CPHA set to 1/1.

The problem is that when CPOL/CPHA are set to 0/0 I am unable to read the previously listed items. Originally I was getting nothing but zeroes, but I have since updated to the latest SPI library files that I could find on the website. I now get 0xFF when I attempt to read. Also strangely enough when hooked up to the scope, we don't see any data coming out of the controller on the MOSI line in the 0/0 configuration. Any help that can be provided would be greatly appreciated. Please let me know that additional information I can provide.

Below you will find a snippet of the code that I am using detailing the SPI configuration.

Pin Configurations

void SPI_Flash_LowLevel_Init(void)

{

  GPIO_InitTypeDef  GPIO_InitStructure;

   

  RCC_AHBPeriphClockCmd(FLASH_SPI_CS_GPIO_CLK | FLASH_SPI_MOSI_GPIO_CLK | FLASH_SPI_MISO_GPIO_CLK |

                        FLASH_SPI_SCK_GPIO_CLK, ENABLE);

  RCC_APB2PeriphClockCmd(FLASH_SPI_CLK, ENABLE);

  GPIO_InitStructure.GPIO_Pin = FLASH_SPI_SCK_PIN;

  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;

  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;

  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;

  GPIO_InitStructure.GPIO_PuPd  = GPIO_PuPd_UP;

  GPIO_Init(FLASH_SPI_SCK_GPIO_PORT, &GPIO_InitStructure);

 

  GPIO_InitStructure.GPIO_Pin = FLASH_SPI_MISO_PIN;

  GPIO_Init(FLASH_SPI_MISO_GPIO_PORT, &GPIO_InitStructure);

  GPIO_InitStructure.GPIO_Pin = FLASH_SPI_MOSI_PIN;

  GPIO_Init(FLASH_SPI_MOSI_GPIO_PORT, &GPIO_InitStructure);

 

  /*MKM - TODO - Clean this up and put this pin configuration in the right place*/

  GPIO_InitStructure.GPIO_Pin = FLASH_SPI_CS_PIN;

  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;

  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;

  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;

  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;

  GPIO_Init(FLASH_SPI_CS_GPIO_PORT, &GPIO_InitStructure);

 

  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;

  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;

  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;

  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;

  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;

  GPIO_Init(FLASH_SPI_CS_GPIO_PORT, &GPIO_InitStructure);

 

  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;

  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;

  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;

  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;

  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;

  GPIO_Init(FLASH_SPI_CS_GPIO_PORT, &GPIO_InitStructure);

 

  GPIO_PinAFConfig(FLASH_SPI_SCK_GPIO_PORT, FLASH_SPI_SCK_SOURCE, FLASH_SPI_SCK_AF);

  GPIO_PinAFConfig(FLASH_SPI_MISO_GPIO_PORT, FLASH_SPI_MISO_SOURCE, FLASH_SPI_MISO_AF);

  GPIO_PinAFConfig(FLASH_SPI_MOSI_GPIO_PORT, FLASH_SPI_MOSI_SOURCE, FLASH_SPI_MOSI_AF);  

 

  SPI_Cmd(FLASH_SPI, ENABLE);

}

Usage

unsigned int i,mfg,memtype,capacity,address;

            

static portTASK_FUNCTION( vSPITask, pvParameters )

{

  /* The parameters are not used. */

  ( void ) pvParameters;

 

  SPI_InitTypeDef   SPI_InitStructure;

  SPI_InitTypeDef   *ptr_SPI_InitStructure;

  ptr_SPI_InitStructure = &SPI_InitStructure;

  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_High;

  SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;

  SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;

  SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_2;

  SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;

  SPI_InitStructure.SPI_CRCPolynomial = 7;

  SPI_Init(FLASH_SPI, &SPI_InitStructure);  

 

  RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);

  SPI_Init(FLASH_SPI, ptr_SPI_InitStructure);

  SPI_Cmd(FLASH_SPI, ENABLE);

 

   for(;;){

    

     

    GPIO_ResetBits(GPIOA, GPIO_Pin_4); //Flash Chip Select

    //GPIO_ResetBits(GPIOA, GPIO_Pin_3); //FPGA Chip Select

    

    while(SPI_GetFlagStatus(FLASH_SPI, SPI_FLAG_TXE)==RESET){}

    

    SPI_SendData(FLASH_SPI,0x9F); //Read ID command

    while(SPI_I2S_GetFlagStatus(FLASH_SPI, SPI_I2S_FLAG_TXE)==RESET){}

    SPI_I2S_ReceiveData(FLASH_SPI); // Clear out any pending RX data

    SPI_I2S_SendData(FLASH_SPI,0x00); // Junk Byte        

    

    while(SPI_GetFlagStatus(FLASH_SPI, SPI_FLAG_RXNE)==RESET){}

   

    mfg = SPI_ReceiveData(FLASH_SPI); // Manufactuer ID 0x20

   

    while(SPI_GetFlagStatus(FLASH_SPI, SPI_FLAG_TXE)==RESET){}

    SPI_SendData(FLASH_SPI,0x00); // Junk Byte

    while(SPI_GetFlagStatus(FLASH_SPI, SPI_FLAG_RXNE)==RESET){}

   

    memtype = SPI_I2S_ReceiveData(FLASH_SPI);

    while(SPI_GetFlagStatus(FLASH_SPI, SPI_FLAG_TXE)==RESET){}

    SPI_SendData(FLASH_SPI,0x00); // Junk Byte

    while(SPI_GetFlagStatus(FLASH_SPI, SPI_FLAG_RXNE)==RESET){}

    capacity = SPI_ReceiveData(FLASH_SPI);

    GPIO_SetBits(GPIOA, GPIO_Pin_4);

    vTaskDelay( 2000/ portTICK_RATE_MS );

   }

}

 

#spi #spi-cpha #spi-st32l151rb
11 REPLIES 11
gada
Associate III
Posted on April 03, 2013 at 09:40

Why no mode defined for these pins

  GPIO_InitStructure.GPIO_Pin = FLASH_SPI_MISO_PIN;

  GPIO_Init(FLASH_SPI_MISO_GPIO_PORT, &GPIO_InitStructure);

  GPIO_InitStructure.GPIO_Pin = FLASH_SPI_MOSI_PIN;

  GPIO_Init(FLASH_SPI_MOSI_GPIO_PORT, &GPIO_InitStructure);

  

heres how i use to define miso mosi pins and sck pin as well

  GPIO_InitStructure.GPIO_Pin = SPI1_SCK | SPI1_MOSI;

  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;

GPIO_Init(SPI1_GPIO, &GPIO_InitStructure);

GPIO_InitStructure.GPIO_Pin = SPI1_MISO;

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;

GPIO_Init(SPI1_GPIO, &GPIO_InitStructure);

Posted on April 03, 2013 at 10:34

Why no mode defined for these pins

Because it relies on basic fall through execution, using the structure as previously defined, just changing the pin designation.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
Posted on April 17, 2013 at 23:16

That would be correct. Our FPGA engineer wound up flipping the polarity he was requiring so that we were able to move forward. Is there any known errata for an issue like this?

Posted on April 18, 2013 at 03:07

Is it mentioned in the published errata?

I'd code review the initialization, but there are no defines.

I would also cross check things with a bit-banging implementation.
Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
Posted on April 18, 2013 at 06:30

OK so at the end of the day, do you interface to an FPGA or serial FLASH, or anything else?

JW
jpeacock2399
Associate II
Posted on April 18, 2013 at 16:29

One of the ''gotchas'' with SPI is the relationship of data to clock edge.  I use SPI with M25P64 parts on various STM32 parts, and it does work, but you have to watch out for clock edge.  From the M25P64 manual:

''For these two modes, input data is latched in on the rising edge of Serial Clock (C), and

output data is available from the falling edge of Serial Clock (C).''

The STM32 SPI only clocks data on one edge, which means you have to change the SPI port configuration when going from read to write and back to read.  CPHA is off to write on a rising edge, CPHA is on to read on a falling edge.  Make sure SPI is not busy when changing CPHA phase.  This means you can't run in bi-directional mode on SPI, no simultaneous read and write.

Some SPI peripherals only use one clock edge for in or out, but I've found that serial flash parts almost always requires two edges.

  Jack Peacock
John F.
Senior
Posted on April 18, 2013 at 17:57

That sounds wrong. I think ''output data is available from the falling edge'' means that the output data changes on the falling edge and is stable and valid during the time the rising edge occurs (when it is clocked in by the Master SPI device). I have had no problems reading and writing M24C64 device using the same SPI settings.

Time to break out the oscilloscope?

jpeacock2399
Associate II
Posted on April 18, 2013 at 21:47

It's more a question of when the SPI port samples the data line than when data is valid from the device.  The STM32 won't sample on both edges.  Yes you might get valid data in on the wrong edge but is it within the timing diagram?  Often the peripheral is just about to change data on the wrong edge, no guarantee it will always work if the SPI is sampling outside or right at the edge of the valid envelope.

  Jack Peacock
John F.
Senior
Posted on April 19, 2013 at 09:16

Correction - My reference to 24C64 is nonsense; it's an I2C device! (But I do have four different devices all running on SPI busses from an STM32F4.)

Regarding data sampling. Yes. Sampling time is the issue. I think the STM32 SPI works in the standard way and that no clock phase or polarity changes are needed. Please have another look at the actual data transfers for your device(s) with an oscilloscope - you shouldn't need to be changing clock phase or polarity to operate in full-duplex.