+ Post New Thread
Results 1 to 9 of 9
  1. #1
    Newbie level 4
    Points: 34, Level: 1

    Join Date
    Mar 2017
    Posts
    5
    Helped
    0 / 0
    Points
    34
    Level
    1

    STM32 Spi Flash Problem

    Hello,

    I am trying to log data via SPI to external flash with STM32F302VB.
    (Winbond W25Q32FV)

    I guess SPI section is OK, I tested it with logic analyzer and able to see the data I sent. There is no problem. But when I try to talk with flash, I see meaningless(irregular) values (like: 0xFF, 0xFF00, 0x00)

    I've read the entire 100-page datasheet but I could not find a solution cuz I'm a beginner on this topic(communication/flash)

    So, I want help with any kind of advice / sample / source you will do in this matter.


    First of all, I tried to "Read Unique ID Number" Instruction:

    Click image for larger version. 

Name:	Flash_soru.PNG 
Views:	2 
Size:	42.4 KB 
ID:	137145

    simply what I sent: (by the way, my spi_write function 8-bit)

    spi_write(0x4B);
    and 4 dummy bytes;
    spi_write(0xAA); spi_write(0xBB); spi_write(0xCC); spi_write(0xDD);

    and then read at same adress. But I get irregular values so i am confused


    my write function is:

    Code:
    void spi3_write(uint8_t data)
    {
    	uint32_t spixbase = 0x00;
    	spixbase = (uint32_t)SPI3;
    	spixbase += 0x0C;
    	
    	*(__IO uint8_t *)spixbase = data;
    	while(!(SPI3->SR & SPI_SR_TXE));
    }
    my read function is:

    Code:
    uint8_t spi3_read()
    {
    	uint32_t spixbase = 0x00;
    	//while((SPI3->SR & SPI_SR_RXNE));
    	
            spixbase = (uint32_t)SPI3; 
            spixbase += 0x0C;
            return *(__IO uint8_t *) spixbase;
    }


    Thanks for any help.

    •   Alt20th March 2017, 20:06

      advertising

        
       

  2. #2
    Advanced Member level 3
    Points: 5,390, Level: 17

    Join Date
    Jan 2015
    Posts
    778
    Helped
    254 / 254
    Points
    5,390
    Level
    17

    Re: STM32 Spi Flash Problem

    You need to understand that SPI is an exchange protocol - white you are sending the bits of a value from the master to the slave device, the slave will be sending you bits. Therefore you DON'T send values and then read values - you do it all at once.
    Typically you need just one function to perform an SPI exchange, at least from the master device's point of view. The function takes a parameter that is the value you want to send and returns the value that you have received. (By the way, this is a blocking function; there are ways to use interrupts but that is another story.)
    Therefore the function has the steps
    - check that the SPI peripheral is free and ready to start a new transfer
    - write the value you want to send to the peripheral buffer - this normally starts the exchange
    - wait until the exchange is complete
    - handle any errors that may occur (this can be skipped for initial testing but is really needed for the final version)
    - return the received value
    Then, for your purposes, to read the ID value you need a set of calls such as
    - if necessary, select the slave by lowering the \CS\ pin
    - call the function with 0x4b as the parameter and ignore the return value
    - call the function with some dummy value (I generally use 0x00 but if the slave will ignore it then anything will do) 4 times and ignore the return value
    - call the function with some dummy value 8 times but this time record each of the returned values
    - if necessary, deselect the slave device by raising the \CS\ pin
    You the need to reconstruct the unique ID value. As the data sheet shows, the value is a 64-bit number and you will get the top 8 bits first, then the next 8 bits and so on until the 8th value will be the bottom 8 bits.
    Can I suggest that you start with something a little simpler such as reading the JEDEC ID or the manufacturers ID as these sequences are a bit shorter and you have the advantage of knowing what values you should be getting back, whereas the unique ID will (be definition) change from device to device. Yes you should always get the same value back but unless you know what they should be beforehand, it is hard to know if you are getting back the correct values.
    Finally, I would suggest that you get used to reading the status register. Before you start many operations, it is often a good idea to check the status register to make sure the EEPROM is ready for the operation. For example, some operations (reset, write, erase) can take a while to perform and the chip will ignore other commands (except status register reads) while it is busy. Therefore you need to check that it is free for your command before you start sending it.
    Susan



  3. #3
    Newbie level 4
    Points: 34, Level: 1

    Join Date
    Mar 2017
    Posts
    5
    Helped
    0 / 0
    Points
    34
    Level
    1

    Re: STM32 Spi Flash Problem

    Quote Originally Posted by Aussie Susan View Post
    You need to understand that SPI is an exchange protocol - white you are sending the bits of a value from the master to the slave device, the slave will be sending you bits. Therefore you DON'T send values and then read values - you do it all at once.
    Typically you need just one function to perform an SPI exchange, at least from the master device's point of view. The function takes a parameter that is the value you want to send and returns the value that you have received. (By the way, this is a blocking function; there are ways to use interrupts but that is another story.)
    Therefore the function has the steps
    - check that the SPI peripheral is free and ready to start a new transfer
    - write the value you want to send to the peripheral buffer - this normally starts the exchange
    - wait until the exchange is complete
    - handle any errors that may occur (this can be skipped for initial testing but is really needed for the final version)
    - return the received value
    Then, for your purposes, to read the ID value you need a set of calls such as
    - if necessary, select the slave by lowering the \CS\ pin
    - call the function with 0x4b as the parameter and ignore the return value
    - call the function with some dummy value (I generally use 0x00 but if the slave will ignore it then anything will do) 4 times and ignore the return value
    - call the function with some dummy value 8 times but this time record each of the returned values
    - if necessary, deselect the slave device by raising the \CS\ pin
    You the need to reconstruct the unique ID value. As the data sheet shows, the value is a 64-bit number and you will get the top 8 bits first, then the next 8 bits and so on until the 8th value will be the bottom 8 bits.
    Can I suggest that you start with something a little simpler such as reading the JEDEC ID or the manufacturers ID as these sequences are a bit shorter and you have the advantage of knowing what values you should be getting back, whereas the unique ID will (be definition) change from device to device. Yes you should always get the same value back but unless you know what they should be beforehand, it is hard to know if you are getting back the correct values.
    Finally, I would suggest that you get used to reading the status register. Before you start many operations, it is often a good idea to check the status register to make sure the EEPROM is ready for the operation. For example, some operations (reset, write, erase) can take a while to perform and the chip will ignore other commands (except status register reads) while it is busy. Therefore you need to check that it is free for your command before you start sending it.
    Susan

    OK. I will try to read JEDEC ID.

    I think understand this now, about SPI communication isn't send & read, I should do it all once.

    So if I want to read jedec id then my function will be like:

    Code:
    uint8_t read_ID(uint8_t data)
    {
    //base config.
    	uint32_t spixbase = 0x00;
    	spixbase = (uint32_t)SPI3;
    	spixbase += 0x0C;
    	
    	*(__IO uint8_t *)spixbase = data;  // send
    	while(!(SPI3->SR & SPI_SR_TXE)); // wait till TX empty
    	while((SPI3->SR & SPI_SR_RXNE)); // wait till RX not empty
            return *(__IO uint8_t *) spixbase; // receive value
    }
    and I pass to function 0x9F;

    Code:
    // chip select pin low;
    returnVal = read_ID(0x9F); 
    chip select pin high;
    btw I know I get only last 8-bit value like this but I will try to handle it later(next step)


    Thanks for your advice really. Am I right or I need to use interrupts? Tell me about that a little more please

    (I can't try my code now, I will try it tonight and will keep inform)



  4. #4
    Advanced Member level 3
    Points: 5,390, Level: 17

    Join Date
    Jan 2015
    Posts
    778
    Helped
    254 / 254
    Points
    5,390
    Level
    17

    Re: STM32 Spi Flash Problem

    My only comment on your 'read_ID' function (which is really very close to the general purpose function I was talking about) is that you probably need to wait for the Tx buffer to be empty BEFORE you send the data.
    You can use the SPI peripheral in two ways. The way you have written it is as a 'blocking' function' which means that the application will not do anything else while the SPI exchange is in progress. This has the advantage of being very simple and great for debugging purposes.
    However, in many larger applications where the SPI exchange has to happen while other things are going on, then you need to use interrupts. The STM32 environment provided by ST does contain the Hardware Abstraction Layer (HAL) libraries (amongst other things) and their STcube environment helps a lot by generating a lot of code for you that uses the HAL. It can generate the ISR code and the documentation tells you about the functions you need to call to read and write your data.
    Start with the blocking versions you have now until you are familiar with the concepts behind using the EEPROM. After that you can branch out to using interrupts.
    Susan



    •   Alt21st March 2017, 22:53

      advertising

        
       

  5. #5
    Newbie level 4
    Points: 34, Level: 1

    Join Date
    Mar 2017
    Posts
    5
    Helped
    0 / 0
    Points
    34
    Level
    1

    Re: STM32 Spi Flash Problem

    Click image for larger version. 

Name:	WhatsApp Image 2017-03-25 at 00.50.14.jpeg 
Views:	6 
Size:	103.5 KB 
ID:	137337


    First signal is DATA IN,

    bottom signal is CLK,

    I am trying to send 0x9F (1001 1111)


    and I think its OK?

    But when I check Data Out pin of flash, i see 0xFF first for 1-2 times, and then nothing.

    But I need to see 0xEF:

    Click image for larger version. 

Name:	Ekran Alıntısı.PNG 
Views:	3 
Size:	131.0 KB 
ID:	137336


    What am I missing?
    Last edited by zugzwang; 25th March 2017 at 14:14.



  6. #6
    Super Moderator
    Points: 231,463, Level: 100
    Awards:
    1st Helpful Member

    Join Date
    Jan 2008
    Location
    Bochum, Germany
    Posts
    39,962
    Helped
    12204 / 12204
    Points
    231,463
    Level
    100

    Re: STM32 Spi Flash Problem

    Can't see if chip select is operated correctly. Why is it out-commented in post #3?



  7. #7
    Newbie level 4
    Points: 34, Level: 1

    Join Date
    Mar 2017
    Posts
    5
    Helped
    0 / 0
    Points
    34
    Level
    1

    Re: STM32 Spi Flash Problem

    Quote Originally Posted by FvM View Post
    Can't see if chip select is operated correctly. Why is it out-commented in post #3?
    It's my mistake when I use # code block, CS pin procedure is OK (also I check it on keil-debug-registers-ODR)



  8. #8
    Advanced Member level 3
    Points: 5,390, Level: 17

    Join Date
    Jan 2015
    Posts
    778
    Helped
    254 / 254
    Points
    5,390
    Level
    17

    Re: STM32 Spi Flash Problem

    When you read the JEDEC ID you need 4 exchanges. The first will send the 0x9f command to the EEPROM and the next 3 will read back the values. Therefore the code wil look something like (using your function name and assuming it is working correctly)):
    Code:
    <select the EEPROM by lowering the \CS\ line>
    read_id(0x9f);   // Send the command
    manufacturer_id = read_ID(0x00);   // Dummy send, read back the manufacturer ID value
    memory_type = read_ID(0x00);      // Another dummy send, read back the memory type value
    capacity = read_ID(0x00);              // Again a dummy send to read back the capacity value
    <Deselect the EEPROM by raising the \CS\ line>
    Susan



    •   Alt26th March 2017, 22:50

      advertising

        
       

  9. #9
    Newbie level 4
    Points: 34, Level: 1

    Join Date
    Mar 2017
    Posts
    5
    Helped
    0 / 0
    Points
    34
    Level
    1

    Re: STM32 Spi Flash Problem

    Quote Originally Posted by Aussie Susan View Post
    When you read the JEDEC ID you need 4 exchanges. The first will send the 0x9f command to the EEPROM and the next 3 will read back the values. Therefore the code wil look something like (using your function name and assuming it is working correctly)):
    Code:
    <select the EEPROM by lowering the \CS\ line>
    read_id(0x9f);   // Send the command
    manufacturer_id = read_ID(0x00);   // Dummy send, read back the manufacturer ID value
    memory_type = read_ID(0x00);      // Another dummy send, read back the memory type value
    capacity = read_ID(0x00);              // Again a dummy send to read back the capacity value
    <Deselect the EEPROM by raising the \CS\ line>
    Susan

    Thank you Susan.

    My problem solved finally.

    You have to clear MODER register before you set if you work with PA15. It was my CS pin. I checked all of my SPI registers but I don't care GPIO that much and it dropped me to trap.

    By the way my final Read Jedec ID function is:

    Code:
    // 8.2.27. Read JEDEC ID (0xEF, 0x60, 0x16 (p.22/91))
    void read_Jedec_ID(uint8_t* d)
    {
      uint8_t i=0;
      CS_Low();
      spi3_write(CMD_JEDEC_ID);
      for (i =0; i<3; i++) 
     {
        d[i] = spi3_write(0x00);
      } 
      CS_High();
    }
    and my spi3_write function is:

    Code:
    uint8_t spi3_write(uint8_t data)
    {
    	uint32_t spixbase = 0x00;
    	spixbase = (uint32_t)SPI3;
    	spixbase += 0x0C;
    
    	*(__IO uint8_t *)spixbase = data;
    	
    	while(!(SPI3->SR & SPI_SR_TXE));
    	while((SPI3->SR & SPI_SR_RXNE) != SPI_SR_RXNE){}
    	return *(__IO uint8_t *)spixbase;
    }

    Thanks again to everyone who is try to help.



--[[ ]]--