M25P16 SPI flash memory + LPC1769 - prototype work great, designed PCB not so good...

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

M25P16 SPI flash memory + LPC1769 - prototype work great, designed PCB not so good...

2,397 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by teslabox on Sun Apr 03 04:51:48 MST 2016
Hi everyone!

I need to use Micron M25P16 Serial Flash Embedded Memory with 16 Mb (2 MB) of space.
It communicates used SPI interface up to 75 MHz clock signal.

First I made a prototype universal PCB (one layer, THT, 2.54 mm raster/grid) with +3,30 DC V from my LPCXpresso LPC1769 Rev. C PCB
and pull-up 10 kOhm resistors at W# (not Write Protect) and HOLD# (not Hold) pins and pull-up 100 kOhm resistor at S# (not Chip Select)
and pull-down 100 kOhm resistor at C (serial Clock) according to the "Figure 5: Bus Master and Memory Devices on the SPI Bus"
on the page no 10 in the datasheet of Micron M25P16. Also I added serial 100 Ohm resistor at C (serial Clock) line to reduce generating noise from

this signal to the other lines of SPI interface (MOSI and MISO lines).

I connected the prototype PCB with M25P16 memory to the LPCXpresso LPC1769 using female-female universal pigtails (with ca. 20-25 cm long).
I wrote proper code in ANSI C according to the flash memory commands in the datasheet and it works proper up to 500 kHz of clock speed.

I use commands as follows:
- READ IDENTIFICATION,
- READ STATUS REGISTER,
- WRITE ENABLE,
- WRITE DISABLE,
- READ DATA BYTES,
- SECTOR ERASE
- PAGE PROGRAM.

On the beginning it is enough for me.
Everything works very good - no failures/error, every command it recognizable by memory and gives answer from it.
Also I prepared some ANSI C code with slower SPI clock 10 kHz, 25 kHz, 50 kHz, 100 kHz, 200 kHz - all of them works very good.



In next step I designed a PCB and after assembly all electronics parts it turned out that there are some troubles with communication with M25P16

flash memory. Sometimes it works properly some time not - something like memory does not recognize commends...? and gives no answer
I checked SPI lines with oscilloscope and the SPI lines during sending commands look quite good but there is no answer...
Lengths of SPI traces on the PCB are ca. 20-30 mm from LPCXpresso LPC1769 goldpin connectors and I used round corners routing pull-up and pull-down

resistors are the same, 100 Ohm serial resistor on serial Clock line is also the same, decoupling 100 nF/100 V + 1 uF/50 V MLCC ceramic resistors

on Vcc power pin are the same... Even I slow down clock speed up to only 10 kHz... no positive changes.
I use 2-layer PCB with 20 mils width of traces and 10 mils clearance between signal traces and GDN polygon and signal to signal traces.

Do you have any suggestions what I can check more or what I can do in this situation?
If you need more information from me I will write all them below.
Labels (1)
0 Kudos
Reply
15 Replies

1,825 Views
lpcware
NXP Employee
NXP Employee
bump
0 Kudos
Reply

1,825 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by teslabox on Thu May 05 06:32:35 MST 2016
Hi IanB,

I added checking WIP bit in M25P16 flash memory Status Register after Write Command sequence and it works great at 25 MHz! :)


Quote:
Also, on most of these types of memory, you have to set the write-enable bit EVERY time you write to it. It resets to "disabled" as soon as the write is finished.


I do it before Write Command sequence every time (before every Write Command sequence).

Now I can go further with my device/project.

Best regards and many thanks for disccusion and your help and support.

0 Kudos
Reply

1,825 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by IanB on Thu May 05 04:05:11 MST 2016
Also, on most of these types of memory, you have to set the write-enable bit EVERY time you write to it. It resets to "disabled" as soon as the write is finished.

I was very recently using a 4 Mbit device - I started with the Microchip part and then switched to a device made by Adesto technologies (never heard of them before) because the Microchip part had a non-standard command set. The Adesto part worked immediately. The Microchip part didn't. I have also used Spansion with success in devices up to 1G bit.

I was going to suggest trying a part from a different manufacturer, but if you have sorted out the status register then it will probably work.
0 Kudos
Reply

1,825 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by teslabox on Wed May 04 12:35:23 MST 2016
IanB, I am grateful very much for your help and support in this case.

Following your advice:
I put Timer0 delay instead Busy bit checking. I put 500 ms delay before !CS line goes high and in second test 100 mstime delay.
No changes... works good up to 666 kHz but over... I always get 0xFF of byte value instead increasing number 0x01, 0x02, 0x03, etc...

My source file is in the attachement.
I really do not have more ideas...

--------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------------

I thought about all these things and I figured out one important thought:
First of all: I can read Unique ID of M25P16 flash memory at all clock speeds which I tested (500 kHz, 800 kHz, 1 MHz, 2 MHz) and there were no errors or anything wrong, UID (4 bytes) is 0x20 0x20 0x15 0x00, I read it all the time and it is OK - independent on clock speed.

UID read out sequence looks very similar to Read Data Bytes command sequence - there is no difference in structure in the C code (except of commands value, etc.)

