I’m sure many of your are familiar with a device much like this. This is a microcontroller programmer. More specifically, an AVR ISP MKII. And as a programmer is meant to do, it takes our code written on a computer, and then writes it into our microcontrollers. And usually, this process works with a hitch, until you make a specific mistake that locks you out of the microcontroller. And then, this thing becomes a glorified paper-weight, unless you know about a different method of programming. And that is parallel programming. Parallel programming for AVR microcontrollers is the ultimate programming method, and it can overcome any software issue. So join me today, as I teach you about parallel programming, and how you can use it to unlock one of your microcontrollers, just like this one.
First, let me explain what typically causes these lock-outs. Typically, you will program your microcontroller using the ISP protocol, using a programmer similar to the one I showed in the intro. That is, until you incorrectly program a fuse bit or a lock bit. For example, you could set the Reset Disable fuse bit and essentially disable ISP programming. In my case, I have an ATmega8A that I was using for a previous video. I ended up changing the clock fuses, and wasn’t able to get the device to work afterwards. Either way, parallel programming is able to overcome really any software lockouts because it uses a 12 volt pulse to signify the start of programming. This 12 volt pulse should never be found anywhere in normal, everyday use, so it works perfectly for starting the programming process.
I’ll show you how to do this both by hand and also with your own dedicated circuit, so that you won’t have to worry about losing a microcontroller over an annoying fuse error. The best place to start is the datasheet. Since my example involves the ATmega8A, I’ll be using that datasheet for now. But if you are using, say, an ATmega328p, you can still follow along for the most part. The process is nearly identical expect for a few small differences such as the device signature and the extended fuse. You’ll find that most of the 28-pin AVR microcontrollers have a similar process. The first couple of pages show you what each fuse and lock bit represents. And pay special attention, since in this case a 0 means that the bit is programmed, not a 1. There are a couple of dangerous fuses that will stop you from using ISP programming.
Here is a helpful diagram that shows you the pins we will need. And, as you can see, there are a lot of pins involved. 18 in total, not including GND, VCC, and AVCC. This is why I will say that, in most cases, parallel programming is not practical. You’ll usually only want to use this method when you need to reset those fuse and lock bits, otherwise, just stick to the ISP protocol which uses those 6 pin headers instead. Anyways, on the next page we can see the function of all of the pins. Since we are starting out by programming by hand, let’s connect all of the ones that say ‘I’, which stands for input, to ground. Except for OE and WR, since the line above them means that they are active low, so we will connect those to VCC. I’d also recommend setting up a button that can pull the WR pin low to make programming easier later. Setup a pulldown resistor in conjunction with a button connected to VCC to make up our clock pulses on XTAL1. On the RDY pin, put an LED so that we can see the status of the programming. And finally, put LEDs on each of the DATA pins, so that we can read the output later. Now, we just have one more pin to tackle, which is the 12 volt pulse on the RESET pin.
Now, we have to be careful about the 12 volts, since it can only be on the RESET, the rest of the circuit can only handle 5 volts. For our power supply, we will start out with 12 volts and then use an LM317 to regulate down to 5 volts for everything else. This is good, but we need our 5 volt signals to be able to swtich the 12 volt signal when we automate the process later on. The best component for this job is a transistor. So, I came up with this design, but let’s test it in real-life before we put it into the working circuit. First, I setup our button so that it connects down to ground. We also need a pullup resistor to 12 volts so that the output stays at ground when not in use. Otherwise, the circuit is just a simple transistor switch that involves another resistor for the 12 volt pullup on the output. Now, when I flip the switch, we get 12 volts, and when I flip it again, we get 0 volts. In the actual circuit, I’ll be using this switch, because we will need to continually apply the 12 volt signal. Before anybody leaves a comment, yes if you are doing this entirely by hand, skip the transistor and just use a button, but this is all setup for when we automate the process.
Next, its best to plan out the steps we will take to reset and unlock our locked microcontroller. First, I’d say its best to verify the device signature. This is because first, we can make sure that everything is plugged in correctly, and second, we make sure that we are actually targeting the correct device. Second, we will run a chip erase, this will reset all of the lock bits, flash, and eeprom, but not the fuses. Next, we will program the high and low fuse bytes, most likely to the factory default, but it is up to you. Finally, we will verify the lock and fuse bits. After that, your microcontroller should be as good as new. So let’s get started with this.
First, we need to enter programming mode. Luckily, the datasheet gives us some very explicit instructions for this. There are two algorithms that it gives us. The first is for the majority of circumstances, and the second is for when certain fuses block programming mode. Those fuses are the CKSEL and RSTDISBL bits. Since, my microcontroller had those problems, I had to use the second method, so I’ll show that first. The algorithm goes as follows: set the prog_enable pins to 0. The prog_enable pins are PAGEL, XA1, XA0, and BS1. If you’ve followed along so far, they should already be 0. The next step is to simultaneosuly apply 5 volt power and the 12 volts to RESET. This is tricky when you are doing it by hand, but the best way to do this by hand, I’ve found, is to preconfigure your switch to apply 12 volts, and then apply power to the entire circuit. If your RDY LED is on, then you are in programming mode, congratulations! For everybody else who is using method one, here are the steps: power up the device, no not apply 12 volts yet. Next, toggle your clock six times. Make sure that those prog_enable pins are 0. You may now apply the 12 volts and watch your LED come on! Now we are officially able to start programming our fuses and lock bits.
Before we do that, let’s make sure everything is correctly configured by checking our device signature. We will check for these three bytes, which specify that the microcontroller is a 8KB ATmega8A manufactured by Microchip. The datasheet provides us some instructions for this. First, we need to set XA1 to one and keep XA0 at 0. This will put us into load command mode. Next, we should set BS1 to 0, but it should already be that way. Next, we need to drive our data pins. It tells us to load command 0000 1000, which represents reading the signature and calibration bytes. Press our xtal clock button to load our command into the microcontroller. Remember these steps, since they form the basis for all command loading. Now, we need to load the address of the signature bytes. Their addresses are 0, 1 and 2. To do that, we follow a similiar process to loading a command. The main difference is that we set both XA1 and XA0 to 0 to get into load address mode. For starters we will load address 0 into the data bus. Keep BS1 at 0. Finally, pulse the clock to save your settings. Now we are ready to read our data. Make sure to disconnect any driving pins on the data bus, I don’t want you to accidentally short circuit anything. Now, drive OE to 0, and that will enable the output. On the output we can now see the first signature byte. You should be getting 1E, which is 0001 1110 in binary. Repeat the load address process two more times but this time with address 1 and 2 to get the other bytes. They should be 93 and 07 respectively, if you’ve got an ATmega8A. Check your datasheet for other microcontrollers. If everything checks out, its time to start programming.
Let’s start with our lock bits, since they will block the programming of our fuses. The only way to unprogram a lock bit, is with a chip erase. Remember, chip erases erase lock bits, eeprom, and flash, but not fuses. Again, the datasheet also provides us with a step-by-step guide on how to perform a chip-erase. Just like with the signature bytes, set your XA1 and XA0 pins into load command mode. Keep BS1 at 0. Set your data to the chip erase command, they should all be 0 except for the most significant bit. This represents our chip-erase command. Press our clock button to load our command into the microcontroller. All that is left to do now is to give WR a negative pulse to execute our write command. Depending on how quick you are, you might see the RDY light flash off. It was only off breifly because the microcontroller processes things very quickly, but that LED tells us whether the microcontroller is busy and if it is ready to accept further instructions.
Now let’s change our fuse bits. You’ve probably already caught onto the pattern by now. First, load the write fuse bits command into the microcontroller. Remember to set the XA1 and XA0 pins correctly, and keep BS1 at 0. Here is a new step, now set XA1 and XA0 to 01. This is the load data mode. At this point, load your low fuse bits into the data. I’ll be loading hex C1. That’s important, we are doing the low fuse first. Then pulse your clock to load the fuse bits. Finally pulse the WR pin to save your changes. The high fuse is almost the same. The only difference is that right before your pulse the WR pin, change BS1 to a 1. This just selects the high fuse byte instead. For my data, I’ll be putting in hex 99. After pulsing WR, reset BS1 back to a 0, and you should be done, and you could stop programming here, but we should double check the fuses and lock bits to avoid later frustration.
To read these bytes, load the ‘read fuse and lock bits’ command, which is 0000 0100. From this point on, you will be able to read the data by setting OE to 0 and by switching through the combitnations of BS1 and BS2. Again, make sure you remove any driving wires to avoid short circuits. Set BS2 and BS1 to 0, you will be able to read the fuse low bits. Next set them both to one, you will get the fuse high byte. Finally, set BS2 to 0 and BS1 to 1 and you will get the lock bits, which should all be 1. After you’ve verified the status of the bits, you are now done with programming. Reset OE to 1 and then turn off the 12 volt signal on the RESET pin. You may now power down the device and your changes are now saved. Congrats! We have just recovered this microcontroller and we can now program it using the traditional ISP method. And this method is surprisingly practical if you have just one bricked microcontroller. But I know that some of you will get annoyed by using this bit-banging method over time, especially if you have a lot of chips to recover. So the remainder of this video will be about creating an automated device to do this all for us.
Ideally, this automated device should be able to quickly reset several AVR microcontrollers. That’s why I got this handy 28-pin ZIF socket to will allow us to simply drop in a microcontroller and quickly reset it. Quite conveniently, many of these classic AVR microcontrollers have their reset pins on Pin 1, at least in the DIP package, so we can simply setup the highvoltage to always be at that location. As the brains, I used another ATmega8A. I also added two LEDs that will indicate either a failure or success in reprogramming. The power to the other microcontroller will be supplied through a PNP transistor, which will be toggled by a signal on the programmer.
As for the code, I basically wrote in the microcontroller what we did by hand. You will be able to review the entire thing by looking in the description, but here are a few of the more important functions. The start_programming() method applies those two methods from earlier and we are able to see if it was successful based on the RDY output being HIGH. The load_cmd() function will take our command and go through the process of setting up the microcontroller’s pins to get it to load the specified command. The same goes with the load_addr() function. There are multiple helper functions like these. I then wrote larger functions like chip_erase() and fuse_write() that contained those helper functions. Again, its the same thing that we just did, but the microcontroller is the one doing it now.
Anyways, since this all works on the breadboard, it’s time to solder it all together. And after a few hours of soldering, the project is now a part of my programming toolkit. Let me show you it in action. First, I will lock myself out of this ATmega8A for demonstration purposes. I set all of the lock bits and set the RSTDISBLE fuse. As you can see, we can’t use this with ISP programming anymore. To recover the microcontroller, we just place it into the ZIF socket. Then we press the button and it takes care of itself. The LEDs let us know what is happening. It will turn green when it is successful. But when something is wrong, it turns red. For example, it will turn red if there is no microcontroller plugged in. And that just about does it this device.
I hope that this video has helped you save one of your microcontrollers from an unfortunate lockout. If it did I’d like to ask you to take a look at my buymeacoffee page. These videos take a considerable amount of research, testing, and production to make, and with your support I can continue making more videos. Big thanks to those of you who are already supporting me. Anyways, thanks for watching! Have a good one!