grigorig / stcgal

Open Source STC MCU ISP flash tool
663 stars 137 forks source link

EEPROM is not erased, cannot be rewritten #59

Closed PSLLSP closed 3 years ago

PSLLSP commented 4 years ago
$ stcgal -V
stcgal 1.6

When I flash EEPROM second file to stcgal to empty chip, it works, no problem ($ stcgal -p /dev/ttyUSB0 program.hex eeprom.hex). When I try upload EEPROM second time, I receive error Protocol error: incorrect magic in write packet. When I check EEPROM area, it was not erased so I think that error means that EEPROM cannot be written because that area is not blank. I can repeat this problem with STC15F104W and STC15W408AS.

$ stcgal -p /dev/ttyUSB0 flash-dump.ihx 80.hex 
Waiting for MCU, please cycle power: done
Protocol detected: stc15
Target model:
  Name: STC15W408AS
  Magic: F51F
  Code flash: 8.0 KB
  EEPROM flash: 5.0 KB
Target frequency: 11.021 MHz
Target BSL version: 7.2.5T
Target wakeup frequency: 36.050 KHz
Target options:
  reset_pin_enabled=False
  clock_source=internal
  clock_gain=high
  watchdog_por_enabled=False
  watchdog_stop_idle=True
  watchdog_prescale=256
  low_voltage_reset=True
  low_voltage_threshold=3
  eeprom_lvd_inhibit=True
  eeprom_erase_enabled=False
  bsl_pindetect_enabled=False
  por_reset_delay=long
  rstout_por_state=high
  uart2_passthrough=False
  uart2_pin_mode=normal
  cpu_core_voltage=unknown
Loading flash: 662 bytes (Intel HEX)
Loading EEPROM: 1 bytes (Intel HEX)
Trimming frequency: 11.021 MHz
Switching to 19200 baud: done
Erasing flash: done
Writing flash:  93%|████████████████████████████████████████████████████████████████████████████████████      | 8128/8704 [00:08<00:00, 997.68 Bytes/s]Protocol error: incorrect magic in write packet
Disconnected!
Writing flash:  94%|████████████████████████████████████████████████████████████████████████████████████▋     | 8192/8704 [00:08<00:00, 997.12 Bytes/s]

Tail of flashing process in DEBUG mode (stcgal -D -p /dev/ttyUSB0 flash-dump.ihx 80.hex ):

^MWriting flash:  90%|█████████ | 7872/8704 [00:07<00:00, 1000.00 Bytes/s]-> Packet data: 46 B9 6A 00 4B 02 1E C0 5A A5 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 02 94 16
<- Packet data: 46 B9 68 00 08 02 54 00 C6 16
-> Packet data: 46 B9 6A 00 4B 02 1F 00 5A A5 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 D5 16
<- Packet data: 46 B9 68 00 08 02 54 00 C6 16
^MWriting flash:  92%|█████████▏| 8000/8704 [00:07<00:00, 1000.03 Bytes/s]-> Packet data: 46 B9 6A 00 4B 02 1F 40 5A A5 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 02 15 16
<- Packet data: 46 B9 68 00 08 02 54 00 C6 16
-> Packet data: 46 B9 6A 00 4B 02 1F 80 5A A5 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 02 55 16
<- Packet data: 46 B9 68 00 08 02 54 00 C6 16
^MWriting flash:  93%|█████████▎| 8128/8704 [00:08<00:00, 999.99 Bytes/s] done
-> Packet data: 46 B9 6A 00 4B 02 1F C0 5A A5 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 02 95 16
<- Packet data: 46 B9 68 00 08 02 54 00 C6 16
-> Packet data: 46 B9 6A 00 4B 02 20 00 5A A5 45 45 50 52 4F 4D 20 73 74 61 72 74 73 20 48 45 52 45 0A FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 34 80 16
<- Packet data: 46 B9 68 00 08 02 46 00 B8 16
Protocol error: incorrect magic in write packet
-> Packet data: 46 B9 6A 00 07 82 00 F3 16
Disconnected!
^MWriting flash:  94%|█████████▍| 8192/8704 [00:08<00:00, 999.43 Bytes/s]

Issue #58 has program flash-dump.c that can be used to troubleshot this issue (to dump EEPROM area to serial port)

I erased the chip in Windows with STC-ISP. Then I prepared EEPROM file with 0xff data:

$ cat eeprom-ff.hex
:10000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00
:10001000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0
:10002000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE0
:10003000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD0
:10004000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC0
:10005000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB0
:10006000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA0
:10007000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF90

I can write this file with stcgal again and again, no problem (because no data are changed):

$ stcgal -p /dev/ttyUSB0 flash-dump.ihx eeprom-ff.hex

I prepared other EEPROM file, it has only one byte data and data is 0xfe.

$ cat eeprom-fe.hex 
:01000000FE01

I flash it to MCU, no problem:

$ stcgal -p /dev/ttyUSB0 flash-dump.ihx eeprom-fe.hex

