AVR Programming 02: The Hardware

You may be able to write the most eloquent code in the history of embedded systems but without a way to run it on the hardware it will be worthless. In this installment of the tutorial series we will:

  • Look at some of the available AVR programmer options
  • Place the microcontroller on a breadboard and connect it to a power supply and a programmer.
  • Use programming software to send some example code to the microcontroller

If you missed Part 1 take a few minutes to review that portion of the tutorial and then join us after the break.

Series roadmap:

Programmers

As I said before, if you want to get it on the chip you’ve got to have a programmer. There are a huge number of options, but I’ll cover a few of the easiest and least expensive. We are focusing on In-System Programming (ISP) which means that you can program the chip without removing it from the circuit.

DAPA Cable

A Direct AVR Parallel Access, or DAPA cable, is an incredibly simple and cheap programming method. You can build one very quickly for a few bucks worth of parts, but the convenience comes with a few gotchas. The first is that you must have a parallel port on your computer; something that modern laptop and some modern desktops don’t have. But if you’ve got an old PC around that has one this will get you up and programming in no time.

In fact, the first AVR prototyping I did was with one of these cables. That is, until I discovered another gotcha. This will only program low-speed chips. If you try to run the chip’s clock at full speed (by changing fuse settings… more in Part 3) you won’t be able to use a DAPA cable to talk to it any longer. There’s also the possibility of damaging your parallel port or worse if you do something wrong. But if you want to go for it anyway, here’s how I built mine.

It connects to a computer using a DB25 connector. As you can see in the schematic, I’ve used 1 kilo Ohm resistors on the Reset, SCK, MISO, and MOSI pins for current protection. I did not use a resistor on the ground pin. I used a piece of ribbon cable, soldering one end to each of the five signal lines shown in the schematic. On the other end of the ribbon cable I used a connector housing with six slots, filling one of them with a blank so that I could keep track of the signals. This is easy to plug into a pin header or connect to jumper wires as shown above. In retrospect it may have been a better choice to use a 2×3 IDC connector and route the signals using the AVR ISP standard (from AVR: In-System Programming PDF). If you go this route chances are you’ll upgrade before long so don’t agonize of the design details.

Arduino


I would be remiss to skip over using an Arduino as a programmer. They’re ubiquitous with the embedded systems crowd and if you don’t already own one, you can try to find someone to lend you theirs for a little while. All that is required is to write an AVR programmer sketch to the Arduino and make the programming connections. We’ll take a look at this method later in the post.

USBtinyISP


The USBtinyISP is an In-System-Programmer based around an ATtiny2313 that uses a USB connection (see where the name comes from?). It isn’t a bad choice for your first programmer. If you are confident in your skills you can build the circuit circuit yourself and use a DAPA cable to get the programming firmware onto the chip. Or you can just buy it from Adafruit Industries. But if you think you’re going to be serious about AVR development, you should consider shelling out the extra bucks for a professional programmer.

Professional programmers


The Ateml programmers are the gold standard. They offer something that none of the other hardware we’ve covered has, the ability to recover a chip that you’ve messed up. If you want to use the reset pin as I/O, you will need to use High Voltage Parallel Programming to talk to your chip. Even if you don’t decide to do that, at some point you’re going to screw up and you’ll need to recover a process, which helps offset the extra cost of a professional programmer. It is possible to use an Arduino for High Voltage Parallel Programming to recover your AVR, but that’s another hack in itself.

We use an AVR Dragon for pretty much everything. But the STK500 is a very popular board even though you need a serial port to use it. It has chip sockets, buttons, and LEDs for on-board prototyping. The Dragon leaves options open with unpopulated socket footprints, and it uses a USB connection.

If you’re in this for the long haul there’s no substitute for one of these choices.

We should at least mention the MKII, a programmer that offers ISP in the same way that the USBtinyISP does, but also provides JTAG, debug wire, and few others. We have no experience with this unit so you’ll have to do your own research if you’d like to know more. As for the other programmers out there, use Google or check the comments to this post as people usually don’t like to keep their preferred programmer choice a secret.

Bootloader

A bootloader is not really a programmer, but a way to get around using one. A bootloader is a set of code already on your microprocessor. It handles basic input and output neccessary to write your code into the chip’s memory. The bad news is that they do take up programming space, but you won’t have to buy a hardware programmer.

