USB Easy-Downloader V5.0

Wichit Sirichote, wichit.sirichote@gmail.com

Build the programmer board for 89S52 and SST89E516RD chips with USB port connection.


The USB is now a generic communication port for connecting the PC to many USB devices. I have my free time to renovate the Easy-downloader V2.0 by changing the RS232 port to the USB port. The USB easy-downloader now can be connected to a laptop computer that provides only USB port conveniently. The programmer board is powered by USB plug directly. The programming voltage, +12V is also generated by a DC-to-DC converter. The programmer board is then no need the external AC adapter. The prototype made with double side PCB is shown in Figure 1.

Figure 1: Prototype USB Easy-downloader.

How it works

A simplified block diagram is shown in Figure 2. The target chip is being programmed in parallel mode. The master chip provides data bus (D0-D7), address bus (A0-A15) and programming mode selection control signals. The master chip communicates with EZDL software by a serial port. Since the EZDL software uses the COM port, 9600 8n1 to communicate with the master chip. Thus to make the programmer board compatible with the EZDL, we need the chip that converts USB to RS232. The magic chip that simplified USB connection to the microcontroller is FT232RL made by FTDI. The FT232RL is a bridge between UART and USB. The PC will detect the USB device as the UART and will assign a number for the available COM port. User may check the COM port number from the hardware manager in control panel. The master chip then communicates with PC using UART 9600 8n1 easily.

Another feature is to use power from USB port. The programmer board is powered by +5V from USB plug directly. For +12V programming voltage, the MC34063, DC-to-DC converter will boost +5V to +12V. A small signal PNP transistor is configured as the high side switch to select between +5V or +12V for the programming voltage Vpp.
Figure 2: Simplified block diagram.


Hardware schematic

The circuit is adapted from Easy-downloader V2.0, by replacing the DS275, RS232 converter with the FT232RL USB-UART converter chip. Port 0 of the master chip provides data bus, D0-D7 for the target chip. Port 1 for the Address bus, A0-A7. A8-A15 are generated by P2. J1 is for selecting A15 line. The programming voltage +12V, is generated by U4, DC-to-DC converter. The circuit boosts +5V USB voltage to +12Vpp. Q2, PNP transistor is a high side voltage switch. It is turned on by Q3 through VCON signal. When VCON is logic high, Q3 is conducted, making Q2 turned on. The collector pin of Q2 will be +12V. When Q2 is turned off, D2 will conduct, Vpp at pin 31 of the target chip will be +5V. The programmer board is powered by +5V from USB port.

Figure 3: Schematic (click to enlarge). 

PARTS LIST

Semiconductors

U1-AT89S52, 8kB Flash microcontroller
U2-40 pins ZIF socket
U3-FT232RL USB-UART converter chip
U4-MC34063A DC-to-DC converter
D1-TVS5V, transient voltage suppressor +5.6V SOD123
D3,D2-1N4148 silicon signal diode
D6,D7-surface mount LED/SMD3216
D8-LED-surface mount LED
FB1-PTC-Polyswitch 24VDC /0.20A for overcurrent protection
Q1-BC327, PNP transistor
Q2-BC327, PNP transistor
Q3-BC337, NPN transistor

Resistors (all resistors are 1/4W +/-5%)

R1,R4-10k
R2,R3-680 SMD0805
R5-0.5
R6-20k
R7-220
R8-2.2k
R9-100k
R10,R11,R12-4.7k
R13-100
R14-1k

Capacitors
C1,C3,C7-100nF, SMD0805 multilayer capacitor
C10,C2-10uF, electrolytic
C5,C4-30pF, ceramic disc
C6-220pF, ceramic disc
C8-10nF, SMD 0805
C9-100uF35V, electrolytic

Inductor

L1-100uH

Additional parts

J1 CON3, 3-pin header
CN1 CN-USB, type B USB plug
SW1 SW TACT-SPST
Y1 11.0592MHz, crystal

Master chip firmware

