Programmieren von PIC18F2550 mit einem Arduino

Ich versuche, einen Niederspannungsmodus-Programmierer für den PIC18F2550 in einem Arduino Uno gemäß diesen Programmierspezifikationen zu implementieren.

Bitsequenzen werden vom niedrigstwertigen Bit bis zum höchstwertigen Bit in den PIC geschrieben. Außerdem habe ich die im Datenblatt angegebenen Mindestverzögerungen berücksichtigt, es scheint keine maximalen Verzögerungen zu geben, mit Ausnahme der MCLR / Vpp-Anstiegszeit.

Um meinen Code zu validieren, möchte ich die DeviceID unter Adresse 0x3ffffe und 0x3fffff lesen. Hier ist mein Code:

    /* 
 * Trying to build an arduino pic programmer for the PIC18F2550
 * Programming specifications: http://ww1.microchip.com/downloads/en/DeviceDoc/39622L.pdf
 * Author: Ingmar Jager
 */

//Arduino Pinout
int pgc = 9;  // program clock
int pgd = 8;  // program data
int pgm = 10;  // program mode
int MCLR = 11; //Master Clear Reset / Vpp

void setup()
{
  Serial.begin(9600);

  pinMode(pgc, OUTPUT);
  pinMode(pgd, OUTPUT);
  pinMode(pgm, OUTPUT);
  pinMode(MCLR, OUTPUT);
  digitalWrite(pgc, LOW);
  digitalWrite(pgd, LOW);
  digitalWrite(pgm, LOW);
  digitalWrite(MCLR, LOW);
  delay(500);

  enterProgramming();
  delay(500);
  tableRead(0x3F, 0xFF, 0xFF); //read DeviceID2 at 0x3FFFFF. Should be 0x12 = 00010010

  //delay(500);
  tableRead(0x3F, 0xFF, 0xFF);
 // delay(500);
  tableRead(0x3F, 0xFF, 0xFF);
  exitingProgramming();
}

/*
 * @param: three bytes which form the tablepointer address
 */
void setTablePTR(int addr_upper_byte,int addr_half_byte,int addr_lower_byte)
{

 Serial.print("Set TablePTR to: 0x");
 Serial.print(addr_upper_byte, HEX);
 Serial.print(addr_half_byte, HEX);
 Serial.println(addr_lower_byte, HEX);


 writeBits(4, 0x0); // 4 bit command

 writeBits(16, (0x0E << 8) + addr_upper_byte); // 16 bit data payload: load address

 writeBits(4, 0x0); 
 writeBits(16, 0x6EF8);  // set TBLPTR_U to addr_upper_byte

 writeBits(4, 0x0);
 writeBits(16, (0x0E << 8) + addr_half_byte);

 writeBits(4, 0x0);
 writeBits(16, 0x6EF7); //TBLPTR_H

 writeBits(4, 0x0);
 writeBits(16, (0x0E << 8) + addr_lower_byte);

 writeBits(4, 0x0);
 writeBits(16, 0x6EF6); //TBLPTR_L

}

/*
 * Read byte from the given address
 */
void tableRead(int high_byte, int mid_byte, int low_byte)
{

  setTablePTR(high_byte,mid_byte,low_byte);

  writeBits(4, 0x9); //1000 = Read and no increment
  writeBits(8, 0x00);
  pinMode(pgd, INPUT);
  delayMicroseconds(5); //P6 

  byte data = 0;
  //actual read
  Serial.print("Read bits from LSB to MSB: ");
  for (int i = 0; i < 8; i++)
  {
    digitalWrite(pgc, HIGH);
    delayMicroseconds(3); //P14 

    if (digitalRead(pgd)==HIGH)
    {
      Serial.print("1");
      data += (1 << i);
    }
    else
    {
      Serial.print("0");
    }

    digitalWrite(pgc, LOW);
        delayMicroseconds(3); 
  }  

  delayMicroseconds(5); //P5A
  pinMode(pgd, OUTPUT);
  Serial.println();
  Serial.print("Reading result: ");
  Serial.println(data);

}

/* Write LSB to MSB
 * @param n = number of bits to write
 * @param value = value to write in n bits
 */
void writeBits(int n, int value)
{

  for (int i = 0; i < n; i++) {
   if(boolean ((value >> i) & 1))
     {   
       digitalWrite(pgd,HIGH);
     //   Serial.println("Write High");
     } // else Serial.println("Write Low");
  }   
  digitalWrite(pgc, HIGH);
  delayMicroseconds(3);
  digitalWrite(pgc, LOW);
  delayMicroseconds(3);
  digitalWrite(pgd,LOW);
  delayMicroseconds(5); //P5A
} 

/*
 * Entering low voltage programming signals
 */
void enterProgramming()
{
   digitalWrite(pgc, LOW);
   digitalWrite(pgd, LOW);
   digitalWrite(pgm, LOW);
   digitalWrite(MCLR, LOW);

   delayMicroseconds(20);

   digitalWrite(pgm, HIGH);
   delayMicroseconds(3);//P15
   digitalWrite(MCLR, HIGH);
   delayMicroseconds(3);//P12
   Serial.println("Entered Low Voltage Programming");
}