Programming a chip with a bootloader on it is beyond the scope of this tutorial. But it’s not hard to learn to do. In fact, this is how it is possible to program an Arduino without a separate hardware programmer.

Setting up our test circuit

Enough talk, let’s build something! We need four things: A microcontroller, something to power it, some way to program it, and something to show us it’s working.

Hardware:

  • Solderless breadboard
  • Jumper wires
  • ATmega168 microcontroller
  • 78L05 voltage regulator
  • 100uf electrolytic capacitor
  • 10uf electrolytic capacitor
  • LED
  • 180 Ohm resistor (any resistor between 180 and 330 Ohms will work fine)
  • A programmer (we’ll show both a DAPA and an Arduino)

What we’re doing

In a  nutshell, we’re going to blink an LED as our first embedded program.  This takes a few components: a power supply, the microcontroller itself, and the LED and its current limiting resistor.

The power supply consists of a voltage regulator which will take an input voltage above 7v and output a constant voltage of 5V. In order to work correctly, this circuit requires two filtering capacitors. The capacitors act like storage tanks, absorbing small fluctuations on the power rail to provide a steady source of electricity to keep our microcontroller safe and happy.

As an output we are going to use an LED. We must include a resistor to limit the amount of current that will flow when the software lights it up. Without this current limiting resistor, current would flow at levels that are unsafe for the LED, the microcontroller, or both.

The circuit schematic

Above is the circuit we are using as an example. The a simple 5v regulator circuit using an LM7805 linear regulator and two filtering capacitors is on the left, separated from the rest by a dotted box. If you already have some type of regulated 5v supply save yourself some time and use that.

You may also notice that the chip in the schematic is labelled AVR-MEGA8. The ATmega168 that we’re using is pin-compatible with at ATmega8. That means that you can swap one for the other and all 28 pins will be where they’re supposed to be, so this will cause no issue.

It is a good practice to add a few components not seen here. There should be two 0.1 uF capacitors for decoupling; they filter out fluctuations on the power rails called noise. One between VCC and GND, the other between AVCC and AGND (as close as possible to the pins). There should also be a pull-up resistor on the reset pin with lets an incredibly small amount of current trickle into the pin at a 5V level. This the chip from resetting by accident when it’s floating (not connected so there’s no clear 0 or 5V value). I’ve omitted these parts for simplicity and it shouldn’t be an issue with this simple project. But as your projects get more complicated, neglecting these considerations will come back to bite you.

The circuit built on a breadboard

I started building the circuit by adding the voltage regulator to the breadboard. Then connect the ground leg to the ground rail on top of your breadboard, and the output leg to the voltage rail of your breadboard. I have also added two wires that I will eventually connect to the positive and negative terminals of a 9V battery.

It is important to read the datasheet for your voltage regulator (example: LM7805) to figure out which lead is input, ground, and output. Your regulator may look different from mine as they do come in different packages. In the image above, the input lead is on the left, the ground is in the middle, and the output lead is to the right.

Now I’ve completed the power supply by adding the 100 uF capacitor between the input leg and ground leg of the regulator, and the 10 uF capacitor between the output leg and ground leg. Pay careful attention to these capacitors, one lead should be marked as negative (a band with a minus sign) on the case of each capacitor. Before adding the microcontroller it would be a good idea to check the voltage output using a multimeter. Too much juice can destroy your new chip.

After checking to make sure I had a steady 5V source, then disconnecting the battery, I added the ATmega168 microcontroller to the board. Note that the dimple is pointing to the left. This is important, as the standard orientation and lead numbering of a DIP package shows that pin 1 is now on the lower left, letting us easily find the other pins that we need.

Power and ground have been connected to the chip as well. Pin 7 (VCC) and Pin 20 (AVCC) have been connected to 5V. Pin 8 (GND) and Pin 22 (AGND) have both been connected to ground.

The final step is to connect the LED to output 0 on Port D. Our schematic tell us that we want to connect the positive lead of the LED to Pin 2 on the ATmega168, and the negative lead should go to an unoccupied row on the breadboard (make sure you don’t attach it to Pin 1). LEDs usually have a small notch flattened on one side of the plastic case to denote the negative leg of the device. The final piece of the puzzle is to connect the negative side of the LED to ground by using our resistor.

In the image above I’ve hooked up a 9V battery , but nothing happened. That’s because there’s no firmware on the chip to make the LED blink yet. We’ll need to fix that in the next step.

