AVR Debuggen met Atmel-ICE en MPLAB X IDE onder Linux

Hoe een Atmel/Microchip AVR of SAM Microcontroller debuggen onder Linux met een Atmel-ICE Debugger en MPLAB X IDE

Als je aan een microprocessor project werkt en je wil deze debuggen dan heb je hiervoor een hardware-debugger nodig (zoals de Atmel-ICE of een andere compatibele debugger) en de nodig software.

Microchip (vroeger Atmel) heeft een uitgebreide IDE1 gebaseerd op Microsoft® Visual Studio® (Atmel Studio 7 op dit moment), maar deze is enkel beschikbaar voor Windows®, dus als Linux (of macOS) gebruiker blijf je in de kou staan.

Gelukkig hebben ze ook hun zogenaamde MPLAB X IDE, een op NetBeans gebaseerde IDE die werkt op zowel Linux, macOS als Windows. Deze gaan we dan ook gebruiken om onze microcontroller te "debuggen".

Laten we eerst een kijken wat we allemaal nodig hebben:

Hardware:
  1. Atmel-ICE programmer/debugger of andere compatibele debugger.
  2. 8, 16 of 32bit microcontroller compatibel met de Atmel-ICE (ik gebruik een ATMega168P)
  3. 5volt voeding, breadboard, steekkabeltjes, LED, … om een schakeling te maken die je wil debuggen.
Software:
  1. MPLAB XC Compiler voor jouw microcontroller (XC8, XC16 of XC32), deze is gratis tenzij je gebruik wil maken van de geavanceerde opties. Maar het prijskaartje van een licensie ligt ver boven de prijs die een hobby gebruiker kan betalen. De goedkoopste optie is een maandelijks abonnement dat je eventueel kunt nemen als je de pro functies maar voor 1 project/maand nodig hebt.
  2. MPLAB X IDE om te programmeren/debuggen.
  3. optioneel de AVR/ARM Toolchain voor de microcontroller die je gebruikt, Dit is optioneel en kan gebruikt worden als een alternatief voor de XC Compiler. Deze zijn gebaseerd op de GNU Compiler Collection met enkele "optimalisaties" van Atmel/microchip.

Laten we beginnen met het installeren van de software:

Installatie

Het eerste dat we moeten doen is het installeren van de nodig software, na het downloaden van de IDE en Compiler kunnen we deze installeren.

Compiler

Voordat je de compiler kunt installeren op een 64-bit Linux distribtie moet je eerst de "32-bit compatibility packages" installeren, de compiler is op dit moment nog 32-bit.

Afhankelijk van jouw distributie zijn de stappen die je moet doorlopen anders, zo moet ik bijvoorbeeld op mijn Debian systeeem het volgende doen
  • sudo dpkg --add-architecture i386
  • sudo apt update
  • sudo apt install xx:i386 (de xx vervang je door het nodig pakket).

Als er een pakket ontbreekt zal het installatie programma daar een foutmelding over geven en aan de hand hiervan kun je kijken wat je precies moet installeren. Let er op dat je achter het pakket :i386 zet, ander zal Debian het 64-bit pakket installeren of melden dat het al geïnstalleerd is.

Open een terminal venser en navigeer naar de directory waar je de installer gedownload hebt (meestal is dat ~/Downloads). De Compiler komt als een .run programma, dus je moet deze enkel uitvoerbaar maken met chmod +x xc8-v2.20-full-install-linux-installer.run (als je een nieuwere versie download, moet je natuurlijk de bestandsnaam aanpassen).

Vervolgens installeren we deze met root previleges: sudo ./xc8-v2.20-full-install-linux-installer.run.

Figuur 1. sudo ./xc8-v2.20-full-install-linux-installer.run
sudo ./xc8-v2.20-full-install-linux-installer.run

Geef het wachtwoord van de root gebruiker in en volg het installatieprogramma.

