Arduino-based PIC programmer: read works, increment does not - Page 1
Forum section: electronics / general

author: MrBoarderino
author_rank: Contributor
timestamp: January 03, 2017, 04:56:45 pm
content: Hi all!I started one of these common "use Arduino to program a PIC" projects to get my self starting with PIC microcontrollers. However, I am a bit stuck and wanted to ask for some pointers. I can reliably read thefirstword of the PIC memory, and I can also erase it, but writing data and incrementing the PC is not working for some reason.As a subject to program, I have a PIC10F206. As a basis for implementing my programmer, I use the memory programming instructions fromhttp://www.microchip.com/wwwproducts/en/PIC10F206. Like I said, I reliably can read the chip, I am doing so at this point with a HUGE delay on the clock bin of 500 ms phase duration so that I can watch the serial protocol with some LEDs that I connected to the data and clock lines. This directly leads to my first question:-Can the delays for the PIC every become too large? Do I need to maintain a certain clock speed so that things work reliably?Second, I get the issue with reading out the chip is the that increment does not work. In order to issue the increment command I push the bits 0 1 1 0 0 0 onto the bus, but afterwards any read-command returns all zeroes. I actually do not even know how to verify that the chip is in output-mode at all when the next read command is issued. So:-Is there a way to check that the output pin of my PIC is actually in output mode after I sent the read command?I somehow have the feeling that I attempt to send a garbled command to the PIC which it does not understand and therefore goes into "lock down" mode or so.PS: I can post the circuit board that I have if someone wishes to see it, but since I have "read" and "erase" working reliably, I somehow doubt that this is an electrical issue - but maybe I am wrong...

author: MrBoarderino
author_rank: Contributor
timestamp: January 03, 2017, 04:59:15 pm
content: PS: Erase and read are the only commands about which I know that they work....write + start_programming + end_programming => results in garbage being written to the PICincrement address => chip seems to stay mute after I issue this command

author: MrBoarderino
author_rank: Contributor
timestamp: January 03, 2017, 05:21:55 pm
content: Sorry everybody... I actually after writing this thread did some additional testing and I was a bit stupid... ignore all the previous questions. Actually, more or less all commands seem to work. However. There was some confusion by me when trying to write to the Reset Vector which cannot take all possible values.... this lead to the "garbled data"-assumption.Anyway. There is one last question remaining:-> If I exit and re-enter programming/verification mode, all written program bits read zero again. Is that normal? Or is my "start programming"-"stop programming" command still working incorrectly?-> After an erase, everything seems to work fine, and I can read a lot of more interesting stuff from the memory...Thank you in advance!

author: Buriedcode
author_rank: Super Contributor
timestamp: January 03, 2017, 05:33:31 pm
content: Can you read the ID location of the device at 'normal' speed? I haven't used that particular device but it seems it uses the 'usual' programming method that most 10/12/16F parts use, and I have a atmega-based portable programmer on my desk, which I made about a decade ago..As for your questions:1. AFAIK, the entire process is synchronous, whilst the erase has a minimum time requirement. Therefore I would have thought you could run it at anyreasonableclock and it should work. My half-hearted DIY one runs at 16MHz and has a couple of NOP's either side of clock transitions meaning its very roughly running at 2MHz. Seems fine.2. Page 6 of this document:http://ww1.microchip.com/downloads/en/DeviceDoc/41228F.pdfThe timing diagram shows when the ICSPdat pin changes to output. Not it doesn't instantly switch to output, but only after the first clock of the following command. A simple test would be to use your LED on that pin, send a 'read data from program memory' command (0010xx), turn your programmers ICSP pin to input, then toggle the clock line once.Although a schematic might help, what would be far more useful for anyone to help would be the Arduino sketch and any libraries you used. I coded mine in AVRstudio just using C, so its all low level bit banging. I'm sure there are many Arduino libraries for this that are probably great, but the price you pay is you have to delve into the libraries source to see what exactly is going on.Also note, to enter programming mode requires sequencing the power, VPP and ICSP pins of the chip - which is why PIC programmers have many more components than simple AVR SPI ones - often requires a few transistors controlled by the programmer. Without the correct sequence it may not be entering programming mode, could lock up or be in an unknown state. The best test for hardware would be to read the ID word, as all programmers do at the start to ensure the hardware is working, and to make sure the device being configured is the intended one.