The current version supports only for 8kB 89S52 and 8kB boot block SST89E516RD chips. The source code is available for download and is developed with Micro-C for 8051 compiler. You may modified the source code for a given microcontroller easily.

/*
Easy-Downloader V2.1 for ATMEL 89C51/52/55WD
Copyright(c) 2002 By Wichit Sirichote kswichit@kmitl.ac.th

The source code was modified from ez52.c for programming the 89C55WD.

89C55WD uses A14 tied to P3.4 not P3.0 as 89C55.

The source code was compiled with Dunfiled Micro-C for 8051.

13 December 2013, modified for Microchip FlashFlex 8051 MCU

21 December 2013, complete test for 89S52
add warning for programming lock bits!
27 December 2013, modify code for SST89E516RD for using with EZDL4
ReadID must be executed for ARMING operation
Block 1 for bootloader must be selected.

The EZDL4 will see the chip as 89C52 and will erase
block 1, write the bootloader of NXP89V51RD2
User can then use the Flashmagic to program the
SST89E516 directly!

18 January 2014, test DC-to-DC converter Mc34063 that produces +12V
from +5V
new file name, flex2.c

change VPP control, setbit at VCON will produce +12V
clearbit at VCON will produce +5V

after power reset, set VPP to +5V by clearing VCON

*/

#include <8051io.h>
#include <8051reg.h>
#include <8051bit.h>

#define xon 0x11
#define xoff 0x13

#define Vpp P3.3 // set Vpp = +5V clear Vpp = +12.5V
#define prog P3.2

// map materchip i/o port to the mode selection on ZIF

#define p26 P3.4
#define p27 P3.5

#define p33 P2.7

#define p36 P3.6
#define p37 P3.7

register int i;
unsigned register char ACCU,temp,blank,chip,VPP,ID,bcc;
register char command;
register unsigned int address,chksum;

char title[] = "\n Easy-Downloader V5.0 for AT89C52/89S52 FlashFlexMCU"
char prompt[] = "\n >"
char ok[] = "\n ok"

unsigned register int count,bytes,nonblank,load_address;

register char buffer[50]; // for Intel hex file record buffer
register char eof;

main()
{
delay(100);
clrbit(Vpp)

i = 0;
count = 0;
serinit(9600);
getch();
putstr(title);
sendprompt();
setbit(prog)
delay(100);

for(;;)
{
getcommand();
prompting();
setcounter();
erase();
write();
read();
lock();
printchksum();
getinfo();
PGMparameters();
read_ID();
block_select(); // for SST chips
manual_VPP();
read_lockbit();
printhelp();
get_record(); // read hex record
}
}

getnum()
{
char s[6]; /* five characters plus terminator */
char c;
int i;
c = 0;
for (i = 0; c != 10; i++)
{
putch(xon);
c = putchr(getch());
s[i] = c;
}
s[i] = '\0'; /* put end-of-string to the last byte */
if (i==0)
return (-1);
else
return (_atoi(s));

}

getcommand()
{

if ((SCON & 0x01) != 0)
command = putchr(getch());
else command = -1; /* no cammand has entered */
}

getconsole()
{

if ((SCON & 0x01) != 0)
command = getchr();
else command = -1;
}

putok()
{
putstr(ok);
/* putch(' '); */
sendprompt();
}

sendprompt()
{
putstr(prompt);
}

prompting()

{
if (command == '\n')
{
putstr(title);
/* putok(); */
sendprompt();
}
}

gets()

{
char c;

for (i = 0; c != 10; i++)
{
c = getch();
buffer[i] = c;
}
buffer[i] = '\0'; /* put end-of-string to the last byte */

}

char to_hex(char hi_nib,char low_nib)
{
temp = hi_nib-'0';

if(temp>9) temp-=7;
hi_nib=temp<<=4;

temp = low_nib-'0';
if(temp>9) temp-=7;

return (hi_nib|temp);

}