Bij de vraag naar het licensietype geef je free (de standaard optie) aan, tenzij je een licensie gekocht hebt natuurlijk.
Figuur 2. Licensie opties
Licensie opties
Bij de Compiler Options heef ik in dat ik wil dat iedere gebruiker van de computer deze compiler kan gebruiken, én dat deze moet toegevoegd worden aan het $PATH, zo kan de compiler vanuit iedere directory aangeroepen worden en moeten we niet steeds het volledige path meegeven als we de compiler of een van zijn tools willen gebruiken vanaf de commandoregel.
Figuur 3. Compiler Settings
Compiler Settings
Ga verder en wacht tot de compiler geïnstalleerd is.
Figuur 4. Compiler installeren
Compiler installeren

Op het einde van de installatie krijg je nog een venster met instructies om een eventuele licensie te activeren. Zoals de tekst aangeeft kunnen we omdat we de free versie gebruiken gewoon op next klikken.

Figuur 4. Compiler Activatie
Compiler Activatie
Gefeliciteerd! je hebt stap 1 met success doorlopen
Figuur 6. Installatie klaar
Installatie klaar

De volgende stap is het installeren van MPLAB X IDE:

MPLAB X IDE

MPLAB X IDE komt in een tarball en deze moeten we eerst uitpakken, maak een tijdelijke directory aan en plaats de MPLAB X IDE tarball in deze directory. Geef nu het commando tar xf MPLABX-v5.40-linux-installer.tar in en wacht tot het pakket is uitgepakt.

Voer ook dit programma uit met root previleges: sudo ./MPLABX-v5.40-linux-installer.sh en volg de installatie instructies.
Figuur 7. MPLAB X IDE Installatie
MPLAB X IDE Installatie

Je kunt gewoon de standaard opties gebruiken, bij proxy stel ik wel in dat ik geen proxy heb, de rest zijn de standaard opties.

Als de installatie met success in afgerond kun je MPLAB X IDE opstarten, helaas staat deze nog niet in het menu, dus moeten we deze de eerste keer manueel vanuit de commandoregel opstarten.

het commando hiervoor is mplab_ide

Figuur 8. MPLAB X IDE
MPLAB X IDE

MPLAB X IDE is nu geïnstalleerd, Microchip stelt voor om enkele plugins te installeren (deze worden ook vermeld in het installtieprogramma op het einde van de installatie), het installatie programma opent op mijn computer geen browser naar deze 3, maar 1 ervan is de XC compiler die we al geïnstalleerd hebben, en de andere 2 kunnen we gemakkelijk installeren via: Tools > Plugins > Available Plugins Als deze geïnstalleerd zijn zal MPLAB X IDE vragen om het programma opnieuw op te starten om de plugins beschikbaar te maken.

Programma Maken

Om te testen gaan we een kort programma maken dat een LED zal doen knipperen, dit kunnen we dan wegschrijven naar de microcontroller en vervolgens debuggen:

Het programma:

Begin een nieuw project:

File > New Project
Figuur 9. File -> New Project
File -> New Project

Omdat ik een ATMega 168P gebruik, kies ik voor Microchop Embedded en Standalone Project

Figuur 10. Select Device
Select Device

Geef bij Select Device eerst aan welke familie van microcontroller je gebruikt, daarna het typenummer van deze controller (ATMega168P in mijn geval) en de programmer/debugger (Atmel-ICE), deze moet aangesloten zijn anders krijg je enkel de 2 opties (no tool, en simulator).

Figuur 11. Select Compiler
Select Compiler

Kies een compiler als je de XC8, XC16, en/of XC32 correct geïnstalleerd hebt staan deze in dit menu en kun je de geschikte compiler kiezen. Ook zie je de mogelijkheid om de AVR compiler te kiezen, de AVR v1.00 compiler stonden al op mijn systeem, en de AVR v5.4.0 is de Atmel/Microchip AVR8 Compiler Toolchain, die ik voor het gemak in mijn $HOME directory heb geplaatst (zoals eerder vermeld is deze optioneel).

Figuur 11. Kies naam en directory
Kies naam en directory

Tenslotte moeten we het project nog een naam geven en een directory kiezen voor ons project.

MPLAB X IDE zal nu het project generen en openen
Figuur 13. MPLAB X IDE nieuw Project
MPLAB X IDE nieuw Project