author: Buriedcode
author_rank: Super Contributor
timestamp: January 03, 2017, 05:37:09 pm
content: Quote from: MrBoarderino on January 03, 2017, 05:21:55 pmThen you aren't entering programming mode again. How are you controlling the VPP line? It should have three possible states: 0V - for reset, pull up to VDD - for 'running', and VPP (12V) for programming mode. Look at the correct sequences in the programming spec.Quote from: MrBoarderino on January 03, 2017, 05:21:55 pmSurely after a bulk erase, you wont' be able to read anything but 0xFF's? Except of course the chip ID, and possible the configuration word (whether or not that is erased depends on config flags). You need to tell us the exact sequence of commands you are sending and what you expect/want to happen.

author: MrBoarderino
author_rank: Contributor
timestamp: January 03, 2017, 05:43:05 pm
content: Thanks for the quick responses! I am currently drawing the schematic. As already mentioned it indeed is relatively complex because of the programming voltage etc... takes a few minutes...

author: MrBoarderino
author_rank: Contributor
timestamp: January 03, 2017, 06:37:57 pm
content: Okay... I finished the schematic (I left out all the clutter from my debugging LEDs):Each if the Arduino connection are I/O pins and I use bit-banging as well to write to the PIC. Vin of course is the exception, which I use as power input for the Arduino - not quite necessary given that the whole assembly is always connected to the PC, but should not be a problem either, I assume?However, I think Buriedcode might have accidentally discovered what was wrong about my things the whole time: I forgot about the configuration word!It could very well be the case that I accidentally activated code protection, every time I tried to write my binary data to the PIC. I read it when I started in the documentation file, but seemingly forgot about this detail as I continued implementing my code. I will give it a whirl now and see if this explains the weird behavior that I observed.

author: Buriedcode
author_rank: Super Contributor
timestamp: January 04, 2017, 12:29:37 am
content: Looks good hardware wise, just be careful with VPP. The later PIC's have reduced this to 13V (9V in some case) and if your power supply can vary it might not like it.