/*
 * Exiting low voltage programming signals
 */
void exitingProgramming()
{
   digitalWrite(pgc, LOW);
   digitalWrite(pgd, LOW);
   delayMicroseconds(1); //P16
   digitalWrite(MCLR, LOW);
   delayMicroseconds(1); //P18
   digitalWrite(pgm, LOW);
   Serial.println("Exiting Low Voltage Programming");
}


void loop()
{

}

Dieser Code wechselt in den Programmiermodus, versucht dann dreimal hintereinander von 0x3fffff zu lesen und verlässt schließlich den Programmiermodus. Schade, dass ich drei verschiedene Ergebnisse bekomme, anscheinend lese ich die DeviceID nicht ... Das gedruckte Ergebnis ist:

Entered Low Voltage Programming
Set TablePTR to: 0x3FFFFE
Read bits from LSB to MSB: 00000111
Reading result: 224
Set TablePTR to: 0x3FFFFF
Read bits from LSB to MSB: 00011111
Reading result: 248
Set TablePTR to: 0x3FFFFF
Read bits from LSB to MSB: 00000000
Reading result: 0
Exiting Low Voltage Programming

Wenn ich einen anderen PIC18F2550 anschließe, unterscheiden sich die Ergebnisse. Jetzt weiß ich nicht, wie ich dieses Projekt weiter debuggen soll. Hat jemand Erfahrung mit diesem Thema und/oder einen Vorschlag?

ps Ich weiß, es ist einfacher, einfach einen Programmierer zu verwenden, aber das macht mehr Spaß;)

Haben Sie sich eine der Linien mit einem Oszilloskop angesehen, um Ihr Timing zu überprüfen? Ich würde den Verzögerungsfunktionen nicht vertrauen, dass sie bei niedrigen Werten sehr genau sind.
@AngryEE, Sie haben Recht, wenn Sie den Verzögerungsfunktionen nicht vertrauen, es werden jedoch keine Maxima für die Verzögerungen angegeben. Also ich denke das sollte kein Problem sein. Wenn ich ein Zielfernrohr in die Hände bekomme, werde ich es aber überprüfen.

Antworten (1)

Das erste, was Sie tun müssen, um so etwas zu debuggen, ist zu überprüfen, ob Sie wirklich in den Programmiermodus gewechselt sind. Der zuverlässigste Weg ist die Eingabe im Hochspannungs-Programmiermodus. Stellen Sie sicher, dass der PGM-Pin während dieser Zeit niedrig gehalten wird. Stellen Sie außerdem sicher , dass alle Strom- und Erdungsstifte verbunden sind, unabhängig davon, ob Sie sie verwenden oder nicht, mit einer Bypass-Kappe an jedem Stromstift.

Um zu überprüfen, ob Sie in den Programmiermodus gegangen sind, schalten Sie etwas ein, das PGD ansteuern sollte, wie das Zurücklesen der TABLAT-Anweisung (0010). Darauf folgen 8 Null-Bits, dann sollte der Zielchip bei der nächsten ansteigenden Flanke von PGC zum Ansteuern von PGD umschalten, nachdem er zuvor eine hohe Impedanz hatte.

Wenn das funktioniert, ist als nächstes das Auslesen der Geräte-ID, da dies immer ein fester bekannter Wert ist. Dies ist komplizierter, da Sie Kernanweisungen ausführen müssen, um die drei Bytes von TBLPTR zu laden, und dann einen Lesevorgang durchführen müssen.

Da all diese Interaktionen synchron sind und Ihnen die Uhr gehört, können Sie so langsam vorgehen, wie Sie möchten, und alles auf dem Oszilloskop Stück für Stück beobachten.

Es wäre hilfreich, wenn Sie genau beschreiben würden, wie Ihr Prozess Ihrer Meinung nach aussieht, um diese Operationen durchzuführen. Nein, ich werde nicht nach Arduino-Code suchen. Es gibt zu viel zwischen dem und den PGC- und PGD-Linien.

Danke @Oline! Was ich versucht habe: Zuerst in den Programmiermodus wechseln. Zweitens: Setzen Sie TBLPTR auf 0x3FFFFF. Senden Sie dann den Read-No-Increment (1000)-Befehl, gefolgt von 8 Null-Bits. Anschließend Auslesen der nächsten 8 Takte aus PGD. Aber ich werde jetzt versuchen, das TABLAT-Register auszulesen.
Der Versuch, das High-Byte der DEV-ID zu lesen, sollte auch als Test funktionieren. In Ihrem Fall sollten Sie 12 Stunden bekommen. Überprüfen Sie, ob der PIC PGD nach der ansteigenden Flanke von PGC nach den 8 Nullbits ansteuert. Wenn ja, haben Sie TBLPTR wahrscheinlich nicht richtig geladen.