Electronics > Projects, Designs, and Technical Stuff
Trouble when bit banging SST39SF040A
NivagSwerdna:
I have a SST39SF040A (512K x 8 ) flash which I am trying to program and it is misbehaving.... some bytes seem to stick whereas other ones don't work out...
If I program...
I intended to program...
--- Code: ---00004000 : 1D C7 48 C6 35 CC EF C7 C5 CA DF CA 70 CF 23 CB 9C C8 9C C7 74 C7 1F C8 0C C7 7F C7 C9 C7 32 C8
00004020 : 1B C7 42 C8 01 D7 D4 FF D7 FF DA FF 94 D2 F8 D6 7E C9 9E C9 44 C7 A7 C5 6F C7 84 C9 DD FF BF FF
00004040 : C2 FF 9E CA 50 C5 0B DB 9E DB 2A DB 00 00 64 D2 85 D2 24 DE 45 DF BF D8 A0 DE 9E DF A5 DF EE DF
00004060 : 48 E0 E6 D6 54 D6 49 D3 85 D6 63 D6 C4 D5 D8 D5 04 D6 0F D6 79 3E D7 79 27 D7 7B FF D8 7B E3 D9
00004080 : 7F 2D DE 50 D8 CE 46 D5 CE 7D 66 DE 5A E7 CD 64 05 CF 45 4E C4 46 4F D2 4E 45 58 D4 44 41 54 C1
...
--- End code ---
then when verifying (* means mismatch)
--- Code: ---00004000 : 00*C7 40*C6 15*CC EF C7 84*CA C0*CA 60*CF 02*CB 8C*C8 8C*C7 04*C7 0F*C8 0C C7 0F*C7 C9 C7 02*C8
00004020 : 1A*C7 42 C8 01 D7 D4 FF D7 FF DA FF 84*D2 00*D6 0A*C9 8A*C9 40*C7 A4*C5 66*C5*80*C9 DD FF BF FF
00004040 : C2 FF 1C*CA 50 C5 01*DB 98*DB 20*DB 00 00 40*D2 00*D2 04*DE 45 DF B6*D8 80*DE 98*DF 85*DF 28*C0*
00004060 : 08*E0 E0*D6 54 D6 09*D3 85 D6 61*D6 C4 D5 D8 D5 04 D6 01*D6 79 34*D7 79 25*D7 7B 36*D8 7B 01*D8*
00004080 : 7F 25*DE 50 C8*CE 46 C5*CE 7D 20*DE 5A C6*CD 64 05 CE*45 4E C4 46 4F D2 4E 45 58 D4 44 41 54 C1
--- End code ---
So some bytes are correct... in fact some runs of bytes are correct... but some are not!
My current code, with some defensive delays, is...
--- Code: ---void flashProgramByte2(ADDRESS_T address, uint8_t data) {
// Check FLASH is very off
nOE_Set();
nCE_Set();
nWE_Set();
setDataForWrite();
setAddress(0x5555);
writeData(0xAA);
nWE_Clear();
nCE_Clear();
// TWP 40ns
SysTick_Wait1us();
nWE_Set();
nCE_Set();
// TWPH
SysTick_Wait1us();
setAddress(0x2AAA);
writeData(0x55);
nWE_Clear();
nCE_Clear();
// TWP
SysTick_Wait1us();
nWE_Set();
nCE_Set();
// TWPH 40ns
SysTick_Wait1us();
setAddress(0x5555);
writeData(0xA0);
nWE_Clear();
nCE_Clear();
// TWP
SysTick_Wait1us();
nWE_Set();
nCE_Set();
// TWPH
SysTick_Wait1us();
setAddress(address);
writeData(data);
nWE_Clear();
nCE_Clear();
// TWP
SysTick_Wait1us();
nWE_Set();
nCE_Set();
// TBP 20us
for (int i=0; i<20; i++) SysTick_Wait1us();
}
--- End code ---
The wait at the end should be sufficient (matches datasheet) and in reality my program then does some serial IO for the next byte so there is a huge delay between calls. This is running at 48MHz on a ATSAMC21G18A and 1/f gives 20.8ns per instruction if it were one cycle... so nothing can happen faster than that.
Very confused.
Thanks in advance
rhodges:
It looks like your flash is wearing out. If you write 0xff to an area, you will probably see a lot of zero bits.
Second guess is maybe a problem with the voltage for the flash charge pump?
NivagSwerdna:
Surprisingly I managed to get to work by changing the code to...
--- Code: ---void flashProgramByte2(ADDRESS_T address, uint8_t data) {
// Check FLASH is very off
nOE_Set();
nCE_Set();
nWE_Set();
setDataForWrite();
setAddress(0x5555);
writeData(0xAA);
nWE_Clear();
nCE_Clear();
// TWP 40ns
nCE_Clear();
nCE_Clear();
nWE_Set();
nCE_Set();
// TWPH
nCE_Set();
nCE_Set();
setAddress(0x2AAA);
writeData(0x55);
nWE_Clear();
nCE_Clear();
// TWP
nCE_Clear();
nCE_Clear();
nWE_Set();
nCE_Set();
// TWPH 40ns
nCE_Set();
nCE_Set();
setAddress(0x5555);
writeData(0xA0);
nWE_Clear();
nCE_Clear();
// TWP
nCE_Clear();
nCE_Clear();
nWE_Set();
nCE_Set();
// TWPH
nCE_Set();
nCE_Set();
setAddress(address);
writeData(data);
nWE_Clear();
nCE_Clear();
// TWP
nCE_Clear();
nCE_Clear();
nWE_Set();
nCE_Set();
// TBP 20us - Super Long Time!
for (int i=0; i<20; i++) SysTick_Wait1us();
}
--- End code ---
There must be some constraint which is not documented in the datasheet since it says TWPH Min 30ns with no maximum; however looks like 1us is too long. 2 instructions worth seems to work.
Mysterious.
bson:
--- Quote from: NivagSwerdna on August 18, 2020, 05:33:36 pm ---Surprisingly I managed to get to work by changing the code to...
--- Code: ---void flashProgramByte2(ADDRESS_T address, uint8_t data) {
// Check FLASH is very off
nOE_Set();
nCE_Set();
nWE_Set();
setDataForWrite();
setAddress(0x5555);
writeData(0xAA);
nWE_Clear();
nCE_Clear();
--- End code ---
--- End quote ---
Try using WE to strobe the data, something like:
--- Code: --- nOE_Set();
nCE_Clear();
nWE_Set();
setDataForWrite();
setAddress(0x5555);
nWE_Clear();
writeData(0xAA);
nWE_Set();
// ... more ...
nCE_Set();
--- End code ---
Here's code I have to write the same flash. Obviously a very different library. It polls for the write to finish at the end (using SysTimer to time out to avoid getting stuck).
--- Code: ---bool Writer::WriteByte(uint32_t addr, uint8_t byte) {
// Deassert CE#, OE#, WE#
Pin_OEn::set(true);
Pin_CEn::set(true);
Pin_WEn::set(true);
Pin_CEn::set(false);
// Unlock and write byte
Port_DB::P_DIR = 0xff; // Make port output
SetAddr(0x5555);
Pin_WEn::set(false);
Port_DB::P_OUT = 0xaa;
Pin_WEn::set(true);
SetAddr(0x2aaa);
Pin_WEn::set(false);
Port_DB::P_OUT = 0x55;
Pin_WEn::set(true);
SetAddr(0x5555);
Pin_WEn::set(false);
Port_DB::P_OUT = 0xa0;
Pin_WEn::set(true);
SetAddr(addr);
Pin_WEn::set(false);
Port_DB::P_OUT = byte;
Pin_WEn::set(true);
// Wait for write to finish by repeatedly reading the byte until BIT7 isn't inverted.
const SysTimer::Future deadline = SysTimer::future(TIMER_USEC(200));
const uint8_t bit7 = byte & BIT7;
Pin_CEn::set(true);
Pin_OEn::set(true);
Port_DB::P_DIR = 0x00; // Make port input
//SetAddr(addr);
uint8_t data;
do {
Pin_CEn::set(false);
Pin_OEn::set(false);
data = Port_DB::P_IN;
Pin_CEn::set(true);
Pin_OEn::set(true);
} while ((data & BIT7) != bit7 && !SysTimer::due(deadline));
return (data & BIT7) == bit7;
}
--- End code ---
bson:
By the way, I think the Cypress S29GL064S80TFIV10 is a better part. It's significantly bigger (8M * 8 or 4M * 16) and more importantly MUCH faster to program. It has both an "unlock bypass" mode where you unlock it once then keep writing without having to unlock it for each byte, and a "buffered write" where you tell it how many bytes to write (up to 128) and then just clock them out and wait for it to finish. This is MUCH faster when bit banging. As in, like 6-10x faster. With a lot of µC's it can also be done with a timer feeding a write strobe (WE#) pin and triggering a DMA controller. Super nice when you have to be responsive to things like USB bus enumeration or suspend/resume at any arbitrary time (including in the middle of a USB-driven write).
Navigation
[0] Message Index
[#] Next page
Go to full version