author: MrBoarderino
author_rank: Contributor
timestamp: January 06, 2017, 12:42:42 am
content: Thanks one more time for the reply. Yesterday, I did not have time to work any forther on the project but dug into the documentation again since I clearly got thrown off by the configuration word. Sorry for this. I can give a much more clear explanation of the issue at hand now, I think.Here the things I tested since my last reply:1. I handle the the configuration word specially now!I usually leave it unchanged. I also tried writing to it: all in all writing to it and reading from it seems to make sense now. Only three bits can be set using the write+program-instruction which are clearly documented in the documentation. If I rewrite the configuration word and power off the PIC afterwards, the word is saved as expected. Works!2. Reading program memoryAfter powering up by entering programming mode inputting 13V to MCLR, reading the configuration word:Code:0 0 0 1 1 1 1 1 1 1 1 1 0 1 1 0 [binary including the configuration word]and the incrementing, and reading the program memory from (0x0 to 0x1FF), I get:Code:Word 0: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0Word 1: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0Word 2: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0Word 3: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0Word 4: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0Word 5: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0Word 6: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0... all read zero ...Weird - the configuration word says that code protection is off. But it could be that the memory actually is filled with zeroes, of course3. Rewriting the COMPLETE chip after erase(I am aware that this includes writing into the reserved areas etc. Don't know if this destroys the chip?)Entering programming mode as described in 2 and incrementing behind the configuration word, then:- Issue an erase (address = 0).- Read memory - now I get something:Code:Word 0: 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 0Word 1: 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 0Word 2: 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 0Word 3: 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 0Word 4: 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 0Word 5: 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 0Word 6: 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 0Word 7: 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 0[...]Word 1fc: 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 0Word 1fd: 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 0Word 1fe: 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 0Word 1ff: 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 0Word 200: 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 0Word 201: 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 0Word 202: 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 0Word 203: 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 0Word 204: 0 0 0 1 1 0 0 0 0 1 0 1 0 1 0 0Word 205: 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 0Word 206: 0 0 0 0 0 0 0 0 0 1 0 0 1 0 1 0Word 207: 0 0 0 0 1 0 1 0 0 0 0 0 1 0 1 0Word 208: 0 0 0 0 1 0 1 1 0 1 0 0 0 1 1 0[...]Word 3fd: 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 0Word 3fe: 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 0Word 3ff: 0 0 0 1 1 1 0 1 1 1 1 1 0 0 0 0Looks good I think! To be sure, I- rewrite every location one more time by:- reading the current position- write it and program it- increment addressThere was a bug in that code now, which lead to me writing garbage into memory... this might have been a problem. I ignored this and continued... [the issue was fixed after this experiment]Anyway, when I now power down the PIC and re-enter programming mode, the memory will read all zeroes again:Code:Word 0: 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 0Word 1: 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 0[...]Word 3fe: 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 0Word 3ff: 0 0 0 1 1 1 0 1 1 1 1 1 0 0 0 04. A sort-of solution - I do not understand what happens. Can somebody explain this?I experimented even further and found the following behavior that allows me to actually read the program memory, except for the first location of the memory:1. Enter programming mode2. Increment 1 to get past the configuration-word3. Write anything to the first location. E.g.:- write 0- begin programming + end programming4. Read the memory by:- read memory word- increment 1- loop 4 until done 0x400 timeset voila: I can read the remaining addresses of the chip. I also see that data is persisted correctly. But I find this behavior very odd...Do I miss something? The first address after the configuration-word should be at address 0x0 in user program memory, or is this wrong? Does this have a special function? Any help would be appreciated!Thanks in advance (and also retrospectively) to the commenters in the thread! Also sorry, for the chaotic analysis - still getting to learn what is important with PICs and what is not...

author: Buriedcode
author_rank: Super Contributor
timestamp: January 06, 2017, 01:06:49 am
content: I think its time we saw your code. It would well be you're out of sync when sending commands/data, so we need to see the code that bit bangs the programming port. This way we can follow it and check all the delays that are required between programming words as in this document.http://ww1.microchip.com/downloads/en/DeviceDoc/41228F.pdfPage 12 has a ncie flow chart, which looks different from the programming I did a while ago (which was for the 16F628A, an old device).

author: MrBoarderino
author_rank: Contributor
timestamp: January 07, 2017, 05:52:00 pm
content: Roger that! I am currenlty preparing the code to upload to Github... in the mean-while:I read those flow charts already. They seem really nice, but my first self-defined milestone was to actually read out the OSCCAL-bits from the chip first (FIGURE 3-11: READING AND TEMPORARY SAVING OF THE OSCCAL CALIBRATION BITS). This is also the first step of the graph that you are referring to. Since I can only read zeroes from the chip, this does not work (well, it does with the work-around described above).While I am preparing the code, one additional question just to be sure that I do not beat a dead cow here: Can I "destroy" the PIC by writing to the wrong locations (there is memory tagged "reserved" area in the data sheet). If that might be the issue I will dump the current one, but I am a bit scared that if I switch to a new one now, I will just destroy the whole batch of "fresh" chips that I have at my hand.I assume that only the limited number of rewrites of the flash memory is an issue, correct?

author: Buriedcode
author_rank: Super Contributor
timestamp: January 07, 2017, 09:32:11 pm
content: I don't tihnk you can 'destroy' a PIC by programming to the reserved locations, you should be able to do a full erase on the off chance you do write to the wrong locations.And as for flash memory rewrite cycles, I've programmed a few test PIC's many many times and I have yet to wear out the flash. Now if you were to run software that writes its own flash memory every few ms, then yes you could wear it out, but I don't think its something to worry about with what you're doing.

author: jaromir
author_rank: Unknown
timestamp: January 07, 2017, 10:50:00 pm
content: Quote from: MrBoarderino on January 07, 2017, 05:52:00 pmYes, it is specified on datasheet.Code:• Low-Power, High-Speed Flash Technology:- 100,000 Flash endurance- > 40 year retentionBy the way, I made PIC programmer around arduino, currently it support over 300 MCUshttps://github.com/jaromir-sukuba/a-p-prog10F206 is not one of them, as it doesn't do LVP (I decided not to support HVP types) but perhaps you can find it useful.

author: MrBoarderino
author_rank: Contributor
timestamp: January 08, 2017, 12:19:51 am
content: Thank you jaromir, thank you Buriedcode!@jaromir: I was considering looking for other solutions and comparing the programming to mine, so that is really helpful! I will have a look later as that will take some timeOnly issue will be that I only bought HVP chips I think. PIC10F206, PICLF1709-I/P, PIC24FJ64GB002-ISP, all increasing in price, and I do not really feel like exposing the more expensive ones to my programmer yet ;-) Also they are 3.3 V based and I would like to build some voltage regulator/buck converter stuff around them first, I think. [Digressing...]I now uploaded my rough-and-ready PIC10F206 programmer code now to github:https://github.com/MrApplejuice/arduino-pic-programmer.Notes- Even though the intention was to make a generic programmer, the current version of the programmer is hard-coded for the PIC10F206-I/P and a certain pin-configuration on my Arduino- Used pins are 40-43- I use an Arduino Mega 2560 board- I invoke my commands using the Arduino-IDE serial terminal using a text-based communication protocol specified inarduino-pic-programmer/pic_programmer_prototype.ino- The typical sequence of commands to read out the memory of the PIC is:Code:prog_mode onread// Checking the returned configuration word, example output:// Word ffff: 0 0 0 1 1 1 1 1 1 1 1 1 0 1 1 0incread// Checking if the first word still read all zero. Example output:// Word 0: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0// Now the next three commands are my weird workaroundwrite FFFburnread 10// Check if I now can indeed read the memory for the next 10 positions, Example output:// Word 0: 0 0 0 0 1 1 0 1 0 0 1 0 0 0 0 0// Word 1: 0 0 0 0 0 0 0 1 1 1 1 0 0 0 0 0// Word 2: 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 0// Word 3: 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 0// Word 4: 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 0// Word 5: 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 0// Word 6: 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 0// Word 7: 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 0// Word 8: 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 0// Word 9: 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 0// Word a: 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 0// Word b: 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 0// Word c: 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 0// Word d: 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 0// Word e: 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 0// Word f: 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 0prog_mode off- The actual communication protocol for the PIC is implemented inarduino-pic-programmer/programmer.cpp.- Textual commands can be matched relatively straight-forward to the programmer-functions- The delays I use are all defined inprogrammer.cppand I roundend them all up or bunched a few together and used the maximum required delay timeI sort-of suspected that it is too much work for a random helper in the Forum to sift through the code that I wrote. However, if you want to, I would be very grateful. However, from visual inspections of the protocol (counting flashing LED cycles) I cannot spot an issue. I will certainly continue checking on my own...If I find a solution, I will post it here! (Perhaps I should just buy a working real programmer and see how that thing does it)

