Electronics > Projects, Designs, and Technical Stuff

Trouble when bit banging SST39SF040A

(1/2) > >>

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

There was an error while thanking
Thanking...
Go to full version
Powered by SMFPacks Advanced Attachments Uploader Mod