Skip to main content
matt239955_stm1_stmicro
Associate
March 29, 2013
Question

SPI Communication Issues

  • March 29, 2013
  • 11 replies
  • 2963 views
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
This topic has been closed for replies.

11 replies

gada
Associate III
April 3, 2013
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);

Tesla DeLorean
Guru
April 3, 2013
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 (See Profile) Up vote any posts that you find helpful, it shows what's working..
matt239955_stm1_stmicro
Associate
April 17, 2013
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?

Tesla DeLorean
Guru
April 18, 2013
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 (See Profile) Up vote any posts that you find helpful, it shows what's working..
waclawek.jan
Super User
April 18, 2013
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 III
April 18, 2013
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.
Associate III
April 18, 2013
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 III
April 18, 2013
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.
Associate III
April 19, 2013
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.

oversc0re
Associate II
July 8, 2015
Posted on July 08, 2015 at 14:58

Jack thank you for this post. My driver with SPI mode 0 worked for quite some time :) but now I found a couple of devices that have some problems and I think edge sampling might be the problem. 

If you are still active here on this forum I'd like to ask you, how did you handle the switch from mode 0 to mode 3. 

I asserted CS, sent command and address with mode 0, changed to mode 1 (waited until SPI is busy) and tried to read the data. Nothing useful comes out. Could you please comment on this?

Thanx,

Oversc0re