get_record()
{
if(command=='h')
{
putstr("\nwating hex file");

eof=0;

while(eof==0)
{
// _getstr(buffer,sizeof(buffer));

putch(xon);
_getstr(buffer,sizeof(buffer));
putch(xoff);

printf("\n%i %d",buffer,sizeof(buffer));

// :100060007105F583710543B14075B5AAF5B4858373

// check end of file

eof = to_hex(buffer[7],buffer[8]);

bcc =0;

bytes= to_hex(buffer[1],buffer[2]); // get number of byte

bcc+=bytes;

// printf("\n byte = %d ",bytes);

address=to_hex(buffer[3],buffer[4]);

bcc +=address;

address<<=8;

address|=to_hex(buffer[5],buffer[6]);

bcc +=address&0x00ff;

// printf("\n %d %04x",bytes,address);

for(i=0; i<bytes; i++)
{

temp = to_hex(buffer[i*2+9],buffer[i*2+10]);

bcc+=temp;

// printf(" %02x",temp);

}

bcc=~bcc+1;

// printf(" %02x",bcc);

}

sendprompt();

 

}

 

}

read_lockbit() // for 89S52
{
if(command=='q')
{
setbit(prog)
clrbit(Vpp)
setbit(p26)
setbit(p27)
clrbit(p33)
setbit(p36)
clrbit(p37)
delay(10);
P0 = 0xff;
temp=P0;
printf("\n%08b",temp);
sendprompt();
}
}

manual_VPP()
{

if(command=='v')
{

putstr("\nVPP =+12V");
setbit(Vpp)
putstr("\npress any key to turn VPP off");
getch();
clrbit(Vpp)
sendprompt();

}

}

 

read_ID()
{
if(command=='i')
{

readID();
putok();
sendprompt();

 

}

}

block_select()
{
char c;

if(command=='b')
{

putstr("\nBlock 0 or 1>");
c=putchr(getch());

if (c==0x31) temp = 0xA5;
else temp = 0x55;

P2 = temp;

setbit(p37)
clrbit(p36)
clrbit(p27)
setbit(p26)

pulseProg();
delay(100);
putok();
sendprompt();

}

}

erase()
{
if (command == 'e')
{

if(chip ==0x52)
{

setbit(Vpp);

delay(100);

setbit(p26)
clrbit(p27)
setbit(p33)
clrbit(p36)
clrbit(p37)

delay(10); // raise Vpp from +5V to +12.5V

pulseProg();

delay(100);
clrbit(Vpp);
}
// select memory block beforehand

if(chip ==0x93)
{
setbit(Vpp);

delay(100);

setbit(p26) // erase memory block
clrbit(p27)
setbit(p36)
setbit(p37)

delay(10); // raise Vpp from +5V to +12.5V

pulseProg();

delay(100);
clrbit(Vpp);
}
putok();
}
}

write() /* call sequence before write: 's', 't','e','w' */
{
if (command == 'w')
{

if(chip == 0x52 || chip == 0x93)
{

clrbit(Vpp)

clrbit(p26)
setbit(p27)
setbit(p33)
setbit(p36)
setbit(p37)

setbit(prog)

delay10us();

setbit(Vpp)

delay(100); /* raise programming voltage to 12V */
chksum = 0;
for (i = 0; i < count; i++)
{ /* use XON & XOFF flow control */
putch(xon); /* send XON */
address = i;

if(chip==0x52)
{
asm{
mov P1,address /* put address to P1 and P2 */
mov A,address+1
ORL A,#$80 // P3.3 must be high
mov P2,A
}
}

if(chip==0x93)
{
asm{
mov P1,address /* put address to P1 and P2 */
mov A,address+1
mov P2,A
}
}

delay10us();
P0 = getchr(); /* read raw bytes from console */
putch(xoff); /* send XOFF */
chksum += P0; /* summing chksum */
pulseProg();

delay100us(); // use delay instead of checking RDY/BSY

}

clrbit(Vpp) /* bring Vpp back to 5V */
delay(100);
putok();
}
}
}

