Howto debug con PIC32

pic32 debug

Le schede di sviluppo PIC32 micro sono progettate per imparare a programmare le applicazioni dei PICmicro e per lo sviluppo di progetti basati sui PIC32 micro. I kit di sviluppo pronti all'uso, con il debugger totalmente incorporato, sono di grande aiuto a chi sta iniziando a programmare (come me!), con il linguaggio C, i dsPIC.

Howto debug con PIC32

Un caro amico mi ha dato uno starter kit PIC32MX dicendomi: accendilo e giocaci. Facile a dirsi, difficile a farsi. Lo starter kit PIC32MX contiene i seguenti oggetti:
• Un CD-ROM per l'installazione
Contiene i Data Sheet, il family reference manual, il peripheral library manual,
esempi di codice, gli schemi e file di disegno del PCB (Printed Circuit Board).
• La scheda dello starter kit PIC32MX + il cavo USB MINI-B

La scheda comprende principalmente :

Un micro-controllore PIC32MX360F512L 32-bit
Un micro-controllore PIC18LF4550 USB micro-controller per il debugging
Un LED verde per indicare la presenza di tensione
Tre pulsanti per input definiti dall'utente
Tre LED per usi definiti dall'utente

Nella figura sottostante c'è il layout della scheda dello starter kit PIC32MX

layout della scheda dello starter kit PIC32

Nel CD del PIC32 starter kit c'è una applicazione che mi ha guidato nella installazione automatica di tutti gli strumenti e di tutta la documentazione necessaria per la mia nuova avventura. Ho seguito, passo dopo passo, tutte le indicazioni su come costruire un progetto ( " Building the project" ), ho usato gli esempi in codice già scritti per essere sicuro che la scheda stesse lavorando correttamente, alla fine ero pronto a costruire un mio progetto.

Cosa potevo fare con tre LED e tre pulsanti? Potevo simulare, con il pulsante n° 1, un sensore ( per esempio una fotocellula ) che rileva la presenza di qualcuno che entra in una stanza, questo evento accende un LED che posso resettare premendo un secondo pulsante. Per accendere e spegnare un LED ho usato le seguenti istruzioni:

mPORTDSetBits(BIT_0); ( BIT_0  is referred to LED1) 
mPORTDClearBits(BIT_0);

Il problema più grande che ho dovuto affrontare (almeno per me) è stata la correlazione pulsante-LED. In quale modo il PIC32 poteva "capire" che io stavo premendo un pulsante? I pulsanti dovrebbero avere un valore quando vengono premuti e un altro valore quando vengono rilasciati. Come prendere questi valori?
Spulciando tra documentazione ed esempi di codice ho trovato che i due pulsanti e il LED erano definiti nella seguente maniera:

/* PORTD */

#define _RD0 PORTDbits.RD0     // LED1
#define _RD6 PORTDbits.RD6, Change Notice ( CN15 )    //  SW1
#define _RD7 PORTDbits.RD7, Change Notice ( CN16 )    //  SW2 

Così ho messo nel mio codice le seguenti definizioni:

#define PINS1        (CN15_ENABLE)
#define PINS2        (CN16_ENABLE)
#define PULLUPS1     (CN15_PULLUP_ENABLE)
#define PULLUPS2     (CN16_PULLUP_ENABLE)

All'inizio, per abilitare il pulsante n° 1 ho scritto:

mCNOpen(CONFIG,PINS1,PULLUPS1);

quindi per abilitare il pulsante n° 2:

mCNOpen(CONFIG,PINS2,PULLUPS2);

Ho ottenuto, come risultato, che solo il pulsante n° 2 era stato abilitato. C'era qualcosa di sbagliato nel mio ragionamento. Cercando ancora nella documentazione ho trovato:

_pins

CN Enable Pins
CN0_ENABLE
CN1_ENABLE
CN2_ENABLE
...
CN21_ENABLE
CN_DISABLE_ALL

_pullups 

This argument contains one or more bit masks bitwise OR’d together. Select one or more from the following bitmasks. 
Note: An absent mask symbol assumes corresponding bit(s) are disabled, or default value, and will be set = 0.

CN Enable Pullups
CN0_PULLUP_ENABLE
CN1_PULLUP_ENABLE
CN2_PULLUP_ENABLE
...
CN21_PULLUP_ENABLE
CN_PULLUP_DISABLE_ALL