I looked into "main.c" file and I analyzed it.
I found these lines:

SectorErase_CMD (0);// SECTOR ERASE - COMMAND
WriteByte (0x00000000, i);// PAGE WRITE/WRITE BYTE - COMMAND
Byte = ReadByte (0x00000000);// READ BYTE - COMMAND


First I erase whole zero sector - to be able to write whatever into this sector (according to the M25P16 Micron datasheet),
next I write a 8-bit number to address 0x00000000
and next (in third line) I quickly (imiedetely) read out byte value.

Let's go further:
There is a Status Register in the M25P16 flash memory with bit no 0 Write In Proggres bit (WIP bit).
This register and this bit is described on page 22 and 23 of datasheet.
But on page 28 of the same datasheet there is described Page Proggram sequence and somewhere in the middle of this page/sheet is written how to proggraming the page of memory with WIP bit usage - to wait until the device will finished writting process before the nex command/sequence and do not lose the data byte.

Probably (I guess 99%) that is the solution and answer why I get 0xFF when I read the data byte -
I read erased data byte (0xFF), then I write something - I do not wait until device will finish (now written data are broken) and I read data byte as 0xFF.

I will try test my theory tommorom in the morning and I let you now IanB.

Additionally on the page 40 in Table 17 there are shown instruction times e.g. Sector Erase and Page Program.
0 Kudos
Reply

1,825 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by IanB on Wed May 04 03:07:55 MST 2016
I bet it's getting annoying.

What happens if you wait for *AGES* (some absurd amount of time) before returning CS high?
0 Kudos
Reply

1,825 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by teslabox on Wed May 04 02:35:17 MST 2016
Hi IanB,

I made changes in "flash_memory_spi.c" source file as you suggested - to check Busy bit (bit ni 4 in Status Register SPI/SSP0) before !CS line goes high as follows:

