Created
March 9, 2018 19:52
-
-
Save bkifft/4953f848fd4fda0b93b42e838dd23b94 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//raspberry pi based pic 18f2550 programmer | |
//only meant as a bootstrap (e.g. for http://openprog.altervista.org/OP_eng.html), not for production use | |
//only bulk erases then writes programm data (including empty areas) and config, does no verification. | |
//hardcoded to 16bit adresses for program data (search for "//WARNING" to find the location) | |
//based on rpp by Giorgio Vazzana (http://holdenc.altervista.org/rpp/rpp.html) | |
/* | |
* Raspberry Pi PIC Programmer using GPIO connector | |
* Copyright 2012 Giorgio Vazzana | |
* | |
* 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 3 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, see <http://www.gnu.org/licenses/>. | |
*/ | |
/* Compile: gcc -Wall -O rpp.c -o rpp */ | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#include <stdint.h> | |
#include <sys/types.h> | |
#include <sys/stat.h> | |
#include <fcntl.h> | |
#include <sys/mman.h> | |
#include <unistd.h> | |
/* GPIO registers address */ | |
#define BCM2708_PERI_BASE 0x20000000 | |
#define GPIO_BASE (BCM2708_PERI_BASE + 0x200000) /* GPIO controller */ | |
#define BLOCK_SIZE (256) | |
/* GPIO setup macros. Always use GPIO_IN(x) before using GPIO_OUT(x) or GPIO_ALT(x,y) */ | |
#define GPIO_IN(g) *(gpio+((g)/10)) &= ~(7<<(((g)%10)*3)) | |
#define GPIO_OUT(g) *(gpio+((g)/10)) |= (1<<(((g)%10)*3)) | |
#define GPIO_ALT(g,a) *(gpio+(((g)/10))) |= (((a)<=3?(a)+4:(a)==4?3:2)<<(((g)%10)*3)) | |
#define GPIO_SET(g) *(gpio+7) = 1<<(g) /* sets bit which are 1, ignores bit which are 0 */ | |
#define GPIO_CLR(g) *(gpio+10) = 1<<(g) /* clears bit which are 1, ignores bit which are 0 */ | |
#define GPIO_LEV(g) (*(gpio+13) >> (g)) & 0x00000001 | |
/* GPIO <-> PIC connections */ | |
#define PIC_CLK 4 /* Output */ | |
#define PIC_DATA 7 /* Output */ | |
#define PIC_DATAIN 8 /* Input */ | |
#define PIC_MCLR 9 /* Output */ | |
#define DELAY 40 /* microseconds */ | |
// specific for 18f2550 | |
#define PROGSIZE 0x8000 | |
#define EEPROMSIZE 256 | |
#define EEPROMOFFSET 0xF00000 | |
#define CONFIGSIZE 0xE | |
#define CONFIGOFFSET 0x300000 | |
#define WRITEBUFFERSIZE 32 | |
#define PIC18F2550_ID 0x1240 | |
#define DELAY_BASE 5 //microseconds, 5 taken as a security margin | |
#define DELAY_P9 DELAY_BASE * 1000 | |
#define DELAY_P10 DELAY_BASE * 100 | |
#define DELAY_P11 DELAY_BASE * 5000 | |
struct picmemory { | |
uint32_t program_memory_used_cells; | |
uint32_t program_memory_max_used_address; | |
uint8_t has_configuration_data; | |
uint8_t has_eeprom_data; | |
uint8_t *program_data; /* 8-bit data */ | |
uint8_t *program_filled; /* 1 if this cell is used */ | |
uint8_t *eeprom_data; /* 8-bit data */ | |
uint8_t *eeprom_filled; /* 1 if this cell is used */ | |
uint8_t *config_data; | |
}; | |
int mem_fd; | |
void *gpio_map; | |
volatile uint32_t *gpio; | |
/* Set up a memory regions to access GPIO */ | |
void setup_io() | |
{ | |
/* open /dev/mem */ | |
mem_fd = open("/dev/mem", O_RDWR|O_SYNC); | |
if (mem_fd == -1) { | |
perror("Cannot open /dev/mem, run as root"); | |
exit(1); | |
} | |
/* mmap GPIO */ | |
gpio_map = mmap(NULL, BLOCK_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, mem_fd, GPIO_BASE); | |
if (gpio_map == MAP_FAILED) { | |
perror("mmap() failed"); | |
exit(1); | |
} | |
/* Always use volatile pointer! */ | |
gpio = (volatile uint32_t *)gpio_map; | |
/* Configure GPIOs */ | |
GPIO_IN(PIC_CLK); /* must use GPIO_IN before we can use GPIO_OUT */ | |
GPIO_OUT(PIC_CLK); | |
GPIO_IN(PIC_DATA); | |
GPIO_OUT(PIC_DATA); | |
GPIO_IN(PIC_DATAIN); | |
GPIO_IN(PIC_MCLR); | |
GPIO_OUT(PIC_MCLR); | |
GPIO_CLR(PIC_CLK); | |
GPIO_CLR(PIC_DATA); | |
GPIO_CLR(PIC_DATAIN); | |
GPIO_CLR(PIC_MCLR); | |
usleep(DELAY); | |
} | |
/* Release GPIO memory region */ | |
void close_io() | |
{ | |
int ret; | |
/* munmap GPIO */ | |
ret = munmap(gpio_map, BLOCK_SIZE); | |
if (ret == -1) { | |
perror("munmap() failed"); | |
exit(1); | |
} | |
/* close /dev/mem */ | |
ret = close(mem_fd); | |
if (ret == -1) { | |
perror("Cannot close /dev/mem"); | |
exit(1); | |
} | |
} | |
void free_picmemory(struct picmemory **ppm) | |
{ | |
free((*ppm)->program_data); | |
free((*ppm)->program_filled); | |
free((*ppm)->eeprom_data); | |
free((*ppm)->eeprom_filled); | |
free((*ppm)->config_data); | |
free(*ppm); | |
} | |
/* Read a file in Intel HEX 16-bit format and return a pointer to the picmemory | |
struct on success, or NULL on error */ | |
struct picmemory *read_inhx16(char *infile, int debug) | |
{ | |
FILE *fp; | |
int linenum; | |
char line[256], *ptr; | |
size_t linelen; | |
int nread; | |
uint16_t adress_offset; | |
uint8_t adress_ok; | |
uint16_t i; | |
uint8_t start_code; | |
uint8_t byte_count; | |
uint16_t address; | |
uint8_t record_type; | |
uint16_t data; | |
struct picmemory *pm; | |
fp = fopen(infile, "r"); | |
if (fp == NULL) { | |
fprintf(stderr, "Error: cannot open source file %s.\n", infile); | |
return NULL; | |
} | |
pm = calloc(1, sizeof(*pm)); | |
if (pm) { | |
pm->program_data = calloc(PROGSIZE, sizeof(*pm->program_data)); | |
pm->program_filled = calloc(PROGSIZE, sizeof(*pm->program_filled)); | |
pm->eeprom_data = calloc(EEPROMSIZE, sizeof(*pm->eeprom_data)); | |
pm->eeprom_filled = calloc(EEPROMSIZE, sizeof(*pm->eeprom_filled)); | |
pm->config_data = calloc(CONFIGSIZE, sizeof(*pm->config_data)); | |
} | |
if (!pm || !pm->program_data || !pm->program_filled || !pm->eeprom_data || !pm->eeprom_filled || !pm->config_data) { | |
fprintf(stderr, "Error: calloc() failed.\n"); | |
free_picmemory(&pm); | |
return NULL; | |
} | |
fprintf(stderr, "Reading hex file...\n"); | |
linenum = 0; | |
adress_offset = 0; | |
while (1) { | |
ptr = fgets(line, 256, fp); | |
adress_ok = 0; | |
if (ptr != NULL) { | |
linenum++; | |
linelen = strlen(line); | |
if (debug) { | |
fprintf(stderr, " line %d (%zd bytes): '", linenum, linelen); | |
for (i = 0; i < linelen; i++) { | |
if (line[i] == '\n') | |
fprintf(stderr, "\\n"); | |
else if (line[i] == '\r') | |
fprintf(stderr, "\\r"); | |
else | |
fprintf(stderr, "%c", line[i]); | |
} | |
fprintf(stderr, "'\n"); | |
} | |
start_code = line[0]; | |
if (start_code != ':') { | |
fprintf(stderr, "Error: invalid start code.\n"); | |
free_picmemory(&pm); | |
return NULL; | |
} | |
nread = sscanf(&line[1], "%2hhx", &byte_count); | |
if (nread != 1) { | |
fprintf(stderr, "Error: cannot read byte count.\n"); | |
free_picmemory(&pm); | |
return NULL; | |
} | |
if (debug) | |
fprintf(stderr, " byte_count = 0x%02X\n", byte_count); | |
nread = sscanf(&line[3], "%4hx", &address); | |
if (nread != 1) { | |
fprintf(stderr, "Error: cannot read address.\n"); | |
free_picmemory(&pm); | |
return NULL; | |
} | |
if (debug) | |
fprintf(stderr, " address = 0x%04X\n", address); | |
nread = sscanf(&line[7], "%2hhx", &record_type); | |
if (nread != 1) { | |
fprintf(stderr, "Error: cannot read record type.\n"); | |
free_picmemory(&pm); | |
return NULL; | |
} | |
if (debug) | |
fprintf(stderr, " record_type = 0x%02X (%s)\n", record_type, record_type == 0 ? "data" : (record_type == 1 ? "EOF" : (record_type == 4 ? "adress offset" : "Unknown"))); | |
if (record_type != 0 && record_type != 1 && record_type != 4) { | |
fprintf(stderr, "Error: unknown record type.\n"); | |
free_picmemory(&pm); | |
return NULL; | |
} | |
if (4 == record_type) | |
adress_offset = address << 16; | |
for (i = 0; i < byte_count; i++) { | |
nread = sscanf(&line[9+2*i], "%2hx", &data); | |
adress_ok = 0; | |
if (nread != 1) { | |
fprintf(stderr, "Error: cannot read data.\n"); | |
free_picmemory(&pm); | |
return NULL; | |
} | |
if (debug) | |
fprintf(stderr, " data = 0x%02X\n", data); | |
if (0 == record_type) | |
{ | |
if (address + adress_offset + i < PROGSIZE) | |
{ | |
adress_ok = 1; | |
pm->program_memory_used_cells += 1; | |
pm->program_memory_max_used_address = address + adress_offset + i; | |
if (pm->program_filled[address + adress_offset + i] != 0) | |
fprintf(stderr, " !!data overwrite. adress: 0x%04X old: 0x%02X new: 0x%02X\n", address + adress_offset + i, pm->program_data[address + adress_offset + i], data); | |
pm->program_data[address + adress_offset + i] = data; | |
pm->program_filled[address + adress_offset + i] = 1; | |
} | |
if (CONFIGOFFSET <= address + adress_offset + i && address + adress_offset + i <= CONFIGOFFSET + CONFIGSIZE) | |
{ | |
adress_ok = 1; | |
pm->has_configuration_data = 1; | |
pm->config_data[address + adress_offset + i - CONFIGOFFSET] = data; | |
} | |
if (EEPROMOFFSET <= address + adress_offset + i && address + adress_offset + i <= EEPROMOFFSET + EEPROMSIZE) | |
{ | |
adress_ok = 1; | |
pm->has_eeprom_data = 1; | |
pm->eeprom_data[address + adress_offset + i - EEPROMOFFSET] = data; | |
pm->eeprom_filled[address + adress_offset + i - EEPROMOFFSET] = 1; | |
} | |
if (0 == adress_ok) | |
{ | |
fprintf(stderr, "Error: adress out of bounds: 0x%08X\n", address + adress_offset + i); | |
free_picmemory(&pm); | |
return NULL; | |
} | |
} | |
} | |
if (debug) | |
fprintf(stderr, "\n"); | |
if (record_type == 1) | |
break; | |
} else { | |
fprintf(stderr, "Error: unexpected EOF.\n"); | |
free_picmemory(&pm); | |
return NULL; | |
} | |
} | |
fclose(fp); | |
return pm; | |
} | |
/* Send a 4-bit command to the PIC */ | |
void pic_send_cmd(uint8_t cmd) | |
{ | |
int i; | |
for (i = 0; i < 4; i++) { | |
GPIO_SET(PIC_CLK); | |
if ((cmd >> i) & 0x01) | |
GPIO_SET(PIC_DATA); | |
else | |
GPIO_CLR(PIC_DATA); | |
usleep(DELAY); /* Setup time */ | |
GPIO_CLR(PIC_CLK); | |
usleep(DELAY); /* Hold time */ | |
} | |
GPIO_CLR(PIC_DATA); | |
usleep(DELAY); | |
} | |
/* Send 16-bit data to the PIC */ | |
void pic_send_data(uint16_t data) | |
{ | |
int i; | |
for (i = 0; i < 16; i++) { | |
GPIO_SET(PIC_CLK); | |
if ((data >> i) & 0x01) | |
GPIO_SET(PIC_DATA); | |
else | |
GPIO_CLR(PIC_DATA); | |
usleep(DELAY); /* Setup time */ | |
GPIO_CLR(PIC_CLK); | |
usleep(DELAY); /* Hold time */ | |
} | |
GPIO_CLR(PIC_DATA); | |
usleep(DELAY); | |
} | |
void pic_bulk_erase() | |
{ | |
/* per spec: | |
4bit-cmd data | |
0000 0E3C //1 | |
0000 6EF8 | |
0000 0E00 | |
0000 6EF7 | |
0000 0E05 //5 | |
0000 6EF6 | |
1100 3F3F | |
0000 0E3C | |
0000 6EF8 | |
0000 0E00 //10 | |
0000 6EF7 | |
0000 0E04 | |
0000 6EF6 | |
1100 8F8F | |
0000 0000 //15 | |
0000 [sleep 5 ms (5000 microseconds) + 100 microseconds] 0000 | |
*/ | |
GPIO_SET(PIC_MCLR); | |
usleep(DELAY); | |
pic_send_cmd(0x00); //1 | |
pic_send_data(0x0E3C); | |
pic_send_cmd(0x00); //2 | |
pic_send_data(0x6EF8); | |
pic_send_cmd(0x00); //3 | |
pic_send_data(0x0E00); | |
pic_send_cmd(0x00); //4 | |
pic_send_data(0x6EF7); | |
pic_send_cmd(0x00); //5 | |
pic_send_data(0x0E05); | |
pic_send_cmd(0x00); //6 | |
pic_send_data(0x6EF6); | |
pic_send_cmd(0x0C); //7 | |
pic_send_data(0x3F3F); | |
pic_send_cmd(0x00); //8 | |
pic_send_data(0x0E3C); | |
pic_send_cmd(0x00); //9 | |
pic_send_data(0x6EF8); | |
pic_send_cmd(0x00); //10 | |
pic_send_data(0x0E00); | |
pic_send_cmd(0x00); //11 | |
pic_send_data(0x6EF7); | |
pic_send_cmd(0x00); //12 | |
pic_send_data(0x0E04); | |
pic_send_cmd(0x00); //13 | |
pic_send_data(0x6EF6); | |
pic_send_cmd(0x0C); //14 | |
pic_send_data(0x8F8F); | |
pic_send_cmd(0x00); //15 | |
pic_send_data(0x0000); | |
pic_send_cmd(0x00); | |
usleep(DELAY_P10 + DELAY_P11); | |
pic_send_data(0x0000); | |
GPIO_CLR(PIC_MCLR); | |
usleep(DELAY); | |
} | |
void nop_p9_p10() | |
{ | |
GPIO_CLR(PIC_DATA); | |
GPIO_SET(PIC_CLK); //up1 | |
usleep(DELAY); | |
GPIO_CLR(PIC_CLK); | |
usleep(DELAY); | |
GPIO_SET(PIC_CLK); //up2 | |
usleep(DELAY); | |
GPIO_CLR(PIC_CLK); | |
usleep(DELAY); | |
GPIO_SET(PIC_CLK); //up3 | |
usleep(DELAY); | |
GPIO_CLR(PIC_CLK); | |
usleep(DELAY); | |
GPIO_SET(PIC_CLK); | |
usleep(DELAY_P9); | |
GPIO_CLR(PIC_CLK); | |
usleep(DELAY_P10); | |
pic_send_data(0x0000); | |
usleep (DELAY); //doesn't hurt | |
} | |
/* Bulk erase the chip, and then write contents of the .hex file to the PIC */ | |
void pic_write(char *infile, int debug) | |
{ | |
//int error = 0; | |
struct picmemory *pm; | |
int adress; | |
int offset; | |
pm = read_inhx16(infile, debug); | |
if (!pm) | |
return; | |
/* Bulk erase the chip first */ | |
pic_bulk_erase(); | |
fprintf(stderr, "Writing chip...\n"); | |
GPIO_SET(PIC_MCLR); | |
usleep(DELAY); | |
/*writing per spec: | |
enable writemode: | |
0000 8EA6 //1 | |
0000 9CA6 //2 | |
set write start adress: | |
0000 0E[adress21:16] //3 | |
0000 6EF8 //4 | |
0000 0E[adress15:08] //5 | |
0000 6EF7 //6 | |
0000 0E[adress07:01] //7 | |
0000 6EF6 //8 | |
push all but last two program bytes: | |
loop: | |
1101 2byteDATA | |
last two bytes: | |
1111 2byteDATA | |
SPECIAL: data low. three regular clocks (up and down). clock high. hold for P9. clock low. hold for P10. send regular data 0x0000 . | |
*/ | |
for (adress = 0; adress < PROGSIZE; adress += WRITEBUFFERSIZE) | |
{ | |
fprintf(stderr, "Writing program, adress: 0x%08X ", adress); | |
pic_send_cmd(0x00); //1 | |
pic_send_data(0x8EA6); | |
pic_send_cmd(0x00); //2 | |
pic_send_data(0x9CA6); | |
pic_send_cmd(0x00); //3 | |
pic_send_data(0x0E00); //WARNING: lazy ass hardcoded | |
pic_send_cmd(0x00); //4 | |
pic_send_data(0x6EF8); | |
pic_send_cmd(0x00); //5 | |
pic_send_data(0x0E00 | (adress >> 8)); | |
pic_send_cmd(0x00); //6 | |
pic_send_data(0x6EF7); | |
pic_send_cmd(0x00); //7 | |
pic_send_data(0x0E00 | ( adress & 0x00FF ) ); | |
pic_send_cmd(0x00); //8 | |
pic_send_data(0x6EF6); | |
for (offset = 0; offset < WRITEBUFFERSIZE - 2 ; offset += 2) | |
{ | |
fprintf(stderr, "0x%04X ", (pm->program_data[adress + offset] << 8) | pm->program_data[adress + offset + 1]); | |
pic_send_cmd(0x0D); | |
pic_send_data( (pm->program_data[adress + offset] << 8) | pm->program_data[adress + offset + 1]); | |
} | |
offset += 2; | |
pic_send_cmd(0x0F); | |
pic_send_data( (pm->program_data[adress + offset] << 8) | pm->program_data[adress + offset + 1]); | |
fprintf(stderr, "\n"); | |
nop_p9_p10(); | |
} | |
////config////////////////////////////////////////////////////// | |
fprintf(stderr, "Writing config...\n"); | |
for (adress = 0; adress < CONFIGSIZE; adress++) | |
{ | |
pic_send_cmd(0x00); //1 | |
pic_send_data(0x8EA6); | |
pic_send_cmd(0x00); //2 | |
pic_send_data(0x8CA6); | |
pic_send_cmd(0x00); //3 | |
pic_send_data(0x0E30); | |
pic_send_cmd(0x00); //4 | |
pic_send_data(0x6EF8); | |
pic_send_cmd(0x00); //5 | |
pic_send_data(0x0E00); | |
pic_send_cmd(0x00); //6 | |
pic_send_data(0x6EF7); | |
pic_send_cmd(0x00); //7 | |
pic_send_data(0x0E00 | adress ); | |
pic_send_cmd(0x00); //8 | |
pic_send_data(0x6EF6); | |
pic_send_cmd(0x0F); | |
if(!(adress&0x01)) | |
{ | |
fprintf(stderr, "Adress: 0x%08X 0x%04X\n",adress, 0x0000 | pm->config_data[adress]<<8); | |
pic_send_data(0x0000 | pm->config_data[adress]<<8 ); | |
} | |
else | |
{ | |
fprintf(stderr, "Adress: 0x%08X 0x%04X\n",adress, 0x0000 | pm->config_data[adress]); | |
pic_send_data(0x0000 | pm->config_data[adress] ); | |
} | |
nop_p9_p10(); | |
} | |
///end config | |
GPIO_CLR(PIC_MCLR); | |
usleep(DELAY); | |
} | |
int main(int argc, char *argv[]) | |
{ | |
pic_bulk_erase(); | |
pic_write(argv[1], 1); | |
close_io(); | |
return 0; | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment