Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

[ARM] STM32 Spi Flash Problem

Status
Not open for further replies.

zugzwang

Newbie level 4
Joined
Mar 20, 2017
Messages
5
Helped
0
Reputation
0
Reaction score
0
Trophy points
1
Activity points
46
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:

Flash_soru.PNG

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.
 

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
 

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)
 

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
 

WhatsApp Image 2017-03-25 at 00.50.14.jpeg


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:

Ekran Alıntısı.PNG


What am I missing? :-(
 
Last edited:

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

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)
 

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
 

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.
 

Status
Not open for further replies.

Similar threads

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top