#if BUSY_BIT_CHECK == 1
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////// CHECKING BUSY BIT - BEGIN ////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Check Busy bit (bit no 4) in SPI/SSP0 Status Register - if SPI/SSP0 master is not busy after sending data bytes,
// if SPI/SSP0 master in not busy then !CS line can go high and make master SPI ready to receiving data bytes from slave SPI
// Busy bit = 0 - idle (delaulf/reset value)
// Busy bit = 1 - sending/receiving
while ( ((LPC_SSP0->SR & (1 << 4)) >> 4) == 1 ) // wait until Busy bit is "1"
{
// do nothing - wait if Busy bit (bit no 4) is "1" ("1" means the SSP master is currently sending or receiving data bytes)
// Default/reset value Busy bit is "0"
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////// CHECKING BUSY BIT - END ////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#endif


I do line:
while ( ((LPC_SSP0->SR & (1 << 4)) >> 4) == 1 )

where I read Status Register value, ANDing with (1<<4) and shift 4 bits left and compare it to "1".

I tun this code but there is no result/differences - behaviour is still the same up to 666 kHz works OK but over 666 kHz does not work properly.
maybe I do something wrong in my checking Busy bit?
C code file is in the attachement.
0 Kudos
Reply

1,825 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by IanB on Sat Apr 30 06:22:12 MST 2016
on this line:
while((LPC_SSP0->SR & (1 << 2)) == 0); // wait until byte is received


You are checking the Receive FIFO Not Empty bit.

Before you let CS go high, you should also check the Busy bit (bit 4) - the busy bit doesn't go to zero until the SPI has completely finished what it is doing.

Don't bother taking out the pull-up, I'm just saving you the £0.0009 that it costs! The line is driven both high and low and never floats, so the pull-up doesn't do anything.
0 Kudos
Reply

1,825 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by teslabox on Sat Apr 30 04:01:16 MST 2016
Hi IanB,

Thank you for your support in this case.

If the CS edge is BEFORE the last clock has finished then the memory hasn't noticed it, and thinks CS has remained low throughout.

It is something strange because...

As you can see on the oscilloscope screens (in my previous reply) I got proper answer from my memory only when !CS line goes high to +Vcc (+3,3 V) before last falling edge of CLK signal. When !CS signal goes high after the last falling edge of CLK signal then the data is invalid - then I get 0xFF (data byte vaue).
It is exactly oposite as it should be... (?!) I am a little bit confused of that.

I found that on an LPC15xx the automatic generation of CS doesn't work - I bet the 17 is the same. Switch that pin back to GPIO and do it manually. 

I drive the !CS line manually all the time. I connected !CS memory line to the P0.16 pin as GPIO OUTPUT with internal pul-up resistor (default value). I do not use this pin as SSEL0 of SPI0 built-in. You can see it in my ANSI C code in attachements in previous reply
To drive this GPIO OUTPUT pin I use FIODIR (to make it output), FIOSET (to make it high level) and FIOCLR (to make it low level) registers.
But additionaly I connected external pull-up 10 kOhm resistor.
I will try to remove my externall pull-up 10 kOhm resistor and I will check it again with a few speed of CLK (frequencies): 400, 500, 666, 800 and 1000 kHz.

For me the most strange thing is moving !CS rising edge on last falling CLK signal (I marked it on the oscilloscope screens in my prevoipus reply in the attachement).
0 Kudos
Reply

1,825 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by IanB on Thu Apr 28 23:02:02 MST 2016
In a lot of these memories CS should not be returned V+ until the entire transaction is finished. When it sees CS go high, it thinks you have finished and shuts down to wait for another command. If, after that point, you try to clock out data from the memory you will just get 0x00 or 0xFF depending where the pull-up goes, or, if there is no pull-up, depending on where the line floats to.

If that CS pulse is between the command byte and the data bytes then that explains why it fails. If the CS edge is BEFORE the last clock has finished then the memory hasn't noticed it, and thinks CS has remained low throughout.

I found that on an LPC15xx the automatic generation of CS doesn't work - I bet the 17 is the same. Switch that pin back to GPIO and do it manually. (And it doesn't need a pull-up - it's an OUTPUT fully driven in both directions) Check the idle bit after the last byte in the transaction and then return the line to V+
0 Kudos
Reply

1,825 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by teslabox on Thu Apr 28 06:30:10 MST 2016
Hi,

I made changes on my prototype board with M2516P:
- no series 100 Ohm resistor on SCK (serial clock) line,
- no pull-down 100 kOhm resistor on SCK line,
- changed pull-up resistor on !CS line from 100 kOhm to 10 kOhm,

I connected two oscilloscope probes to !CS and SCK lines and set SPI/SSP0 clock speeds as follows:
- 400 kHz,
- 500 kHz,
- 666 kHz,
- 800 kHz,
- 1 MHz.

I saved the oscillographs and compared them.

The result are shown below in the picture in the attachement.

I noticed that the faster the SCK signal then more shifted !CS (high level) to right side.
When the !CS signal is shifted over the last SCK the read value is failed....
I am wondering why it happens? Why !CS depends on SCK speed... ?

Maybe it is happening because I use !CS line as GPIO as output and I drive this pin by my own in the code... Maybe GPIO is not so fast as should be as !CS line os SPI interface... ?
Maybe manual GPIO as !CS line driving is incorrect by my side... but up to 800 kHz is OK.

In the attachement are also my libraries to ssp and flash memory with ANSI C code for LPC1769.
0 Kudos
Reply

1,825 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by teslabox on Wed Apr 27 22:42:13 MST 2016
Hi there!


Quote:
reduce the CS pull up resistor to 10K.


Ok, maybe this is it. I followed in the footsteps and I found/read in the Micron M25P16 datasheet (on page 10, notes 4 and 5) - something about pull-up resistor  valueo on !CS line in connection to line capacity and maximum timing.
I reduce this pull-up resistor to 10 kOhm and check it again.

remove the 100K clock resistor, there is no need for this.

Ok, I will remove this pull-down 100 kOhm resistor for tests.
any series resistor should be very small, less than 33 ohms (just short it out for now)

For test I will short it (just 0 Ohm).
0 Kudos
Reply

1,825 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by rocketdawg on Wed Apr 27 08:26:09 MST 2016
reduce the CS pull up resistor to 10K.
remove the 100K clock resistor, there is no need for this.
any series resistor should be very small, less than 33 ohms (just short it out for now)

The maximum SSPx speed is 33Mbit/s in master mode and you should only need a pull up resistor on CS.
directly connect the other three signals.
you do not need any series resistors unless you see ringing on MOSI, MISO, SCK. (and you probably will not).
then add some very small series resistors.

If you were running at 75Mhz, then that might be a different story.
0 Kudos
Reply

1,825 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by IanB on Wed Apr 27 06:27:59 MST 2016
DO the waveforms look OK on the scope?
0 Kudos
Reply

1,825 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by teslabox on Wed Apr 27 06:11:38 MST 2016
Hi IanB,

I run M25P16 flash memory at 500 kHz clock on my prototype board (with small cables between PCB LPC Xpresso LPC1769 and my prototype flash memory board) and I read Unique ID, write some value at  byte addres 0x00 and later I read value from byte address 0x00.
At 500 kHz everything is OK, Unique ID is OK, WriteCommand is OK and ReadCommand is OK and finally read value is OK.
But if I just do... higher clock - 1 MHz or higher then... Unique ID is OK but read value of byte is always 0xFF... I can't figure it out what's wrong and fix it...
Is there any difference between reading Unique ID and Read Byte value maybe?
0 Kudos
Reply

1,825 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by IanB on Sun Apr 03 14:41:39 MST 2016
Just a suggestion, because I found this with an Xpansion serial-flash and an LPC15xx processor; but check the CS line. The automatic control of CS in the LPC15 doesn't work - I wonder if the LPC17 is the same - I had to rewrite it and control CS as a GPIO pin. It was giving random errors and was tricky to find. It gets into a mess whenever there is an interrupt.

Not sure about the 100Ω series resistor on CLK - you won't need much capacitance on that line at 75MHz before it gets into trouble (although it won't make much difference below 1MHz)

I connected Hold and Write Protect straight to V+ - I can't see any reason for pull-up resistors - just looks like somewhere high-frequency edges can get coupled in where you don't want them.
0 Kudos
Reply