author: MrBoarderino
author_rank: Contributor
timestamp: January 08, 2017, 12:40:39 am
content: @jaromir:I see in your code a magic command that I do not know:Code:void isp_send_config (unsigned int data){isp_send(0x00,6);isp_send(data,16);}What is this doing? Can you tell me for which PIC this was designed so that I can look up the documentation and compare it to mine? For the PIC10F206 this command is not specified in the programming instructions (I think?).

author: Buriedcode
author_rank: Super Contributor
timestamp: January 08, 2017, 04:21:11 am
content: I couldn't find 'isp_send' in the code, but I don't have to time to look at it in detail - I'll go over it tomorrow.It *looks* ok in terms of the serial routines to write and read words. Don't forget its a 12-bit device, so the two MSB's of the 14-bit word will be 0. I see you've knocked out the two MSB's, and then left shifted it by 2 to get the start and stop bits (both 0). That looks fine, but when reading in, alignment can get tricky. Sure you could just read in a 16-bit word, right shift it by 1, then AND with 0x3FFF, but with the 12-bit core would be better to AND with 0x0FFF, just to be sure those two MSB's of the 14-bit words are 0.The programmer I did many years ago was done in raw C, but the principles are still the same. I see you've created a nice class with properties, but it can get confusing keeping track of its status, and I don't see any delays between powering on, VPP and the start of programming - although if you're starting the commands manually by using terminal, then there must be long delays anyway.I suspect it isn't so much the low level bit banging thats the problem, but the write cycle, and perhaps how you keep track of what state the chip is in. For example, you can only program the config word upon program entry, so if you want to write the bulk of the memory first you must skip over it, then leaving programming mode, re-enter programming mode, then write the config word. Some PIC's have a different command to write to the config memory but thats a different kettle of fish.

