AT89C52 SPI programming via parallel port nightmare

399 Views Asked by At

I'm trying to figure out why my chip can't be programmed completely. I attempted to store 1.7 KB of code in the chip. I was successfully able to program the first 256 bytes and was able to verify each one (even though there were hiccups at times), however, the 257th byte can't be verified.

The chip I used is AT89S52 which accepts at least 4KB code. Also, the file I have inputted into the program as a parameter was found and stored in x051 char array.

The hardware I use is my own circuit I built in which the following connections are made through buffers from PC parallel port to microcontroller:

Pin 1 (strobe) to SCK
Pin 2 (data bit 0) to enable all buffers
Pin 4 (data bit 2) to MOSI
MISO to Pin 11 (busy)

Each line on the microcontroller is taken high by a 10K external pull-up resistor.

EA/VPP line on the microcontroller is set to high to allow programming.

The microcontroller is attached to a 20Mhz crystal.

I'm just trying to figure out. Is there a way I can change my code such that the timing more adheres to the AT89S52 chip because in the state it is in, I can only program the first 256 bytes of the chip. The datasheet for this microcontroller isn't clear on the timings.

I have tried page-mode writing and the results were substantially worse.

This is my code, and as it shows, if it struggles on a certain byte, it gets rewritten every 100 attempts of verification until it is verified as stored:

#include <sys/stat.h>
#include <sys/types.h>
#include <sys/io.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int fm=0;
void lag(){if (fm!=1){usleep(1500);}else{usleep(500);}} //lag routine
void _sclk(unsigned char n){if (n != 0){n=1;};outb(n,0x37A);lag();} //set value for SCK
void _touc(unsigned char n){if (n != 0){n=4;};n++;outb(n,0x378);lag();} //set value for MOSI and set reset low
unsigned char _fromuc(){unsigned char n=inb(0x379);if ((n & 0x80)!= 0){n=1;}else{n=0;};return n;} //get MISO value

void bo(unsigned char byt){
//byte out to uC
  int bit,bn;
  for (bit=0;bit<8;bit++){
  bn=(byt & 0x80);
  if (bn != 0){bn=1;}
  _touc(bn);_sclk(1);_sclk(0);byt=byt<<1;
  }
}

unsigned char bi(){
  //byte in from uC
  int bit,bn;unsigned char outbyte;
  for (bit=0;bit<8;bit++){
_sclk(1);
bn=_fromuc();
outbyte=outbyte<<1;
if (bn!=0){outbyte++;}
_sclk(0);
  }
  outbyte=255-outbyte;
  return outbyte;
}


int main(int argc,char* argv[]){
  char x051[10000]; //buffer for file data
  setbuf(stdout,NULL);
  if (argc < 2){
  printf("binary filename required as argument.\n");
  return -1;
  }
  struct stat info;stat(argv[1],&info); //get file size
  if (info.st_size > 32767){
  printf("FILE SIZE TOO LARGE\n"); //my chip can't handle 32kb
  return -1;
  }
  int fs=info.st_size;
  if (fs < 1){
printf("File non-existant.\n");
return -1;
  }
  printf("File size for %s is %d bytes\n",argv[1],fs);
  memset(x051,0,4999); //clear just enough data memory. we only use 4K max.
  FILE* fh=fopen(argv[1],"r");
  if (fh){ //don't crash if computer disk breaks during program
fread(x051,fs,1,fh);
  };
  fclose(fh);
  //LPT address definitions
  //378: bit 0: 1=SPI MODE,0=RUN
  //     bit 2: uC recv (MOSI P1.5)
  //379: bit 7: uC send (MISO P1.6)
  //37A: bit 0: sclk (SCK P1.7)
  if (ioperm(0x378,3,1) ==-1){ //get permission to use port
printf("ERROR: Access to port hardware denied by PC.\n");
return -1;
  }
  printf("AT89S5x burner starting\n");
  outb(0x0,0x378); //set reset on micro to
  _touc(0); //RESET=high + MOSI = 0
  _sclk(0); //SCK = 0
  usleep(1000000); //wait 1 second for chip to catch up
  printf("Identifying chip...");
  //enable SPI
  bo(0xAC);bo(0x53);bo(0x00);bo(0x69); //send code AC,53,00,69 to chip
  usleep(100000); //wait for chip to catch up
  //get sig (this part works 50% of the time)
  bo(0x28);bo(0x0);bo(0x0);int bin=bi(); //send code 28,0,0 and read last byte
  if (bin != 0x1E){
printf("Bad signature on micro\n");
outb(0x0,0x378); //reset=low for bin != 1Eh
return -1;
  }
  printf("OK\n");
  //erase
  printf("Erasing old data on chip...");
  bo(0xAC);bo(0x80);bo(0x0);bo(0x0);usleep(100); //send AC,80,0,0 and wait 100uS
  //This part works 50% of the time
  //(check memory address 0000h, and FFFFh, but highest 3 bits are ignored by microcontroller
  // but I don't care. Returning FFh means byte is erased)
  printf("validate 1...");do{usleep(100);bo(0x20);bo(0);bo(0);}while(bi() != 0xFF);
  printf("validate 2...");do{usleep(100);bo(0x20);bo(0xFF);bo(0xFF);}while(bi() != 0xFF);
  printf("OK\n");
  printf("Writing %d bytes of data.",fs);
  int an;fm=1; //fm=fast mode=1 (less sleep time between port instructions)
  for (an=0;an<fs;an++){ //loop through all bytes
  unsigned char rb,byt=(unsigned char)x051[an]; //convert each into unsigned char
  bo(0x40);bo(an/256);bo(an%256);bo(byt); //write value of byt to counter value address
  printf("%d/%d bytes written. ",an,fs); //and show progress
  int sv=0; //set sleep value (sv) and receive byte (rb) to zero
  do{
//loop is always stuck at 256th byte
if (sv==1){fm=0;printf("Chip catching up...");};
usleep(sv*1000); //wait longer each time verification fails
bo(0x20);bo(an/256);bo(an%256);rb=bi(); Read byte at same location byte was written to. Value returned in rb
sv++; //increment sleep value for each verification failure
if (sv > 101){
  printf("retrying...");bo(0x40);bo(an/256);bo(an%256);bo(byt);sv=0; //write byte to same location once more to wake up chip
}
  }while(rb != byt);
  fm=1;
  printf("\n");
  }
  //we never get here
  printf("** write done\n");
  outb(0x0,0x378);
  printf("** ALL DONE and program running**\n\n");
  return 0;
}
0

There are 0 best solutions below