# Seeking code for low-voltage programming of enhanced midrange PIC

#### John P

Joined Oct 14, 2008
1,861
I'm trying to write code for a PIC16F690 to program a PIC16F1619--that's an "enhanced midrange" processor which has a low-voltage programming mode, with no need for anything above 5V. The way you get it to work is to pull Reset low, then send a 32-bit code which supposedly puts it into programming mode. So far I've just tried it for the first time, and as far as I can tell, my target processor is staying inert. I have a scope, and I know the PIC16F690 is doing what I've told it to. Before I put more time into this, I thought maybe someone has already got it working and might give me some code. I'm working in Mikro C, but I'm sure any language would make it clear what's supposed to happen.

#### andre_teprom

Joined Jan 17, 2016
31
Have you already checked how the programmer it self could interfere on the status of the core ? Some of them allow you to determine by roper configuration if the reset will be released or not after upload the code to uC.

#### John P

Joined Oct 14, 2008
1,861
You're not understanding my setup. I'm using one processor to program another, without a commercially produced programmer of any kind. And so far, I'm keeping the target processor in reset all the time: what I want to see is a response to a "read" operation, which would confirm that I've got control of the processor.

#### ErnieM

Joined Apr 24, 2011
8,089
All the code I have ever needed is inside the executables of whatever programmer I use. I have PICkit II and III, plus an ICD 3 somewhere.

If you are attempting to program your device without a programmer I suggest you stop and get a proper programmer. You will get the added benefit of doing debugging inside your hardware if you can leave it connected.

Otherwise yes it is barely possible to program these devices without a programmer as they come with low voltage programming enabled. The spec is only 38 pages long: http://ww1.microchip.com/downloads/en/DeviceDoc/40001720C.pdf

#### MMcLaren

Joined Feb 14, 2010
851
Hi John P,

I tried this a couple years ago but couldn't quite get it to work... Last week however I spotted a project on Hackaday.io by Jaromir Sukuba that uses an Arduino to program PIC16F1xxx 'enhanced mid-range' devices using this newer LVP process. Anyway, since this Gentleman got it working I downloaded his 'sketch' and I plan to study the heck out of it while comparing it to the Microchip programming documents.

I'll wish you good luck on your project if you'll do the same for me, Sir.

Cheerful regards, Mike

#### andre_teprom

Joined Jan 17, 2016
31
@john, I believe you are already aware of that, but it's worth to point that. Had you already decreased the clock rate to check if could be happening a load coupling problem among I/Os of both devices ?

#### John P

Joined Oct 14, 2008
1,861
Mike, thanks for the link to the Hackaday project. I've downloaded the code and I'm working through it, and in fact it's C code, which is even better than an Arduino sketch. I'll let you know how things go.

Ernie, I think you're being a bit too conservative. It can be handy to be able to program a processor with minimal equipment--ideally, just another processor, and the low-voltage mode is very tempting. I can live without debugging, but you'll get my oscilloscope when you pry my cold dead fingers off the trigger select knob.

What I've done since posting the first message is to accept that I need to delay the low-voltage programming and just get something working. (Question of keeping up the morale of the troops. I'm sure everyone understands.) So I put together a charge pump running off the PWM output of the PIC16F690, and with that creating a Vpp of about 8V I've been able to establish communication between the processors. So my failure must be with the 32-bit code that enables low-voltage programming mode. I'll try tinkering with it some more, with the Hackaday project to copy.

#### MMcLaren

Joined Feb 14, 2010
851
John, I dug up my code (from 2010, oh my). At the time I was concerned whether or not I was sending the 32 bit "MCHP" pattern (plus one extra clock) correctly to enter programming_mode. Based on Mr. Sukuba's code, it looks like I was... Anyway, I'm going to dig out the prototyping stuff and try this again...

Mike

#### dannyf

Joined Sep 13, 2015
2,197
The best place for such information is the datasheet / programming specification.