author: jaromir
author_rank: Unknown
timestamp: January 08, 2017, 09:17:22 am
content: Quote from: MrBoarderino on January 08, 2017, 12:40:39 amhttps://github.com/jaromir-sukuba/a-p-prog/blob/master/fw/pp.ino#L443it just makes "software transmit-only SPI" for specified number of bits (second parameter) and given data (first parameter), it is used over all platforms (PIC12, 16, 18). I know my code has virtually no comments, it's a bit complicated to absorb. That's why it's still 0.xx release.

author: MrBoarderino
author_rank: Contributor
timestamp: January 08, 2017, 12:11:26 pm
content: Hi Buriedcode:jaromir sent me the code for his PIC programmer. Theisp_*-stuff is from his code, not from mine :-)12-bit vs 14-bitI know about this, and in fact if you look one commit back, you will find that the code is littered withx & 0xFFFinstead ofx & 0x3FFFmasking. It is probably just a detail, but when looking at different PICs it seemed like a good idea to switch to 14 bits to make the code a bit less specific to the type of PIC I am currently using.Power-on cycleI extracted the timing diagram that I implemented from my code. It should be this:Code:INPUT_LINE_SET_TIME = 1 µSVPP_LEAD_TIME = 10 µSHOLD_ACTIVATION_TIME = 10 µSConfig wordI actually did not know about that there is a special command on some PICs for writing it. I have read the docs on PIC10F206 very closely by now but did not stray far from that, yet. This explains what the "weird"isp_send_configis. I double checked for my PIC16LF1709 and that one implements the command.Edit after cross-post detection@jaromir: I was confused by the command0x00that you are using. The remaining stuff seems relatively straight-forward to me - good work! ;-) But thanks to Bueriedcode I figured that our already, I think: the PIC16LF1709 that I have here as well also defines it - it is just for writing configurations as the name suggests. I somehow have the feeling that I am fighting some shortcoming in the design specifications for this chip by now... :-/ The "bigger" PIC chips seem more and verbose when it comes to how to program them...

author: MrBoarderino
author_rank: Contributor
timestamp: January 13, 2017, 07:43:21 pm
content: Okay, I figured it out: It was an electrical issue after all!After using my half-working programmer to upload my first LED-blink program, yesterday, the program would not start running. Code for reference:Code:#define _XTAL_FREQ 4000000#pragma config OSC = IntRC, WDTE = OFF, CP = OFF, MCLRE = ON#include <xc.h>void main(void) {OSCCALbits.FOSC4 = 0;OPTION = 0b11011111;TRISGPIO = 0b111011;while (1) {GPIO = 0b000111;__delay_ms(1000);GPIO = 0b000000;__delay_ms(1000);}return;}I probed around on my breadboard with my multimeter and touched R4 (see schematic further up), which must have caused a loose contact. In any case, after touching it the program started running - I was happy. I removed resistors R4 and R8 from my bread board which lead to repeatable program startups.Since this solved the program execution issue, I continued and tried the progamming mode again, and there it was: reading works now!Feels a bit strange without those two resistors, since if I am not in programming mode now, MCLK is just floating, but that seems to be what the chip needs. Furthermore, all discharging now is viat the PIC10F206, which works, but feel uncontrolled. I will read a bit more in order to hopefully find something about MCLK. It seems that I do not quite understand how it works exactly...Thanks to everybody who was so kind in helping me an given hints. It really helped eliminating red herings (e.g. "Perhap,s I broke the PIC")!