We voegen een sourcecode bestand toe door rechts te klikken op Source Files > new > avr-main.c

Figuur 14. nieuw bestand
nieuw bestand

MPLAB X IDE zal nu een broncode bestand aanmaken met daarin wat boilerplate code

Figuur 14. blinkLED.c boilerplate
blinkLED.c boilerplate
Nu schrijven we een simpel programma
/*
 * File:   blinkLED.c
 * Author: Patrick Kox
 *
 * Created on 14 July 2020, 12:39
 */


#include <avr/io.h>
#include <util/delay.h>

int
main (void)
{
  DDRB = 0xff;      // Data Direction Register B, alle pinnen instellen voor OUTPUT
  PORTB = 0xff;     // Alle pinnen op DDRB naar HIGH (5 Volt) dit zorgt ervoor dat de LEDs om mijn prototyping board uit gaan
  while (1)         // Eeuwigdurende loop (dit programma stop nooit)
    {
      _delay_ms(1000);  // wacht 100 miliseconden
      PORTB |= (1 << PB1);  // Schrijd een 1 (HIGH/5V) naar PB1 (de 2de pin van DDRB);
      _delay_ms(1000);  // wacht 100 miliseconden
      PORTB &= ~(1 << PB1); // Schrijf een 0 (LOW/0V) naar PB1
    }
  return (0);   // dit is niet nodig omdat de code hier nooit komt, maar bepaalde compiler klagen als dit er niet bij staat.
}
Figuur 15. C programma
C programma

Programma Schrijven

Nu kunnen we het programma wegschrijven naar de AVR en een Debug sessie beginnen.