The quickest is to repurpose the pickit2 source code.

#### John P

Joined Oct 14, 2008
1,861
I was most concerned about how to get the target processor into programming mode using the low-voltage method, because my version of that didn't work, and the instructions in the programming manual aren't entirely clear about the order of data to be sent. So naturally that's the first thing I looked at in Jaromir Sukuba's C program; thanks for that pointer, Mike! What I saw is that evidently he had his doubts too, because he wrote the code out 4 different ways with variations, and he must have been ready to comment blocks out and try another one in turn. I wonder how many attempts it took him. Or maybe each time he failed, he'd comment out the code and rewrite it, and he got it right the 4th time.

Code:
unsigned char enter_progmode (void)
{
ISP_MCLR_0
_delay_us(300);
/*
isp_send(0b10110010,8);
isp_send(0b11000010,8);
isp_send(0b00010010,8);
isp_send(0b00001010,8);
*/
/*
isp_send(0b01001101,8);
isp_send(0b01000011,8);
isp_send(0b01001000,8);
isp_send(0b01010000,8);
*/
/*
isp_send(0b00001010,8);
isp_send(0b00010010,8);
isp_send(0b11000010,8);
isp_send(0b10110010,8);
*/

isp_send(0b01010000,8);
isp_send(0b01001000,8);
isp_send(0b01000011,8);
isp_send(0b01001101,8);

isp_send(0,1);

}

#### NorthGuy

Joined Jun 28, 2014
611
It takes a while because you don't know if the entry was successful or not until you successfully read something. To make it a little bit easier, program your target with PICKit3 so that you know the first word programmed into the program memory. Then you can clock in the sequence (don't forget the extra 33-rd clock) and then do a read command. As a result of this read, you should read the first word of the program memory, which is known to you, so you will know right away if you're reading correctly. Once you get this right, you know your sequence is correct and you can continue on.

#### ErnieM

Joined Apr 24, 2011
8,089
Look, I've actually made a programmer as part of a test fixture for a PIC based timer. It first programs the device then performs a full acceptance test on it. So I know making a programmer is possible.

I also know I had debuggers and programmers to keep track of what was going on... not only to verify what the target was getting for a program but to watch what the programmer (another PIC) was up to.

While I have the source to look at it is proprietary for a job I did a few years back, thus I cannot release it.

This is not a beginners or even intermediate level task. Collecting bottles for nickles will get you a programmer faster than writing your own. But I can give a few hints as I see them...

Before you program some known data and try to verify it try this: do the Load Configuration command of section 4.3.1 to point to the configuration area. The 6th thing in there is always the device ID, something you should be checking for before programming anyway.

#### MMcLaren

Joined Feb 14, 2010
851
Look, I've actually made a programmer as part of a test fixture for a PIC based timer. It first programs the device then performs a full acceptance test on it. So I know making a programmer is possible.
Fun stuff, isn't it? My first PIC HV programmer design used a 16F88. I remember finding a bug in the 18F2620/18F4620 Programming Spec' which was reported to and corrected by Microchip and then I helped MELabs with a work-around for their Serial Programmer. Here's a picture of the prototype...

Cheerful regards, Mike

Last edited:

#### John P

Joined Oct 14, 2008
1,861
I'd have included a picture of the programmer I made years ago, but I think I dumped it.

Anyway, the progress I've made is that after using high-voltage programming mode just once, I got the low-voltage mode working, with some inspiration from Jaromir Sukuba's code. To convince myself that it works, I used pretty much the method that Ernie suggested, go into the config area and advance the address 6 times, so the active address is the chip ID, and then read that. Now if I'm serious about this, I have to write code to do the actual programming, and that's going to take some time, with work to be done on the PIC16F690 and on the computer, where I have to write something to open a file and send it via a pseudo-serial port on a USB link. I have a UART converter based on the FTDI chip to connect to the PIC.