read() /* read according to number of bytes by 'c' command */
{
unsigned int i;
if (command=='r')
{
/* temp = getch(); */
chksum = 0; /* reset check sum word */

setbit(prog)
clrbit(p26)
clrbit(p27)
clrbit(p33)
setbit(p36)
setbit(p37)

blank = '1';
for(i = 0; i < count; i++)
{
address = i;
asm{
mov P1,address
mov A,address+1
mov P2,A
}

// delay10us();
asm" mov P0,#$FF"; /* put FF before read back */
chksum += P0;
printA(P0); /* read in HEX */

chkXOFF();
}
putok();
}
}

printA(n)
char n;
{
ACCU = n;
ACCU >>= 4; /* shift right 4 bits */
putHEX();
ACCU = n&15;
putHEX();
/* delay(2); */

}

chkXOFF() /* use XON and XOFF for controlling flow with host */

{
if(getconsole() == xoff)
{
do
;
while(getconsole() != xon);
}
}

putHEX()
{
if (ACCU > 9)
putch(ACCU+55);
else putch(ACCU+48);
}

blanktest() /* if all bytes are 0FFH then blank =FF, else blank = 0 */
{
if (P0 != 0xff)
{ blank = '0'; /* full */
nonblank++;
}
}

lock() /* only protection mode 4 can be programmed,i.e., disabled further
program, verify, and external execution */

{
if (command == 'l')
{
// lock bit 1
putstr("\nwarning ! further programming will be disabled...");
putstr("\nclick yes to continue>");
temp=getchr();

if(temp=='y')
{

setbit(Vpp)
delay(100); // wait +12V

setbit(prog)
setbit(p26)
setbit(p27)
setbit(p33)
setbit(p36)
setbit(p37)

pulseProg();
delay(100);
delay(5);
// lock bit 2
clrbit(p36)
clrbit(p37)
pulseProg();
delay(100);

// lock bit 3

clrbit(p27)
setbit(p36)
clrbit(p37)

pulseProg();
delay(100);
putstr("\nlock complete");
}
else
{
putstr("\nabort");
}

putok();

}

}

printchksum()
{
if (command == 'c')
{
printf("\n CHKSUM = %04x",~chksum+1);
putok();
}
}

readID()
{
clrbit(Vpp)
setbit(prog)

clrbit(p26)
clrbit(p27)
clrbit(p36)
clrbit(p37)

address = 0x31; // check SST89E516RD2
asm{
mov P1,address
mov A,address+1
mov P2,A
}
delay10us();
P0 = 0xFF; /* put FF before read back */
chip=P0;

if(chip != 0x93)
{
address = 0x100; // check 89S52 or 89C52
asm{
mov P1,address
mov A,address+1
mov P2,A
}
delay10us();
P0 = 0xFF; /* put FF before read back */
chip=P0;
}

}

signature() /* read signature ATMEL chip 51/52/55 12V or 5V Vpp */

{
readID();
printf("%x",chip);
/*
address = 0x60; // location stores ATMEL ID for 89C51 and 89C52
asm{
mov P1,address
mov A,address+1
mov P2,A
}
delay10us();
P0 = 0xFF; /* put FF before read back */
temp = P0;
printf(" %08b ",temp); // print status

address = 0x61; // location stores ATMEL ID for 89C51 and 89C52
asm{
mov P1,address
mov A,address+1
mov P2,A
}
delay10us();
P0 = 0xFF; /* put FF before read back */
temp = P0;
printf(" %08b ",temp); // print status

// if chip = 0xFF, try with address 0x100 for 89C55WD also

if(chip ==0xFF)
{
address = 0x100; // stores ATMEL device ID 0x55 for 89C55WD
asm{
mov P1,address
mov A,address+1
mov P2,A
}
delay10us();
P0 = 0xFF; /* put FF before read back */
chip = P0;
// setbit(p27)
// printf("\n %04x = %02x ",address,chip);
}

address++;
asm{
mov P1,address
mov A,address+1
mov P2,A
}
delay10us();

*/

clrbit(Vpp)

P0 = 0xff; /* put FF before read back */
VPP = P0; /* save Vpp 12V (FF) or 5V (5) into VPP */
}

