Electronic – arduino – PIC programmer problems reading and writing program configuration memory

arduinopicprogrammer

I was making a programmer for pic16f877a using arduino with the help of the programming specification document as I can't find any good one around here at the time.
I was able to write code in the user program memory and read it back in low voltage programming mode (and I'm very confident this process is successful) but I didn't write anything in the configuration memory.

The project didn't work (a simple blinking LED), so i made some research and found that it might be the 2 bits in the configuration word that define the type of the clock (supposedly RC oscillator by default) and it must be changed to another type. so i tried accessing and editing the configuration word using the commands given in the document but I always only read zeros whatever I do, even if I make a chip erase command at the configuration memory.

I know that this is very hard to answer as the programming protocol is specific to the device but I will really appreciate it if someone could give me a hint, and if there is any missing information just tell me in a comment and I will edit the question to add them.

Here is my code for accessing and reading the configuration word:

#define MCLR 8
#define PGM 9
#define DATA 10
#define CLK 11

  /*
    MCLR -> MCLR
    PGM -> RB3
    data -> RB7
    clk -> RB6
  */


void setup() {
  pinMode(MCLR, OUTPUT);
  pinMode(PGM, OUTPUT);
  pinMode(DATA, OUTPUT);
  pinMode(CLK, OUTPUT);

  digitalWrite(DATA, LOW);
  digitalWrite(CLK, LOW);
  digitalWrite(PGM, LOW);
  digitalWrite(MCLR, LOW);

  Serial.begin(9600);
  while(Serial.available() == 0);

  // Low voltage programming
  digitalWrite(PGM, HIGH);
  delayMicroseconds(1);
  digitalWrite(MCLR, HIGH);
  delayMicroseconds(10);


  loadConfig();
  for (int i = 0; i < 7; i++)
  {
     increment(); 
  }
  Serial.print(readData(),DEC);

}

void loop() {
  // no need

}

void writeBit(int a)
{
  digitalWrite(DATA, a);
  digitalWrite(CLK, HIGH);
  delayMicroseconds(1);
  digitalWrite(CLK, LOW);
  delayMicroseconds(1);
  digitalWrite(DATA, LOW);
}

byte readBit()
{
  byte _bit;
  digitalWrite(CLK, HIGH);
  delayMicroseconds(1);
  _bit = digitalRead(DATA);
  digitalWrite(CLK, LOW);
  delayMicroseconds(1);
  return _bit;
}

void sendCommand(char command)
{
  for (int i = 1; i <= 0b100000; i *= 2)
  {
    writeBit((command & i) >= 1);
  }
}
uint16_t readData()
{
    sendCommand(0b000100);
    delayMicroseconds(2);
    uint16_t value = 0;
    pinMode(DATA, INPUT);
    readBit();
    for(int i = 0; i < 14; i++)
    {
        value = (value<<1) | readBit();
    }
    readBit();
    pinMode(DATA, OUTPUT);
    return value;
}

void loadConfig()
{
    sendCommand(0b000000);
    delay(2);
}

void increment()
{
   sendCommand(0b000110);
   delayMicroseconds(2);
}

In short I am driving the MCU into low voltage programming mode, which appears to be working, the sending a command to move the program counter to the configuration memory, then incrementing the program counter till it reaches the configuration word address 2007h, then reading the word at this address.

There is another part for writing the code but I didn't add it here.

All of this is described in the programming document here

Best Answer

So I managed to read and write the configuration word by sending an unprogrammed data word (i.e. writing a word of all ones or 0x3FFF as a word is 14-bit) just after the load configuration command and before incrementing seven times.

It turns out that this is the typical way of writing the configuration word and yet the programming specification didn't bother mentioning it and I actually read the programming specification of a handful of different models until I found this information.

So, my advice is if you have a similar problem and can't find the solution in your data sheet or so, go check the similar models' documents and maybe you can find a hint or two to solve your problem.