Hiervoor hebben we de Atmel-ICE nodig
Figuur 17. Atmel-ICE
Atmel-ICE
De Atmel-ICE is verkrijgbaar in 3 varianten
  1. Atmel-ICE PCBA (dit is enkel de printplaat zonder behuizing of kabels)
  2. Atmel-ICE Basic (dit is de printplaat in een behuizing, usb kabel en de flatcable in de afbeelding hierboven met de 6-pin header (dit is voldoende voor een ATMega168P.
  3. Atmel-ICE (de volledige kit zoals hierboven is afgebeeld).

De prijs zit tussen de €80 en €180 voor de goedkoopste en de duurste.

Sluit de Atmel-ICE aan, in het geval van de ATMega168P in mijn voorbeeld is dat simpelweg de 6-pin header aansluiten op de ISP aansluiting van de microcontroller.

Schrijf of laad het project in en klik op de knop Make and Program Device Main Project

Figuur 18. Make and Program Device Main Project
Make and Program Device Main Project
Figuur 19. debugWIRE staat niet ingeschakeld
debugWIRE staat niet ingeschakeld

Bij een microcontroller die enkel debugWire ondersteund (zoals de ATTiny en ATMega168P/328P) krijg je bovenstaande foutmelding, dat komt omdat debugWIRE standaard is uitgeschakeld (and deze is ingeschakeld kun je namelijk geen ISP programmer gebruiken om de microcontroller te programmeren).

Als je JA kiest dan zal de Atmel-ICE omschakelen naar ISP modus en de correcte instellingen uitvoeren.
Figuur 20. debugWIRE inschakelen
debugWIRE inschakelen

schakel de AVR kortstondig uit en klik binnen de 10seconden na het inschakelen op de knop OK

De versie van MPLAB X IDE die ik gebruikt (versie 5.40) heeft een bug waarbij de snelheid (MHz) van de ISP programmer verkeerd staat ingesteld (0.000) en het programma geeft ook aan dat deze tussen de 0.000MHz en 0.000MHz moet zitten. De beste snelheid die je hier moet ingeven weet ik niet maar 0.01MHz blijkt te werken:
Opmerking: Ik heb contact gehad met Microchip Support en zij geven aan dat er er bug zit in de huidige versie (5.40). Zij bieden 2 "workarounds" om dit voorlopig op te lossen
  1. Begin het project in MPLAB X IDE versie 5.35 en open het daarna in versie 5.40
  2. Bewerk het bestand configurations.xml en stel daar de correcte snelheid in.
    <property key="communication.speed" value="0.125"/>

Beide workarounds moeten voor ieder project harhaalt worden. De oplossing die ik hieronder aangeef werkt ook nog. Enkel de aangegeven snelheid is niet correct. Dit is wat Microship Support hierover zegt

A valid communication (such as 0.125 MHz or 1/4 of the device clock speed) must be entered when selecting the ISP communication protocol.

Figuur 21. ISP Snelheid
ISP Snelheid
Als je een nieuw project opstart, moet je ook deze instelling opnieuw doen!
  1. Open project properties
  2. klik op Atmel-ICE
  3. Kies "communication" in het drop-down menu
  4. Zet interface op ISP (in debugWIRE modus kun je de snelheid niet aanpassen).
  5. Stel de snelheid in op 0.01 (negeer de foutmelding)
  6. Zet de interface opnieuw op debugWIRE
  7. klik Apply/OK

debugWIRE

DebugWIRE uitschakelen2:

MPLAB X IDE zal dit automatisch doen bij het beëindigen van een debug-sessie, is er om de een-of-andere reden iets foutgelopen en kun je de microcontroller niet meer benaderen met de Atmel-ICE of enig andere ISP programmer.

Hiervoor gebruiken we AVRDUDE en een HVPP programmer, de correcte fuse instelling kunnen we opzoeken op https://www.engbedded.com/fusecalc/
Figuur 22. https://www.engbedded.com/fusecalc/
https://www.engbedded.com/fusecalc/
Kies de correcte microcontroller, dit is héél belangrijk want iedere MCU heeft zijn eigen fuse settings. de website zal automatisch de standaard (fabrieksinstellingen) nemen dus je moet niks aanpassen op deze pagina. Deze site is natuurlijk niet enkel om standaard instellingen te herstellen, je kunt hier bijvoorbeeld ook de fuses opzoeken die je moet gebruiken om een externe oscillator te gebruiken. In dit geval veranderen we dus niks en gaan naar naar de onderkant van de pagina:
Figuur 23. AVRDUDE Arguments
AVRDUDE Arguments
Opmerking: Let op! de fuse instellingen op de afbeelding hierboven zijn niet correct, als je deze vergelijk met de instellingen die ik hieronder aangeef zie je dat de waarde van de High fuse 9F is en de correcte waarde moet DF zijn. Als je de bovenstaande fuse waarden programmeert, kun je hierna geen ISP programmer meer gebruiken en zul ja na een eerste geslaagde debug-sessie de microcontroller niet meer kunnen gebruiken (of zoals eerder vermeld tenzij je deze herstelt met een HVPP).

Klik voor de zekerheid op Apply manual fuse bit settings.

Zoals je ziet zijn de mensen van deze website zo vriendelijk om ons de correcte AVRDUDE parameters te geven zodat we deze enkel moeten kopieren en plakken. doe dit ook! een typefout is snel gemaakt.

Om deze fuse settings te programmeren openen we dus een commandoregel en geven het volgende commando in:

avrdude -c HVPP-programmer -p m168P -U lfuse:w:0x62:m -U hfuse:w:0xdf:m -U efuse:w:0xf9:m
Opmerking: Afhankelijk van de winkel waar je de microcontroller koopt kan het zijn dat de ATMega168P niet beschikbaar is, de meeste kleinere winkels verkopen enkel de ATMega328 en eventueel nog een ATTiny85. De ATMega328 heeft dubbel zoveel flash geheugen dan de ATMega168P en is dus een alternatief. Let bij aankoop van een ATMega328 wel op of je er één koopt met UNO bootloader of zonder.

De ATMega328 is de standaard microcontroller op de Arduino Uno, en veel winkels verkopen een ATMega328 welke al is voorgeprogrammeerd met de Arduino Uno bootloader waardoor je deze kunt gebruiken om een kapotte microcontroller te vervangen of om een Arduino project over te zetten op een breadboard of printplaat.

Een nadeel van de ATMega328 met Uno bootloader is dat deze is ingesteld om gebruik te maken van een externe 16MHz oscillator terwijl een standaard ATMega328 is ingesteld om gebruik te maken van de interne 8MHz oscillator met een pre-scaler van /8.

Voor een ATMega328 met Uno bootloader moet je een externe oscilator met condensatoren voorzien anders werkt de microcontroller niet, en kun je hem ook niet programmeren. Het is mogelijk dat de winkel een kit verkoopt met Microcontroller, Oscillator en 2 condendatoren. Doen ze dat niet dan moet je deze erbij kopen. Wel kun je dit uitzetten door de correcte fuse instellingen te doen en vanaf dat moment heb je geen externe oscillator meer nodig.

Voor de standaard ATMega328 heb je dus geen externe oscillator nodig, maar houd er rekening mee dat deze niet op 8MHz draait, maar slechts op 1MHz! (de pre-scaler van /8). Dit klinkt mischien raar want ze laten een CPU die 8MHz aankan draaiën op slechts 1/8, maar dit is gedaan om stroom te besparen en omdat veel projecten voldoende hebben met een kloksnelheid van 1MHz.

Als je naar de schermafbeelding van de website voor de fuse calculator kijkt kun je dit ook zien.
  • Int RC Osc. 8MHz. Startup time PWRDWN/RESET:6
  • Divide clock by 8 internally [CKDIV8=0]

In het drop-down menu kun je aangeven of je een interne of externe oscillator wil gebruiken (en nog enkele andere opties) en het vinkje voor Divide clock by 8 geeft aan dat we de interne oscillator delen door 8.

Opmerking: Als je een programma schrijft waarbij timing belangrijk is, moet je rekening houden met de kloksnelheid van de microcontroller. Doe je dit niet dan kan het programma te snel of te traag draaien. Een LED die in de software geprogrammeerd is om te knipperen aan een snelheid van 1 seconde aan en 1 seconde uit kan dan bijv. in werkelijkheid knipperen aan een snelheid van 8 seconden aan en 8 seconden uit.

Debuggen

Het Debuggen zelf:

Open het project dat je wil programmeren/debuggen in MPLAB X IDE.

Figuur 24. Make and Program Device Main Project
Make and Program Device Main Project
Als alles goed is krijg je na enige tijd (het programma zal eerst gecompileerd en geupload worden) een melding in het output venster dat het programmeren gelukt is:
Figuur 25. Programmeren gelukt
Programmeren gelukt

Bij mijn opstelling werkt het nieuwe programma pas na het uit en terug inschakelen van de spanning. Dit mag je straks als we in debug-modus zijn dus absoluut niet meer doen!.

Om een debug-sessie te starten klikken we op de debug main project knop
Figuur 25. Debug Main Project
Debug Main Project
Als de debug sessie gestart is toont MPLAB X IDE standaard de output van de Atmel-ICE. Hier staat dezelfde informatie als bij het programmeren. Als je op het tabblad Debugger Console klikt zie je dat de debug sessie met sucess gestart is
Figuur 27. Debug Console
Debug Console

Breakpoints:

De taakbalk bovenaan het scherm past zich automatisch aan aan de huidige context, zodra je begin te debuggen worden de volgende knoppen toegevoegd.
Figuur 28. Knoppenbalk debug-modus
Knoppenbalk debug-modus

Ik heb nog geen breakpoints toegevoegd, dus de LED op mijn proefinstelling blijft gewoon knipperen. Als ik links op het regelnummer klik wordt hier zo'n breakpoint toegevoegd en zal de microcontroller stoppen op dit punt.

In het editor venster kun je de status van de breakpoints volgen. Het breakpoint dat actief is wordt met een groene achtergrong weergegeven en de andere met een rode achtergrond.
Figuur 29. Breakpoint op regel 20
Breakpoint op regel 20

Willen we dat het programma verder gaat naar het volgende breakpoint, dan klikken we op de knop continue (F5) en het programma zal verder gaan tot het volgende breakpoint bereikt is.

Debug-sessie stoppen:

Als je klaar bent met debuggen, kun je zoals eerder vermeld niet gewoon de Microcontroller en Atmel-ICE (of andere debugger) loskoppelen.

Ik weet niet of het noodzakelijk is, maar voor de veiligheid verwijder ik alle breakpoints en klik daarna op de knop Finish Debugger Session (SHIFT-F5).

Configuration bits

MPLAB X IDE heeft ook een optie om de fuses of configuration bits weer te geven. deze optie zit onder het Production > Set Configuration Bits menu
Figuur 30. Set Configuration Bits
Set Configuration Bits

Terug naar ISP modus

Als je klaar bent met debuggen moet je de microcontroller terug omzetten naar ISP modus, anders kun je deze niet benaderen met een ISP programmer of met de Atmel-ICE is ISP modus (via avrdude bijvoorbeeld).

Om dit te doen openen we de project properties en navigeren we naar Atmel-ICE > Option Catrgories > Communication en zetten we de interface van debugWIRE naar ISP en bevestig met OK:

Figuur 31. Communication : ISP
Communication : ISP
Klik nu op de knop Make and Program Device Main Project
Figuur 31. Omschakelen van debugWIRE naar ISP
Omschakelen van debugWIRE naar ISP

Je krijg een melding dat verbinden via ISP niet mogelijk is omdat je misschien in debugWIRE modus zit, met de vraag of je terug wil omschakelen naar ISP modus. Klik op Yes en de microcontroller zal weer omgeschakeld worden naar ISP en is weer te gebruiken met iedere ISP programmer.

We kunnen dit controleren met avrdude in de commandoregel:

debugWIRE actief:
[patrick@Commandoregel:~]$ avrdude -c atmelice_isp -p m168p

avrdude: Short read, read only 0 out of 512 bytes
avrdude: jtag3_edbg_recv(): Unexpected response 0x50
avrdude: stk500v2_jtag3_recv(): error in jtagmkII_recv()
avrdude: AVR device initialized and ready to accept instructions

Reading |                                                    | 0% 0.00savrdude: Short read, read only 0 out of 512 bytes
avrdude: jtag3_edbg_send(): Unexpected response 0xf0, 0x14
avrdude: stk500v2_command(): command failed
avrdude: stk500isp_read_byte(): timeout/error communicating with programmer
avr_read(): error reading address 0x0000
    read operation not supported for memory "signature"
avrdude: error reading signature data for part "ATmega168P", rc=-2
avrdude: error reading signature data, rc=-2
avrdude: jtag3_edbg_recv(): Inconsistent fragment number; expect 1, got 0
avrdude: stk500v2_jtag3_recv(): error in jtagmkII_recv()
avrdude: Short read, read only 0 out of 512 bytes
avrdude: jtag3_edbg_send(): Unexpected response 0x00, 0x00
avrdude: Short read, read only 0 out of 512 bytes
avrdude: jtag3_edbg_recv(): Unexpected response 0x50
avrdude: Short read, read only 0 out of 512 bytes
avrdude: jtag3_edbg_send(): Unexpected response 0x00, 0x00
avrdude: Short read, read only 0 out of 512 bytes
avrdude: jtag3_edbg_recv(): Unexpected response 0x40
avrdude: Short read, read only 0 out of 512 bytes
avrdude: jtag3_edbg_signoff(): failed to read from serial port (0)

avrdude done.  Thank you.

debugWIRE modus is nog actief en we kunnen de microcontroller niet benaderen via ISP. Als je dit doet zullen alle LEDS op de Atmel-ICE branden. Je kunt de Atmel-ICE dan niet meer gebruiken tot je deze gereset hebt, koppel dan de USB kabel even los en verbind hem weer.

debugWIRE niet actief:
[patrick@Commandoregel:~]$ avrdude -c atmelice_isp -p m168p

avrdude: AVR device initialized and ready to accept instructions

Reading | ################################################## | 100% 0.01s

avrdude: Device signature = 0x1e940b (probably m168p)

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

avrdude done.  Thank you.

We kunnen de ATMega168P weer gewoon gebruiken.

Om later weer te debuggen zet je de communicatie terug in debugWIRE modus en MPLAB X IDE doet de rest.

1 Integrated Development Environment
2 Manueel uitschakelen van debugWIRE is normaal gezien niet nodig).