testblank() /* need to call signature function pior calling testblank */
{
signature();

switch(chip){
case (0x51): /* 89C51 */
bytes = 4096; /* if chip == 0x51 or 0x61 then bytes = 4kB */
break;
case (0x61): /* 89LV51 */
bytes = 4096;
break;
case (0x52): /* 89C52 */
bytes = 8192; /* if chip == 0x52 or 0x62 then bytes = 8kB */
break;
case (0x62): /* 89LV52 */
bytes = 8192;
break;
case (0x55): /* 89C55 */
bytes = 20480; /* if chip == 0x55 or 0x65 then bytes = 20kB */
break;
case (0x65): /* 89LV55 */
bytes = 20480;
break;
case 0xff:
bytes = 0;
}
chksum = 0; /* reset check sum word */
nonblank = 0; /* reset nonblank bytes counter */

clrbit(Vpp)
setbit(prog)
clrbit(p26)
clrbit(p27)
setbit(p36)
setbit(p37)

blank = '1';
for(i = 0; i < bytes; i++)
{
address = i;
asm{
mov P1,address
mov A,address+1
// orl A,#$80
mov P2,A
// clr p27
}

// delay10us();
P0 = 0xff; /* put FF before read back */
chksum += P0;
blanktest();
// setbit(p27) /* next address */
}
}

setcounter()
{
if (command == 's')
{
count = getnum();
putok();
}
}

getinfo()
{
if (command =='g')
{
// testblank();
signature();
if(chip!=0xff)
{
if(chip==0x93) putstr("\nfound SST89E51RD");
if(chip==0x52) putstr("\nfound 89C52 or 89S52");
printf("\n nonblank %u bytes",nonblank);
printf("\n bytes counter %u",count);
}
else(putstr("\ntarget not found "));
putok();
}
}

PGMparameters() /* for simple host interfacing */
{
if (command=='p')
{
readID();
delay(100);

nonblank=0;
// testblank();
printf("%x,%u,%u",0x52,nonblank,count); // test..
putok();
}

}

 

printhelp()
{
if (command == '?')
{
putstr("\n e erase block");
putstr("\n q read lock bit");
putstr("\n s set number of byte");
putstr("\n r read code");
putstr("\n l lock the chip");
putstr("\n g get chip info");
putstr("\n w write byte");
putstr("\n b set block 0/1");

sendprompt();
}
}

pulseProg()

{
clrbit(prog)
asm{
NOP
NOP
NOP
NOP
}
setbit(prog)
}

delay10us()
{
int i;
for (i=0;i<1;i++);

}

delay100us()
{
int i;
for (i=0; i<10;i++);
}

Figure 4: Source code listing.

NOTE

1.The USB driver for FT232RL is called VirtualCOM Port, it can be downloaded from FTDI directly.
2. J1 is used to select between 89S52 or SST89E516RD chip. Pin 1-2 is for 89S52 chip. Pin 2-3 is for SST89E516RD.
3. The EZDL will display found 89C52, so the code size maximum is then 8kB.
4. The command line interface is enabled by using 9600 VT100 terminal, for those who want to develop more commands, e.g. HEX file programming, feel free to add the functions then.
5. For those who need upgradable of the master chip, just use the SST89E516RD as the master chip with nxp bootloader. Then the master chip can be reprogrammed by Flashmagic easily. I tested the FT232 USB converter chip under XP, it works very well.

The COM port number can get from control panel, system, devices manager, Ports(COM/LPT).

The Interface must be None(ISP), click Erase blocks used by Hex file, select the hex file.

Before press START (in step5), press and hold reset button of the programmer board..

Click START, when window popup, release the reset button, the Flashmagic will program/verify the chip automatically..



Download ,Schematic, Firmware HEX file , Source code, , List file, Ezdl4.rar

Kit, PCB, or preassembled board, please contact wichit.sirichote@gmail.com


<

27 January 2014