But when I try to flash it again, I receive error Protocol error: incorrect magic in write packet. When I don't ask to write EEPROM file, no error is reported. So I think this confirm the theory that this error means that EEPROM is not blank and data cannot be written...

I prepared file with 0xff data, length 8192. My MCU is STC15W408AS and it has 8kB of FLASH and it has 5kB EEPROM. I read somewhere that stcgal has a secret feature and it can write program and EEPROM data in one run, when first file is large enough. So my idea was to flash file with size 13312 ((8+5)*1024=13312) bytes and data 0xff, that should erase the complete chip. stcgal wrote 8kB and than reported error but EEPROM was not erased it still has 0xfe byte at position 0x0000 (0x2000 when accessed from code)... I executed more experiments and I can confirm that stcgal can write flash and EEPROM in one go as one big file BUT only in the case that EEPROM is blank; stcgal cannot blank EEPROM. When EEPROM is not blank, error Protocol error: incorrect magic in write packet is reported.

Workarround (to avoid switching to Windows to use STC-ISP programmer to blank EEPROM area). C program to check and blank EEPROM, sector by sector, up to 128 sectors; it assumes that sector size is 512 bytes. Based on demo program from STC, modified for SDCC.

$ sdcc --iram-size 128 --xram-size 0 blank-eeprom.c
$ cat blank-eeprom.c

/* --- Exam Program EEPROM/IAP -------------------------------------------------------------------*/
/* If you want to use the program or the program referenced in the ------------------------------*/
/* article, please specify in which data and procedures from STC -------------------------------*/
/*---- In Keil C development environment, select the Intel 8052 to compiling -------------------*/
/*---- And only contain < reg51.h > as header file ----------------------------------------------------*/
/*-------------------------------------------------------------------------------------------------------------*/
//suppose the frequency of test chip is 18.432MHz
//#include "reg51.h"
//#include "intrins.h"

#include <stc12.h>

typedef unsigned char BYTE;
typedef unsigned int WORD;
//-----------------------------------------------

//sfr IAP_DATA = 0xC2; //IAP data register
//sfr IAP_ADDRH = 0xC3; //IAP address HIGH
//sfr IAP_ADDRL = 0xC4; //IAP address LOW
//sfr IAP_CMD = 0xC5; //IAP command register
//sfr IAP_TRIG = 0xC6; //IAP command trigger register
//sfr IAP_CONTR = 0xC7; //IAP control register

#define CMD_IDLE 0          //Stand-By
#define CMD_READ 1          //IAP Byte-Read
#define CMD_PROGRAM 2       //IAP Byte-Program
#define CMD_ERASE 3         //IAP Sector-Erase
//#define ENABLE_IAP 0x80   //if SYSCLK<30MHz
//#define ENABLE_IAP 0x81   //if SYSCLK<24MHz
//#define ENABLE_IAP 0x82   //if SYSCLK<20MHz
#define ENABLE_IAP 0x83    //if SYSCLK<12MHz
//#define ENABLE_IAP 0x84   //if SYSCLK<6MHz
//#define ENABLE_IAP 0x85   //if SYSCLK<3MHz
//#define ENABLE_IAP 0x86   //if SYSCLK<2MHz
//#define ENABLE_IAP 0x87   //if SYSCLK<1MHz
//Start address for STC15 series MCU EEPROM

void Delay(BYTE n);
void IapIdle();
BYTE IapReadByte(WORD addr);
void IapProgramByte(WORD addr, BYTE dat);
void IapEraseSector(WORD addr);

#define _nop_() \
      __asm     \
          nop   \
      __endasm  \

#define IAP_ADDRESS 0x0400
#define SECTOR_SIZE 512
//#define SECTORS 16
#define SECTORS 128

void checkAerase(BYTE sector)
{
  WORD addr;
  WORD i;
  BYTE b;
  addr = sector * SECTOR_SIZE;
  for (i=0; i<SECTOR_SIZE; i++) {
    b = IapReadByte(addr+i);
    if (b != 0xff) {
      IapEraseSector(addr);
      break;
    }
  }
}

void main()
{
  BYTE i;
  for (i=0; i<SECTORS; i++) {
    checkAerase(i);  // check for non empty sectors and erase them!
  }
  while (1);  // HALT
}

/*
void main()
{
  WORD i;
  P1 = 0xfe; //1111,1110 System Reset OK
  Delay(10); //Delay
  IapEraseSector(IAP_ADDRESS); //Erase current sector
  for (i=0; i<512; i++) {  //Check whether all sector data is FF
    if (IapReadByte(IAP_ADDRESS+i) != 0xff)
      goto Error; //If error, break
  }
  P1 = 0xfc; //1111,1100 Erase successful
  Delay(10); //Delay
  for (i=0; i<512; i++) { //Program 512 bytes data into data flash
    IapProgramByte(IAP_ADDRESS+i, (BYTE)i);
  }
  P1 = 0xf8; //1111,1000 Program successful
  Delay(10); //Delay
  for (i=0; i<512; i++) { //Verify 512 bytes data
    if (IapReadByte(IAP_ADDRESS+i) != (BYTE)i)
      goto Error; //If error, break
  }
  P1 = 0xf0; //1111,0000 Verify successful
  while (1);
Error:
  P1 &= 0x7f; //0xxx,xxxx IAP operation fail
  while (1);
}

*/