Code Example: /* enable pullups on change notice pins 10,11 */
ConfigCNPullups(CN10_PULLUP_ENABLE | CN11_PULLUP_ENABLE);

Così, logicamente, dovevo fare l'OR tra le mie istruzioni e non scriverle separatamente: in precedenza avevo prima abilitato SW1, quindi, come se avessi cambiato idea, avevo abilitato SW2. Quindi l'istruzione corretta era:

mCNOpen(CONFIG,PINS1|PINS2,PULLUPS1|PULLUPS2);

I pulsanti non hanno alcun circuito di antirimbalzo (debounce circuit) e richiedono l'uso di resistenze interne di pull-up. Quando non sono premuti si trovano alla tensione di +3.3V (pulled high), quando sono premuti vengono messi a massa. Così, per risolvere il problema, avevo bisogno di vedere i loro valori di transizione.
Ho avuto un grande aiuto da Watch window, Breakpoint e Step Into, tre strumenti per il debug. In Watch window ho selezionato la variabile "temp", nel codice ho messo un Breakpoint ( vedi la figura sottostante). Quando ho premuto SW1 il programma, in esecuzione, si è fermato al Breakpoint ed ho ottenuto il valore - EFBE; quando lo ho rilasciato, tramite lo Step Into, ho ottenuto il valore - EFFE.
Così la transizione della variabile "temp" era stata da "B" a "F", quindi il valore di transizione che stavo cercando era 0x40 (valore esadecimale). Alla stessa maniera quando ho premuto SW2 ho ottenuto il valore - FF7C, quando lo ho rilasciato ho ottenuto il valore - FFFC. Così la transizione della variabile "temp" era stata da "7" a "F", il valore di transizione che stavo cercando era 0x80. Nelle figure sottostanti si può seguire tutta la sequenza che è stata qui sopra descritta.

Valore di transizione di SW1

Valore di transizione di SW1

Valore di transizione di SW2

Valore di transizione di SW2

N.B. Più tardi, purtroppo, ho scoperto che i valori di transizione erano già stati definiti. Nel file "pic32mx360f512l.h" c'erano le seguenti definizioni:

#define _PORTD_RD6_POSITION                      0x00000006
#define _PORTD_RD6_MASK                             0x00000040
#define _PORTD_RD6_LENGTH                        0x00000001


#define _PORTD_RD7_POSITION                      0x00000007
#define _PORTD_RD7_MASK                            0x00000080
#define _PORTD_RD7_LENGTH                        0x00000001

Un altro problema che ho dovuto affrontare, e che purtroppo mi ha portato via molto tempo, è stato quello di riuscire ad utilizzare il potente strumento per il debug che ha solo il micro-controllore PIC32, nell'ambito delle altre famiglie di micro-controllori della Microchip. Questi strumenti per il debug consentono a MPLAB di interagire in maniera interattiva con il micro-controllore. Il primo strumento per il debug consente di vedere se si ottengono i risultati voluti con l'inserzione di una lettera o di un carattere dalla tastiera. Nell'esempio che segue possiamo commutare i tre LED (rosso, verde, arancione) tramite l'inserimento di R,G,O, inseriamo X per uscire dal ciclo. Sotto c'è il codice, la finestra di uscita (Output window) e la finestra che appare chiedendo di inserire l'informazione da mandare al micro-controllore.

 // Display the menu
       DBPRINTF("Basic Starter Kit Lab (" __DATE__ "," __TIME__ ")\n");
       DBPRINTF("type E to echo the Input String. \n");
       DBPRINTF("type R to toggle the RED LED. \n");
       DBPRINTF("type O to toggle the ORANGE LED. \n");
       DBPRINTF("type G to toggle the GREEN LED. \n");
       DBPRINTF("type X to exit the Loop. \n");  
       DBPRINTF("Enter a menu choice (e,r,o,g) \n");  

MPLAB PIC32 debug

Debug TargetIN

Il secondo strumento per il debugging ci permette di mandare alla finestra di uscita (Output window) tutti i messaggi che vogliamo. In questa maniera possiamo seguire, passo dopo passo, dove siamo (in quale ciclo, in quale routine, in quale interrupt) e possiamo vedere i valori delle variabili. Per esempio, se inseriamo nel nostro codice la seguente funzione di libreria:

DBPUTS ("I am in the interrupt routine");

Il messaggio in uscita (il TargetOUT) sarà: I am in the interrupt routine

Debug TargetOUT

Ho detto che ci è voluto molto tempo per fare funzionare questi strumenti di debug perché ho dovuto scoprire che bisognava aggiungere la macro "PIC32_STARTER_KIT" alle opzioni del compilatore C32 e bisognava aggiungere il file "db_utils.a" ai file di libreria (Library Files - vedi le figure sottostanti)

Debug Library Files

Qui sotto c'è il codice del mio semplice "progetto", ma è semplice tutto ciò che si sa fare, altrimenti...

Platform: PIC32MX Starter Kit

Description:
This example set on LED1 (PORTD.RD0) when SW1 (PORTD.RD6) is pressed, causing a Change Notice interrupt; set off LED1 when SW2 ( PORTD.RD7 ) is pressed, causing a Change Notice interrupt.

PIC32MX Starter Kit Led and Switches assignments:

LED1 is on PORTD.RD0
SW1 is on PORTD.RD6, Change Notice (CN15)
SW2 is on PORTD.RD7, Change Notice (CN16)

No resistor pullups are provided for SW1,SW2. PORTD internal pullups should be enabled.

#include "db_utils.h"
#include 
#include 

// Configuration Bit settings
// SYSCLK = 72 MHz (8MHz Crystal/ FPLLIDIV * FPLLMUL / FPLLODIV)
// PBCLK = 36 MHz
// Primary Osc w/PLL (XT+,HS+,EC+PLL)
// WDT OFF

#pragma config FPLLMUL=MUL_18,FPLLIDIV=DIV_2, FPLLODIV=DIV_1,FWDTEN=OFF
#pragma config POSCMOD=HS, FNOSC=PRIPLL,FPBDIV=DIV_2

#define CONFIG      (CN_ON | CN_IDLE_CON )
#define PINS1        (CN15_ENABLE)        //SW1 enabling
#define PINS2        (CN16_ENABLE)       // SW2 enabling
#define PULLUPS1     (CN15_PULLUP_ENABLE)
#define PULLUPS2     (CN16_PULLUP_ENABLE)
#define INTERRUPT   (CHANGE_INT_ON | CHANGE_INT_PRI_2)
#define FOSC         72E6



int main(void)
{
  unsigned int temp;
   DBINIT();     // Initialize the IO channel


// STEP 1. Configure cache, wait states and peripheral bus clock
  SYSTEMConfigPerformance(FOSC);

// STEP 2. configure the port registers
  PORTSetPinsDigitalOut(IOPORT_D,BIT_0);
  PORTSetPinsDigitalIn(IOPORT_D,BIT_6);
  PORTSetPinsDigitalIn(IOPORT_D,BIT_7);

// STEP 3. initialize the port pin states = outputs low
  mPORTDClearBits(BIT_0);

 // STEP 4. enable change notice, enable discrete pins and weak pullups
  mCNOpen(CONFIG,PINS1|PINS2,PULLUPS1|PULLUPS2);

// STEP 5. read port(s) to clear mismatch on change notice pins
  temp=mPORTDRead();  

 // STEP 6. clear change notice interrupt flag
  ConfigIntCN(INTERRUPT);

 // STEP 7. enable multi-vector interrupts
  INTEnableSystemMultiVectoredInt();
  while(1)
  {
   DBPUTS(" I am waiting for an input ");
  }
 }

 // STEP 8. configure the CN interrupt handler
void __ISR(_CHANGE_NOTICE_VECTOR, ipl2) ChangeNotice_Handler(void)
{
 DBPUTS(" I am in the interrupt routine");
 unsigned int temp;
 temp=mPORTDRead();  
 if((temp & 0x40) ==0 )// SW1 transition value
 {
   mPORTDSetBits(BIT_0); // Switch ON LED1
  }
 if((temp & 0x80)==0)  // SW2 transition value
 { 
  mPORTDClearBits(BIT_0); //Switch OFF LED1
 }
  mCNClearIntFlag();      // Clear interrupt flag
 }
Scarica subito una copia gratis

3 Commenti

  1. Avatar photo Domenico 21 Gennaio 2015

Scrivi un commento

Seguici anche sul tuo Social Network preferito!

Send this to a friend