Programming our test circuit

Check all of your connections one more time and let’s get ready to program the microcontroller.

Connecting to a programmer

You only need to make six connections in order to program our chip:

  • Voltage
  • Ground
  • Master In Slave Out (MISO)
  • Master Out Slave In (MOSI)
  • Reset (RST)
  • Slave Clock (SCK)

This is true for any programmer that is using In-System Programming. There’s even a standardized 6-pin header that I design into most of my circuits so that you can easily reconnect your programmer to a circuit board and update the firmware down the line. But for this example we’ll just use some jumper wires to make the connections. One thing to keep in the back of your mind is to only use one voltage source when programming. You should either disconnect the power to your circuit while programming, or do not make a connection to the voltage line on your programmer.

Connecting an Arduino as a programmer

Using your Arduino as a programmer is super easy. The first thing you’ll want to do is open up the Arduino IDE, and then open the example software: ArduinoISP.pde (in the examples/ArduinoISP folder). Flash it to your Arduino in the normal fashion. Now follow the directions for targeting an AVR on a breadboard (bottom of that page). Important: Choose one power source. That is to say, either connect the voltage on the Arduino board to your breadboard, OR connect the battery to the power supply we wired up. Doing both has the potential to damage your hardware.

Here’s how mine looked once I had it hooked up.

Now that everything is ready to go, jump to the next section: Flashing firmware with AVRdude.

Connecting using a DAPA cable

Depending on how you constructed your DAPA cable, it should be pretty easy to make the five connections we need. Notice that the DAPA cable doesn’t have a Voltage connection. The target processor must have its own power source (like the power supply we built on the breadboard) during programming. Here is what my DAPA cable looks like once connected.

If you’re unsure of the connection that need to be made, go back and compare the DAPA cable design to the circuit schematic. Match up our five connections: MISO, MOSI, RST, SCK, and GND.

Flashing firmware with AVRdude

If you did your homework from Part 1 of this series you should already have the cross compiler tools installed. First, download the firmware package and navigate to that directory in a shell, or at the command prompt. The following commands can be used on Linux and OSX systems to program the chip.

Arduino as the programmer:

avrdude -P usb -b 19200 -c avrisp -p m168 -U flash:w:main.hex

DAPA as the programmer:

avrdude -P /dev/parport0 -c dapa -p m168 -U flash:w:main.hex

AVR Dragon as the programmer:

avrdude -P usb -c dragon_isp -p m168 -U flash:w:main.hex

USBtinyISP as the programmer:

avrdude -P usb -c usbtiny -p m168 -U flash:w:main.hex

You can get help from the AVRdude program by running:

avrdude -h