My program for the PIC16F690 is below, though I'm not sure how useful it would be to anyone. Points to note are that I send data both ways in packets, with a start character 0xFF, an opcode, a receiver/sender address, the number of bytes, the data, and a checksum. So far I'm not using data at all, just looking for particular opcodes. And I like circular buffers, one each for data sent and received. I often make up my own pointers for these and use the FSR register directly.

Code:
#define indirect  indf

#define set_high_bank  status.f7 = 1
#define set_low_bank  status.f7 = 0

#define GOOD_PACKET  100

#define TARGET_POWER_ON  1  // a
#define TARGET_POWER_OFF  2  // b
#define TARGET_RESET_LOW  3  // c
#define TARGET_RESET_HIGH  4  // d
#define ENTER_PROG_MODE  5  // e
#define PWM_ON  6  // f
#define PWM_OFF  7  // g
#define PROGRAM_DATA  9  // i Data from packet gets loaded to memory at current address

#define INT_PROG  8
#define EXT_PROG  0x18
#define END_EXT  0xA
#define BULK_ERASE  9
#define ROW_ERASE  0x11

typedef unsigned char byte;

/* High memory usage
Low bank (0xA0 - 0xEF):
0xA0 - 0xAF
0xB0 - 0xBF
0xC0 - 0xDF  Outgoing serial buffer (incoming_push, incoming_pop)
0xE0 - 0xEF

High bank (0x20 - 0x6F):
0x20 - 0x6F  Incoming serial buffer
*/

byte incoming_push, incoming_pop, incoming_opcode, incoming_nbytes, incoming_address, checksum, tbyte;
byte outgoing_push, outgoing_pop;
byte ser_state=0;

byte outgoing_buffer[32] absolute 0xC0;  // Dummy array to make sure compiler doesn't use this area

byte serial_in(void)
{
byte i;

set_high_bank;
fsr = incoming_pop;
i = indirect;
incoming_pop++;
if (incoming_pop >= 0x70)
incoming_pop = 0x20;
set_low_bank;

switch(ser_state)
{
case 1:
if (i == 0xFF)
ser_state = 0;  // Fail, assume the 0xFF was starting a new packet
else
incoming_opcode = i;  // Opcode
break;
case 2:
if (i == 0xFF)
ser_state = 0;  // Fail, assume the 0xFF was starting a new packet
else
break;
case 3:
if (i == 0xFF)
ser_state = 0;  // Fail, assume the 0xFF was starting a new packet
else
{
incoming_nbytes = i;  // Number of bytes
checksum = incoming_opcode + incoming_nbytes + incoming_address;
tbyte = 0;
}
break;
case 4:
if (tbyte == incoming_nbytes)  // Seen final data byte
{
ser_state = (GOOD_PACKET - 1);
else  // Checksum passes
ser_state = 0xFF;  // Failed packet
break;
}
else
{
if (tbyte < 9)
{
// incoming[tbyte] = i;
tbyte++;  // We can't accept data that overfills the array
}
}
checksum += i;
if (i != 0xFF)
ser_state--;  // Normal condition, value of 4 in ss is repeated}
break;
case 5:  // Last input was 0xFF
if (i == 0xFF)  // 0xFF again, OK
ser_state = 3;  // Next ss is 4, expect regular data
else
{
ser_state = 1;  // Fail, assume the 0xFF was starting a new packet
incoming_opcode = i;  // and this was the opcode, so next ss is 2
}
break;

default:  // Uaually serial_state is 0 here
ser_state = 0;
if (i != 0xFF)
ser_state--;  // Fail, set ss so it gets reset to 0
break;
}  // End switch-case
ser_state++;  // Return 0 for trash chars between packets
return(ser_state);  // GOOD_PACKET for complete packet
}  // Any other value for packet in progress

void interrupt( void)
{
txreg = 0x55;
//bit_clear(pir1, TMR2IF);
}

