Atmel AT89C2051 programmer

This is Linux software for idea from former Silicon studio parallel port programmer for AT89C2051 microcontroller. It is a direct translation of the software example for this programmer. It is easily extended to AT89C4051 MCU.

AT89C2051 Features

Hardware

schematics

Download

Download source and original blowit.pdf or AT89C2051 documentation

BlowIT Linux Source

Binary input file is needed for programmer. SDCC has tool called makebin that does HEX to BIN conversion. There is no posibility (hardware limitation) to do programming verification. If programmer says "We are finished" Programming should be OK, otherwise error is issued on missing device or timeout.

bi2051.c

#include "microdelay.h"
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <ctype.h>
#include <sys/io.h>
#include <sys/types.h>
#include <fcntl.h>

#define inc_bit    0x01
#define vpp_bit    0x02
#define prog_bit   0x04 /* not inverse */
#define erase_bit  0x08 
#define prog_mode  0x0F
#define erase_mode 0x07
#define idle       0x09 /* Idle, rst = 0 */

#define MEM_SIZE 2048

int main(int argc, char **argv) {

  // parallel programmer variables
  unsigned int port=0x378;
  unsigned char mem[MEM_SIZE];
  
  int i, j, k, l, fd;
  

  /* check root privileges */
  if (geteuid()!=0) 
    {
      fprintf(stderr,"ERROR: this programs needs root permisions to access "
	      "parallel port. Please use root user to run or setuid bit.\n");
      abort();
    }
  ioperm(port,3,1);

  microdelay_init(); //initialize microdelay function

  for (i = 0; i < MEM_SIZE; i++)
	mem[i] = 0xFF;


  fd = open(argv[1], O_RDONLY);
  if (!fd)
	{
	  perror(argv[1]);
	  outb(idle, port+2);
	  outb(0x00, port);
	  exit(2);
	}

  read(fd, mem, MEM_SIZE);
  close(fd);

#define nms(x) microdelay((x)*1000)
  

  /* Erase */
  outb(0xFF, port);
  outb(0x01, port+2);
  nms(10);
  outb(0x03, port+2); /* RST = 12 */
  nms(1);
  outb(erase_mode, port+2);
  nms(1);
  outb(erase_mode^prog_bit, port+2); /* P3.2 = 0 */
  nms(12);
  outb(erase_mode, port+2); /* P3.2 = 1 */
  nms(12);
  outb(erase_mode ^ vpp_bit, port+2); /* RST = 0 */
  nms(20);
  

  /* Program FLASH */
  outb(idle, port+2);
  nms(10);
  outb(idle | vpp_bit, port+2);
  nms(10);
  outb(prog_mode, port+2); /* RST = 12, PROG = H */
  nms(1);
  printf("Blowing");
  k = 0;
  l = 0;
  for(j = 0; j < MEM_SIZE; j++)
    {
      outb(mem[j], port);
      if (mem[j] != 0xFF)
	{
	  microdelay(2);
	  /* PROG pulse */
	  outb(prog_mode ^ prog_bit, port+2); /* P3.2 = 0 */
	  microdelay(5);
	  outb(prog_mode, port+2); /* P3.2 = 1 */
	  i = 0;
	  while ( (inb(port+1) & 64) == 0)
	    {
	      microdelay(20);
	      if (i > 200)
		{
		  printf("Error, never ready?\n");
		  outb(idle, port+2);
		  outb(0x00, port);
		  exit(3);
		}
	      if (i > k) 
		k = i;
	      i++;
	    }
	  if (l > 30)
	    {
	      printf("Error, no device?\n");
	      outb(idle, port+2);
	      outb(0x00, port);
	      exit(4);
	    }

	  if (i == 0)
	    l++;
	  microdelay(2);
	}
      outb(prog_mode ^ inc_bit, port+2); /* XT1 = 1 */
      microdelay(5);
      outb(prog_mode, port+2); /* XT1 = 1 */
      microdelay(2);
      if (j % 64 == 0)
	printf(".");
    }
  outb(0xFF, port);
  nms(1);
  outb(prog_mode ^ vpp_bit, port+2); /* P3.2 = 0 !! */
  nms(1);
  outb(idle, port+2);
  outb(0x00, port);
  printf("\nWe are finished\n");
  exit(0);
}

microdelay.h

/*
Copyright (C) 2000-2001 José Roberto B. de A. Monteiro <jrm@autsens.com>
                        and Pedro Zorzenon Neto <pzn@autsens.com>

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
*/

#ifndef _MICRODELAY_H
#define _MICRODELAY_H

void microdelay_init();
void microdelay(unsigned int microsec);

#endif

microdelay.c

/*
Copyright (C) 2000-2001 José Roberto B. de A. Monteiro <jrm@autsens.com>
                        and Pedro Zorzenon Neto <pzn@autsens.com>

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
*/

/*
 From http://www.linuxdoc.org/HOWTO/mini/IO-Port-Programming.html
 an outb to port 0x80 gives a delay of aprox 1microsec independent
 of your machine type/clock.
 See also documentation in asm/io.h
*/

#include "microdelay.h"
#include <unistd.h>
#include <sys/io.h>

int old_port_value;

void microdelay_init() {
    // permition to write in port 0x80
    // nothing is suposed to use this port
    // however, we will write the same value we read...
    ioperm(0x80,1,1);
    old_port_value=inb(0x80);
}

void microdelay(unsigned int microsec) {
    while (microsec)
    {
	outb(old_port_value,0x80);
	microsec--;
    }
}

Grzegorz Jaskiewicz suggested the following amendments (verification?) and flush of dotted output.:

--- bi2051.c    2003-04-29 17:01:35.000000000 +0200
+++ /tmp/bi2051.c       2006-06-08 13:43:05.000000000 +0200
@@ -23,7 +23,7 @@
   unsigned int port=0x378;
   unsigned char mem[MEM_SIZE];
   
-  int i, j, k, l, fd;
+  int i, j, k, l, fd, v;
   
 
   /* check root privileges */
@@ -117,14 +117,24 @@
 
          if (i == 0)
            l++;
+
+    v = inb(port);
+    if ( mem[j] != v ) {
+       printf("verification failed\n");
+       exit(5);
+    }
          microdelay(2);
        }
+    
+    
       outb(prog_mode ^ inc_bit, port+2); /* XT1 = 1 */
       microdelay(5);
       outb(prog_mode, port+2); /* XT1 = 1 */
       microdelay(2);
-      if (j % 64 == 0)
+      if (j % 64 == 0) {
+        fflush(stdout);
        printf(".");
+      }
     }
   outb(0xFF, port);
   nms(1);

Leon Kos
Last modified: Thu Jun 8 13:49:54 CEST 2006