Trouble when bit banging SST39SF040A - Page 1
Forum section: electronics / projects

author: NivagSwerdna
author_rank: Super Contributor
timestamp: August 18, 2020, 10:59:02 am
content: 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 C800004020 : 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 FF00004040 : 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 DF00004060 : 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 D900004080 : 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...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*C800004020 : 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 FF00004040 : 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 C1So 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 offnOE_Set();nCE_Set();nWE_Set();setDataForWrite();setAddress(0x5555);writeData(0xAA);nWE_Clear();nCE_Clear();// TWP 40nsSysTick_Wait1us();nWE_Set();nCE_Set();// TWPHSysTick_Wait1us();setAddress(0x2AAA);writeData(0x55);nWE_Clear();nCE_Clear();// TWPSysTick_Wait1us();nWE_Set();nCE_Set();// TWPH 40nsSysTick_Wait1us();setAddress(0x5555);writeData(0xA0);nWE_Clear();nCE_Clear();// TWPSysTick_Wait1us();nWE_Set();nCE_Set();// TWPHSysTick_Wait1us();setAddress(address);writeData(data);nWE_Clear();nCE_Clear();// TWPSysTick_Wait1us();nWE_Set();nCE_Set();// TBP 20usfor (int i=0; i<20; i++) SysTick_Wait1us();}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

author: rhodges
author_rank: Frequent Contributor
timestamp: August 18, 2020, 02:18:51 pm
content: 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?

author: NivagSwerdna
author_rank: Super Contributor
timestamp: August 18, 2020, 05:33:36 pm
content: 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 offnOE_Set();nCE_Set();nWE_Set();setDataForWrite();setAddress(0x5555);writeData(0xAA);nWE_Clear();nCE_Clear();// TWP 40nsnCE_Clear();nCE_Clear();nWE_Set();nCE_Set();// TWPHnCE_Set();nCE_Set();setAddress(0x2AAA);writeData(0x55);nWE_Clear();nCE_Clear();// TWPnCE_Clear();nCE_Clear();nWE_Set();nCE_Set();// TWPH 40nsnCE_Set();nCE_Set();setAddress(0x5555);writeData(0xA0);nWE_Clear();nCE_Clear();// TWPnCE_Clear();nCE_Clear();nWE_Set();nCE_Set();// TWPHnCE_Set();nCE_Set();setAddress(address);writeData(data);nWE_Clear();nCE_Clear();// TWPnCE_Clear();nCE_Clear();nWE_Set();nCE_Set();// TBP 20us - Super Long Time!for (int i=0; i<20; i++) SysTick_Wait1us();}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.

author: bson
author_rank: Unknown
timestamp: August 20, 2020, 12:53:31 am
content: Quote from: NivagSwerdna on August 18, 2020, 05:33:36 pmTry 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();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 bytePort_DB::P_DIR = 0xff; // Make port outputSetAddr(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;}

author: bson
author_rank: Unknown
timestamp: August 20, 2020, 01:35:05 am
content: By the way, I think theCypress S29GL064S80TFIV10is 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).

author: NivagSwerdna
author_rank: Super Contributor
timestamp: August 20, 2020, 09:13:51 am
content: Quote from: bson on August 20, 2020, 01:35:05 amThat sounds perfect for my application. Will check that out for the next rev.