That will print out a list of available commands, or you can read the online documentation. Windows users will need to change the /dev/* portion of the command to match your connection. You should find the Windows page of the online manual particularly helpful for this. Standard Windows port names include com0, com1, etc. for serial ports and lpt0, lpt1, etc. for parallel ports.

As for the other flags used in the programming commands above:

When using the Arduino as an ISP programmer you must specify the speed, using ‘-b’. That value is set in the Arduino sketch and should be 19200 by default.

You will always need to specify what kind of chip is connected to the programmer. Here I’ve used ‘-p m168’ for our ATmega168. Get a list of all compatible microprocessors by typing

avrdude -p ?

The same is true for specifying a programmer. You can change the ‘-p’ to ‘-c’ in the command above to get a list of programmers.

The final option in the commands we used tells the programmer to write (that’s the ‘w’) the file ‘main.hex’ to flash memory. Part of the command is used for many things, including changing the fuse bits on the chip. I’ll talk about this in Part 3 of the series.

Debugging

Your LED should be flashing away quite happily at this point. What’s that? It’s not? Time to start the real learning. Here’s a list to get you started:

  • Did you successfully program the chip? You should get the message: “258 bytes of flash verified” and “avrdude done. Thank you.”
  • If you had an error during programming, check first to make sure there is power going to your chip.
  • Try the programming command again using ‘-v’ in place of ‘flash:w:main.hex’. This will just attempt to talk to the chip instead of writing to it, and is very handy when working out programming bugs
  • Recheck your programming connections to ensure you’ve got the correct signals connected to the right pins
  • Make sure you have the correct port on the computer and that you have permission to use that port. Linux users may try talking to the chip with the -v flag as ROOT to discover if there is a permission problem. If this works you need to add your user to the group that has permission to access the port the programmer is connected to
  • If you did successfully program the chip you should recheck your hardware. Is the LED installed backwards, preventing it from lighting up?
  • Take a trip to Google and start searching… this usually plays a roll in the development process so don’t feel bad. A lot of folks have already experienced the trouble you’re having and they made it through okay in the end.

Conclusion

You’ve done it, your first embedded circuit is alive! For now it will just flash to let you know everything is working. But next time we’ll talk about how this was accomplished, what we can do to make it behave differently, and how to use the compiler to translate our code changes into a file that the microcontroller can run. Thanks for reading and we’ll see you back here for the next installment.

Follow Me

@szczys

Resources

Firmware package: Package download or Github page

Atmel AVR ATmega168 Datasheet (PDF)

AVR dude online documentation

AVR In-System Programming Application Note (PDF)

AVR ISP Programming Header:

67 thoughts on “AVR Programming 02: The Hardware

  1. problem solved… took me 3 days to figure it out but it 0x00 on AVR Dragon (according to the doc) always means the clock speed is too slow.. after a bunch of digging through things I finally found the -B switch… adding: -B 32 made it work for me

  2. Should there be a wire connecting VCC to AVCC and a wire connecting GND to AGND? Also, I’m using an Arduino as my programmer. Should these two wires be hooked up when I’m programming the atmega? I noticed my Arduino turns off if those wires are connected. What is that about? I’m 99% sure everything is all hooked up correctly and the chip claimed it programed correctly and the LED is not blinking and I’m not sure what to do any more.

  3. I have to agre with Melvin above. Your ability to teach in such a down to earth way was truely a blessing for all that search for their answers. I have been searching for answers at least one month now and at age 64 I don’t want to spin my wheels too long. I was about to give up and head to DeVry U for some guidance. I am trying to build and donate a wireless scoreboard to my grandsons ballpark. I have missed my deadline 5 times already.

  4. Hello People, I have a curcuit board with a Atmel Atmega8 au processor on board. And i want to know the bios software,but the file is encrypted, how can i decrypted and which tools a need for this project. ( avr board or ??? )
    Or do you know who can do this. The flash software i have. Now only the Bios data, but decrypted.

    Thanks in advance.

    With kind regards,

    Cosimo.

  5. Hi Interesting article very nice I often read your pages
    Not that i should be the one to advise you of such however your guide that you published reference quote , “Using the AVR ISP standard (from AVR: In-System Programming PDF) ” returns error 404

    The correct link to this is as follows I always find that very often as soon as you find information that is highly useful the link due to sods law is never to be seen or found again So when I come across information which I know will always be useful I tend to download this and upload to my own site of in existence and place a far more reliable permanent link to this there or alternatively drop box it with public link so that all reading may gain access to this

    I hope you that information is at least in part useful to you

    http://www.atmel.com/images/doc0943.pdf

  6. Thanks for the tutorial, I have been trying to get this running myself with an Atmega168 and using a buspirate as programmer. I struggled to flash the file until attaching a pulldown (10k) resistor to the reset pin. This allowed me to flash the code, but the led would not blink, I’m guessing because the chip would then reset as I’m holding it down for too long. However, when attaching a pullup (10k), the code would not flash. I will try changing the pullup value to see if that works. There is no mention here, but would connecting the programmer earth to the circuit make any difference in the floating signal? (basic lack of understanding here. . .)

  7. Jamie, Can you attached a schematic of the AVR’s reset circuit and connections to the ISP header? Also, specify the signal names and connections to the AVR’s ISP header using the BUSPIRATE.

    The ATmega168 has an internal reset generator but generally speaking, a 10K to 20K ohm resistor from the RESET pin to VCC is fine. Any capacitors connected to the RESET pin should be disconnected. If I comprehend your words, are you saying that you have not connected the BUSPIRATE’s GND pin to the AVR’s GND pin? If so, there should be 6 connections between the BUSPIRATE and the AVR. MISO, MOSI, SCK, RST, VCC and GND. Also, the AVR should have at least 3.3 volts applied separately UNLESS the BUSPIRATE provides the VCC. The ATmega168’s 8MHz internal clock should be enabled in the fuses OR an external crystal should be applied and the appropriate fuse(s) set.

    Hope that helps.

    Peace and blessings.

    1. Thanks very much for the response, this isn’t a wiring diagram, but I hope that the attached image (if the attachment works) is sufficient to show the bus pirate wiring, and the vcc connections and my pull down resistor. The attached log shows that the fuses are set to the internal 8MHz clock.
      file:///home/ajcryan/Downloads/IMG_2197.JPG

      Script started on 2017年03月22日 23時16分54秒
      ]0;ajcryan@ajcryan-E202SA: ~/Downloads/had_AVRtut_2-master/src[01;32majcryan@ajcryan-E202SA[00m:[01;34m~/Downloads/had_AVRtut_2-master/src[00m$ avrdude -c buspirate -p m168 -P /dev/ttyUSB0 -U flash:w:main.hex

      Attempting to initiate BusPirate binary mode…
      avrdude: Paged flash write enabled.
      avrdude: AVR device initialized and ready to accept instructions

      Reading | | 0% 0.00s
      Reading | ################# | 33% 0.01s
      Reading | ################################# | 66% 0.01s
      Reading | ################################################## | 100% 0.01s

      avrdude: Device signature = 0x1e9406 (probably m168)
      avrdude: NOTE: “flash” memory has been specified, an erase cycle will be performed
      To disable this feature, specify the -D option.
      avrdude: erasing chip
      avrdude: reading input file “main.hex”
      avrdude: input file main.hex auto detected as Intel Hex
      avrdude: writing flash (220 bytes):

      Writing | | 0% 0.00s
      Writing | ######################### | 50% 0.20s
      Writing | ################################################## | 100% 0.40s

      avrdude: 220 bytes of flash written
      avrdude: verifying flash memory against main.hex:
      avrdude: load data flash data from input file main.hex:
      avrdude: input file main.hex auto detected as Intel Hex
      avrdude: input file main.hex contains 220 bytes
      avrdude: reading on-chip flash data:

      Reading | | 0% 0.00s
      Reading | ######################### | 50% 0.15s
      Reading | ################################################## | 100% 0.30s

      avrdude: verifying …
      avrdude: 220 bytes of flash verified

      avrdude: safemode: Fuses OK (E:F9, H:DF, L:62)

      avrdude done. Thank you.

      ]0;ajcryan@ajcryan-E202SA: ~/Downloads/had_AVRtut_2-master/src[01;32majcryan@ajcryan-E202SA[00m:[01;34m~/Downloads/had_AVRtut_2-master/src[00m$ exit
      exit

      Script done on 2017年03月22日 23時26分14秒

      In case the image is not clear, I have only RST, MOSI, MISO and SCK from the buspirate to AVR. I am powering the AVR using a breadboard power supply with 5v (roughly). I have only 2 x 100uF capacitors between VCC and ground and AVCC and Aground although I seem to get the same result with or without these capacitors.
      I have no capacitor on the Reset pin, and a 10k ohm resistor on the reset pin. Connecting the pin to VCC the device fails to initialise.

      Script started on 2017年03月22日 23時58分04秒
      ]0;ajcryan@ajcryan-E202SA: ~/Downloads/had_AVRtut_2-master/src[01;32majcryan@ajcryan-E202SA[00m:[01;34m~/Downloads/had_AVRtut_2-master/src[00m$ exitavrdude -c buspirate
      -p m168 -P /dev/ttyUSB0 -U flash:w:main.hex

      Attempting to initiate BusPirate binary mode…
      avrdude: Paged flash write enabled.
      avrdude: initialization failed, rc=-2
      Double check connections and try again, or use -F to override
      this check.

      avrdude done. Thank you.

      ]0;ajcryan@ajcryan-E202SA: ~/Downloads/had_AVRtut_2-master/src[01;32majcryan@ajcryan-E202SA[00m:[01;34m~/Downloads/had_AVRtut_2-master/src[00m$ exit
      exit

      Script done on 2017年03月22日 23時58分12秒

      The verbose output is;
      ajcryan@ajcryan-E202SA:~/Downloads/had_AVRtut_2-master/src$ avrdude -c buspirate -p m168 -P /dev/ttyUSB0 -v

      avrdude: Version 6.2
      Copyright (c) 2000-2005 Brian Dean, http://www.bdmicro.com/
      Copyright (c) 2007-2014 Joerg Wunsch

      System wide configuration file is “/etc/avrdude.conf”
      User configuration file is “/home/ajcryan/.avrduderc”
      User configuration file does not exist or is not a regular file, skipping

      Using Port : /dev/ttyUSB0
      Using Programmer : buspirate
      AVR Part : ATmega168
      Chip Erase delay : 9000 us
      PAGEL : PD7
      BS2 : PC2
      RESET disposition : dedicated
      RETRY pulse : SCK
      serial program mode : yes
      parallel program mode : yes
      Timeout : 200
      StabDelay : 100
      CmdexeDelay : 25
      SyncLoops : 32
      ByteDelay : 0
      PollIndex : 3
      PollValue : 0x53
      Memory Detail :

      Block Poll Page Polled
      Memory Type Mode Delay Size Indx Paged Size Size #Pages MinW MaxW ReadBack
      ———– —- —– —– —- —— —— —- —— —– —– ———
      eeprom 65 20 4 0 no 512 4 0 3600 3600 0xff 0xff
      flash 65 6 128 0 yes 16384 128 128 4500 4500 0xff 0xff
      lfuse 0 0 0 0 no 1 0 0 4500 4500 0x00 0x00
      hfuse 0 0 0 0 no 1 0 0 4500 4500 0x00 0x00
      efuse 0 0 0 0 no 1 0 0 4500 4500 0x00 0x00
      lock 0 0 0 0 no 1 0 0 4500 4500 0x00 0x00
      calibration 0 0 0 0 no 1 0 0 0 0 0x00 0x00
      signature 0 0 0 0 no 3 0 0 0 0 0x00 0x00

      Programmer Type : BusPirate
      Description : The Bus Pirate

      Attempting to initiate BusPirate binary mode…
      BusPirate binmode version: 1
      BusPirate SPI version: 1
      avrdude: Paged flash write enabled.
      AVR Extended Commands version 1
      avrdude: initialization failed, rc=-2
      Double check connections and try again, or use -F to override
      this check.

      BusPirate is back in the text mode

      avrdude done. Thank you.

      The colour coded cable from the buspirate to the ICP header I think are correct using Red for Rest (CS), yellow for Clock, Orange for MOSI and brown for MISO. I have checked my wiring for shorts, and the fuses seem fine, so I’m lost and very grateful for your help!!

        1. Jamie:
          I normally use an AVR DRAGON or in some cases, the USBtinyISP or USBASP devices. I do not use a BUSPIRATE for programming AVR’s, thus I cannot speak to how the BUSPIRATE is driving the RST, MOSI and SCK lines.

          AVRDUDE looks to have FLASHED your AVR without a problem. However, it seems by your description that you have not connected GND from the BUSPIRATE to your AVR and I do not see one in your photo. I spoke of this in my first answer to you. Did you follow my initial directions? I am not certain how the FLASH programming worked correctly with the BUSPIRATE’s GND unconnected unless there is a “virtual ground” created somewhere that isn’t obvious. Also, move the 10K resistor from RST to VCC after you connect the BUSPIRATE’s GND to the AVR.

          Thought invoking question: How do you expect there to be a return electrical path to the BUSPIRATE for RST, MISO, MOSI and SCK if the GND is not connected?

          Hint: it’s okay to connect the AVR and BUSPIRATE signal grounds together but leaving the BUSPIRATE’s VCC unconnected is fine because you are using another power source. Some programmers, like the AVR DRAGON, require the connection to VCC because they look for the target AVR having power applied. Thus, the AVR DRAGON does not supply power to the target AVR, only monitors it. For programmers like the USBtinyISP and USBASP, there is a jumper pin that allows the programmer to supply power to the target AVR. The BUSPIRATE may do this as well.

          Hope that helps.

          Peace and blessings.

          1. That absolutely helped! I must have not connected the earth from the buspirate properly the last time when I thought I had (I had removed the connection in the circuit image). Connecting the earth to the circuit and changing the resistor to pull up allowed me to flash the program, and my led is now blinking happily! Thank you so much! I’m not sure why the flash appeared to work previously, but that may be something I can return to ponder later once I have more experience. For now, I’m very happy to continue with my learning.

Leave a Reply to LennyCancel reply

Please be kind and respectful to help make the comments section excellent. (Comment Policy)

This site uses Akismet to reduce spam. Learn how your comment data is processed.