picchick

A utility to aid in programming PIC microcontrollers

#include <Arduino.h>

#include "icsp_commands.h"

uint8_t icsp_startup_key_bytes[] = ICSP_STARTUP_KEY;

void icsp_init_pins(void)
{
    pinMode(PIN_ICSP_DAT, OUTPUT); // Configure our DAT pin as an output and set it low
    digitalWrite(PIN_ICSP_DAT, LOW);

    pinMode(PIN_ICSP_CLK, OUTPUT); // COnfigure our CLK pin and set it low
    digitalWrite(PIN_ICSP_CLK, LOW);

    pinMode(PIN_ICSP_MCLR, OUTPUT); // Configure our reset pin and set it high
    digitalWrite(PIN_ICSP_MCLR, HIGH);
}

void icsp_reset_pins(void)
{
    pinMode(PIN_ICSP_DAT, INPUT); // Configure our DAT pin as an input

    pinMode(PIN_ICSP_CLK, INPUT); // COnfigure our CLK pin as an input

    pinMode(PIN_ICSP_MCLR, INPUT); // Configure our reset pin as input
}


void icsp_enter_program_mode(void)
{
    // To enter program mode, we set MCLR low and shift in the 32 bit startup key
    digitalWrite(PIN_ICSP_MCLR, LOW);

    delayMicroseconds(ICSP_DELAY_ENTH); // Wait a bit

    int i, j;
    for (i=0; i < 4; i++) { // Start with the most significant byte
        for (j=7; j >= 0; j--) { // And the most significant bit
            digitalWrite(PIN_ICSP_CLK, HIGH); // CLK High
            digitalWrite(PIN_ICSP_DAT, bitRead(ICSP_STARTUP_KEY[i],j)); // Set data bit
            delayMicroseconds(ICSP_DELAY_CKH);
            digitalWrite(PIN_ICSP_CLK, LOW);    // CLK Low
            delayMicroseconds(ICSP_DELAY_CKL);
        }
    }
}

void icsp_exit_program_mode(void)
{
    // To exit program mode, we set mclr high
    digitalWrite(PIN_ICSP_MCLR, HIGH);
}

void icsp_write_command(uint8_t command)
{
    // Writes a command to the icsp interface, must be in programming mode.
    // It is the callers responsibilty to send or receive any data that follows the command
    int command_bit;
    for (command_bit=7;command_bit>=0;command_bit--) { // Start with the MSBit of the command
        digitalWrite(PIN_ICSP_CLK, HIGH); // CLK High
        digitalWrite(PIN_ICSP_DAT, bitRead(command, command_bit)); // Set data bit
        delayMicroseconds(ICSP_DELAY_CKH);
        digitalWrite(PIN_ICSP_CLK, LOW);    // CLK Low
        delayMicroseconds(ICSP_DELAY_CKL);
    }
}

void icsp_write_address(uint16_t *address) {

    int i;
    // Clock out 7 clock dummy clocks (1 start and 6 padding 0's)
    for (i=0; i<7; i++) {
        digitalWrite(PIN_ICSP_CLK, HIGH);
        delayMicroseconds(ICSP_DELAY_CKH);
        digitalWrite(PIN_ICSP_CLK, LOW);
        delayMicroseconds(ICSP_DELAY_CKL);
    }

    // Clock out our 16-bit address
    for (i=15; i>=0; i--) {
        digitalWrite(PIN_ICSP_CLK, HIGH);
        digitalWrite(PIN_ICSP_DAT, bitRead(*address, i));
        delayMicroseconds(ICSP_DELAY_CKH);
        digitalWrite(PIN_ICSP_CLK, LOW);
        delayMicroseconds(ICSP_DELAY_CKL);
    }

    // Clock out our stop bit totalling 24 bits
    digitalWrite(PIN_ICSP_CLK, HIGH);
    digitalWrite(PIN_ICSP_DAT, LOW);
    delayMicroseconds(ICSP_DELAY_CKH);
    digitalWrite(PIN_ICSP_CLK, LOW);
    delayMicroseconds(ICSP_DELAY_CKL);
}

void icsp_write_payload(uint16_t *payload)
{
    int i;

    // Clock out 9 dummy clocks
    for (i=0; i<9; i++) {
        digitalWrite(PIN_ICSP_CLK, HIGH);
        delayMicroseconds(ICSP_DELAY_CKH);
        digitalWrite(PIN_ICSP_CLK, LOW);
        delayMicroseconds(ICSP_DELAY_CKL);
    }

    // Clock out our 14-bit payload
    for (i=13; i>=0; i--) {
        digitalWrite(PIN_ICSP_CLK, HIGH);
        digitalWrite(PIN_ICSP_DAT, bitRead(*payload, i));
        delayMicroseconds(ICSP_DELAY_CKH);
        digitalWrite(PIN_ICSP_CLK, LOW);
        delayMicroseconds(ICSP_DELAY_CKL);
    }

    // Clock out our stop bit totalling 24 bits
    digitalWrite(PIN_ICSP_CLK, HIGH);
    digitalWrite(PIN_ICSP_DAT, LOW);
    delayMicroseconds(ICSP_DELAY_CKH);
    digitalWrite(PIN_ICSP_CLK, LOW);
    delayMicroseconds(ICSP_DELAY_CKL);
}

uint16_t icsp_read_word(void) {
    int i;
    uint16_t word = 0;

    // Configure our DAT pin as input
    pinMode(PIN_ICSP_DAT, INPUT);


    // Clock out 9 dummy clocks
    for (i=0; i<9; i++) {
        digitalWrite(PIN_ICSP_CLK, HIGH);
        delayMicroseconds(ICSP_DELAY_CKH);
        digitalWrite(PIN_ICSP_CLK, LOW);
        delayMicroseconds(ICSP_DELAY_CKL);
    }

    // Clock out 14 cycles and read the data bits
    for (i=13; i>=0; i--) {
        digitalWrite(PIN_ICSP_CLK, HIGH);
        delayMicroseconds(ICSP_DELAY_CKH);
        digitalWrite(PIN_ICSP_CLK, LOW);
        word = word | (digitalRead(PIN_ICSP_DAT) << i);
        delayMicroseconds(ICSP_DELAY_CKL);
    }

    // Clock out our stop bit totalling 24 bits
    digitalWrite(PIN_ICSP_CLK, HIGH);
    delayMicroseconds(ICSP_DELAY_CKH);
    digitalWrite(PIN_ICSP_CLK, LOW);
    delayMicroseconds(ICSP_DELAY_CKL);

    // Set DAT pin back to output
    pinMode(PIN_ICSP_DAT, OUTPUT);

    // return result
    return word;
}