void send_prog_instr(byte command, unsigned dataa)
{
int i;

(command == INT_PROG) || (command == EXT_PROG) || (command == END_EXT))
command.f7 = 1;  // Flag says no data, just a 6-bit command

for (i = 0; i < 6; i++)
{
if (command.f0 == 1)
else

command >>= 1;
}
if (command.f1 == 1)  // Test flag, return if no data required
return;

dataa <<= 1;
for (i = 0; i < 16; i++)
{
if (dataa & 1)
else

dataa >>= 1;
}
}

void xmit_byte(byte input)
{
fsr = outgoing_push;
indirect = input;
outgoing_push++;
outgoing_push.f5 = 0;
}

{
int i;
union
{
unsigned int in_data16;
byte in_data8[2];
} ind;

ind.in_data16 = 0;
trisc.f7 = 1;

for (i = 0; i < 16; i++)
{
if (portc.f7 == 1)
ind.in_data16 |= 0x4000;

ind.in_data16 >>= 1;
}
trisc.f7 = 0;

xmit_byte(0xFF);
xmit_byte(0);
xmit_byte(2);
xmit_byte(ind.in_data8[1]);
xmit_byte(ind.in_data8[0]);
xmit_byte(MY_ADDR + 2 + (ind.in_data8[0]) + (ind.in_data8[1]));
}

void enter_prog (void)
{
unsigned long mchp32 = ('M' << 24) + ('C' << 16) + ('H' << 8) + 'P';
byte i;

for (i = 0; i < 33; i++)
{
if (mchp32 & 1)

mchp32 >>= 1;
}

for (i = 0; i < 6; i++)
}

void main() {
byte i;

trisa = 0b00000000;  // 0-5 available
trisb = 0b00100011;  // 4-7 available, bit 5 is RX, bit 7 is TX
trisc = 0b00000010;  // 0-7 available
portc = portc_shadow;  // Target reset high

ansel = 0b00000000;
anselh = 0;  // No analogs

option_reg = 0b00000111;  // Global enable for weak pullups, prescaler to T0, 256:1 (overflow at 30/sec)
osccon = 0b01110001;  // Internal oscillator, 8MHz
ccp1con = 0b00001100;  // PWM on portc.5
pr2 = 100;
ccpr1l = 50;  // 50% duty cycle at 10KHz
t2con = 0b00000000;  // TMR2 off, pre and postscale are 1:1

//  intcon.GIE = 1;
intcon.PEIE = 1;
pie1.TMR2IE = 1;

spbrg = 16;
spbrgh = 0;
rcsta.SPEN = 1;  // Set up serial port for 115.2KB
rcsta.CREN = 1;
txsta.SYNC = 0;
txsta.TXEN = 1;
txsta.BRGH = 1;
baudctl.BRG16 = 1;
incoming_push = 0x20;
incoming_pop = 0x20;
outgoing_push = 0xC0;
outgoing_pop = 0xC0;

while (1)
{
portb.f6 = 0;
if (pir1. RCIF)  // New character on serial port
{
set_high_bank;
fsr = incoming_push;
indirect = rcreg;
incoming_push++;
if (incoming_push >= 0x70)
incoming_push = 0x20;
set_low_bank;
}

if ((outgoing_push != outgoing_pop) && (txsta.TRMT != 0))
{  // Data to send, and serial port can accept it
fsr = outgoing_pop;  // Start at 0xC0, 0b11000000
txreg = indirect;  // Out it goes
outgoing_pop++;  // Cause wrap from 0xE0 to 0xC0
outgoing_pop.f5 = 0;
}

if (incoming_push != incoming_pop)  // New chars in buffer
{
i = serial_in();
if (i == GOOD_PACKET)
{
portb.f6 = 1;
if (incoming_opcode == TARGET_POWER_ON)
else if (incoming_opcode == TARGET_POWER_OFF)
else if (incoming_opcode == TARGET_RESET_LOW)
trisc.f1 = 0;
else if (incoming_opcode == TARGET_RESET_HIGH)
trisc.f1 = 1;
else if (incoming_opcode == ENTER_PROG_MODE)
enter_prog();
else if (incoming_opcode == PWM_ON)
t2con.f2 = 1;
else if (incoming_opcode == PWM_OFF)
t2con.f2 = 0;
}
}
}
}