/*----------------------------
Software delay function
----------------------------*/
void Delay(BYTE n)
{
  WORD x;
  while (n--) {
    x = 0;
    while (++x);
  }
}

/*----------------------------
Disable ISP/IAP/EEPROM function
Make MCU in a safe state
----------------------------*/
void IapIdle()
{
  IAP_CONTR = 0;            //Close IAP function
  IAP_CMD = 0;              //Clear command to standby
  IAP_TRIG = 0;             //Clear trigger register
  IAP_ADDRH = 0x80;         //Data ptr point to non-EEPROM area
  IAP_ADDRL = 0;            //Clear IAP address to prevent misuse
}

/*----------------------------
Read one byte from ISP/IAP/EEPROM area
Input: addr (ISP/IAP/EEPROM address)
Output:Flash data
----------------------------*/
BYTE IapReadByte(WORD addr)
{
  BYTE dat;                 //Data buffer
  IAP_CONTR = ENABLE_IAP;   //Open IAP function, and set wait time
  IAP_CMD = CMD_READ;       //Set ISP/IAP/EEPROM READ command
  IAP_ADDRL = addr;         //Set ISP/IAP/EEPROM address low
  IAP_ADDRH = addr >> 8;    //Set ISP/IAP/EEPROM address high
  IAP_TRIG = 0x5a;          //Send trigger command1 (0x5a)
  IAP_TRIG = 0xa5;          //Send trigger command2 (0xa5)
  _nop_();                  //MCU will hold here until ISP/IAP/EEPROM
  //operation complete
  dat = IAP_DATA;           //Read ISP/IAP/EEPROM data
  IapIdle();                //Close ISP/IAP/EEPROM function
  return dat;               //Return Flash data
}
/*----------------------------
Program one byte to ISP/IAP/EEPROM area
Input: addr (ISP/IAP/EEPROM address)
 dat (ISP/IAP/EEPROM data)
Output:-
----------------------------*/

void IapProgramByte(WORD addr, BYTE dat)
{
  IAP_CONTR = ENABLE_IAP;   //Open IAP function, and set wait time
  IAP_CMD = CMD_PROGRAM;    //Set ISP/IAP/EEPROM PROGRAM command
  IAP_ADDRL = addr;         //Set ISP/IAP/EEPROM address low
  IAP_ADDRH = addr >> 8;    //Set ISP/IAP/EEPROM address high
  IAP_DATA = dat;           //Write ISP/IAP/EEPROM data
  IAP_TRIG = 0x5a;          //Send trigger command1 (0x5a)
  IAP_TRIG = 0xa5;          //Send trigger command2 (0xa5)
  _nop_();                  //MCU will hold here until ISP/IAP/EEPROM
  //operation complete
  IapIdle();
}

/*----------------------------
Erase one sector area
Input: addr (ISP/IAP/EEPROM address)
Output:-
----------------------------*/

void IapEraseSector(WORD addr)
{
  IAP_CONTR = ENABLE_IAP;   //Open IAP function, and set wait time
  IAP_CMD = CMD_ERASE;      //Set ISP/IAP/EEPROM ERASE command
  IAP_ADDRL = addr;         //Set ISP/IAP/EEPROM address low
  IAP_ADDRH = addr >> 8;    //Set ISP/IAP/EEPROM address high
  IAP_TRIG = 0x5a;          //Send trigger command1 (0x5a)
  IAP_TRIG = 0xa5;          //Send trigger command2 (0xa5)
  _nop_();                  //MCU will hold here until ISP/IAP/EEPROM
  //operation complete
  IapIdle();
}

The patch (for stc15 protocol, the only one with this issue?):

diff --git a/stcgal/protocols.py b/stcgal/protocols.py
index 6ce408a..a8e8da7 100644
--- a/stcgal/protocols.py
+++ b/stcgal/protocols.py
@@ -1462,7 +1462,11 @@ class Stc15Protocol(Stc15AProtocol):

         print("Erasing flash: ", end="")
         sys.stdout.flush()
-        packet = bytes([0x03, 0x00])
+        packet = bytes([0x03])
+        if erase_size <= flash_size:
+           packet += bytes([0x00])  # erase flash only
+        else:
+           packet += bytes([0x01])  # erase flash and eeprom
         if self.bsl_version >= 0x72:
             packet += bytes([0x00, 0x5a, 0xa5])
         self.write_packet(packet)
flexifi commented 4 years ago

hi how to get eeprom to STC MCU

PSLLSP commented 3 years ago

Could be patch for this issue accepted?

grigorig commented 3 years ago

I've already noticed this issue and the proposed patch, I'd just like to test it myself with various STC15 series MCUs. It would certainly help if you prepare a proper MR.