#### MMcLaren

Joined Feb 14, 2010
851
Happy to hear you've gotten past the first hurdles, John. I should be in a position to test my code soon, too.

After getting this technique working and characterized, I'd like to tackle what we all were talking about five or six years ago. That is, developing a simple and inexpensive programmer that uses a USB-to-Serial adapter and a couple 74HC chips (no programmable parts required) that can be used to program all of the "enhanced mid-range" parts and other parts that use this same serial LVP technique.

Cheerful regards, Mike

#### John P

Joined Oct 14, 2008
1,861
I don't recall that topic, but most likely I wasn't a member here then. However, I can't see any reason why anyone would want to do this. Small processors like the PIC exist exactly so people don't have to put together assemblies of logic chips! At less than \$2.00 each, it seems hard to justify anything else. It looks pretty awkward, too--could it be that the plan was actually to use the controllable I/O pins on the FTDI interface chip, rather than the UART? Generating the clock from a UART in hardware is a tough project.

But a programmer that uses just a single cheap processor and no other hardware is an attractive idea! What I'd really like to see would be getting the USB interface on board the PIC also, which would be possible with the PIC16F1459, very similar to the PIC16F690 but with a built-in USB function. But although that chip has been available for a while now, it doesn't seem to be getting much use.

#### ErnieM

Joined Apr 24, 2011
8,089
But a programmer that uses just a single cheap processor and no other hardware is an attractive idea! What I'd really like to see would be getting the USB interface on board the PIC also, which would be possible with the PIC16F1459, very similar to the PIC16F690 but with a built-in USB function. But although that chip has been available for a while now, it doesn't seem to be getting much use.
I own several programmers that use but a single cheap processor, they all come in black or red plastic cases, they also can do in circuit debugging of code. They are called PICkit II or III.

They work very nicely too.

The time I built a programmer it was part of an acceptance test fixture for a small pic based timing board. The fixture did several tests besides time such as switch sat voltage, current draw, external start and external timing resistor. Results were displayed on a 4x20 display. The fixture was powered off a 30v supply and used a large PIC as the workhorse. There were plenty of spare pins and code space to add in a simple programming function so freshly built parts could be inserted a single time to be programmed and tested all in a single step.

The fun part was there were 4 major variants requiring their own code, though the code did need to vary depending on the nominal timer time which could vary from 0.1 seconds to 18 minutes. The programmer portion would pull the appropriate code base from ROM and change several instructions to set the timing constants. Then the delta code was inserted into the target, checked, and the code protect door was shut.

For just development work you can't beat a PICkit. Cheap, it works, and it can also debug for you.

#### NorthGuy

Joined Jun 28, 2014
611
But a programmer that uses just a single cheap processor and no other hardware is an attractive idea! What I'd really like to see would be getting the USB interface on board the PIC also, which would be possible with the PIC16F1459, very similar to the PIC16F690 but with a built-in USB function. But although that chip has been available for a while now, it doesn't seem to be getting much use.
I've just built a programmer like this, but using PIC16F1454 (which BTW is cheaper than the FTDI chip). Works well and supports programming/debugging of over 1000 different PICs. The chip even had enough capacities for adding a USB(HID)-to-UART converter in addition to programming/debugging function. We're now finishing testing.

#### John P

Joined Oct 14, 2008
1,861
I'd be very interested in the design for this, or if "We're finishing testing" means that it's a commercial product, I'd be a likely customer. Can we assume that since it's based on such an inexpensive component, the product will be priced pretty low?

#### MMcLaren

Joined Feb 14, 2010
851
Hey, North'. Sounds neat. Are there really over 1000 different PICs?