Sviluppare con i dsPIC

I DSC (Digital Signal Controller) di Microchip sono dei controller single-chip che integrano le funzionalità di controllo di una MCU (MicroController Unit) con la potenza di elaborazione di un DSP (Digital Signal Processor). Microchip fornisce una suite completa di strumenti di sviluppo specifici per i dsPIC, sia software che hardware, altamente integrati in MPLAB IDE. L’ambiente di sviluppo MPLAB è costruito intorno all’IDE (Integrated Development Environment), e si tratta in pratica  dello  stesso  ambiente utilizzato per sviluppare applicazioni  per le MCU delle varie famiglie PIC, cui sono stati aggiunti dei tool specifici  per i dsPIC ed i file di supporto  relativi.

L’AMBIENTE DI SVILUPPO MPLAB

L’ambiente di sviluppo MPLAB è costruito intorno all’IDE (Integrated Development Environment) e comprende i tool necessari per la scrittura del codice, la gestione dei progetti, la compilazione, il debug e la programmazione dei dsPIC.  Esamineremo ora i componenti principali dell’ambiente di sviluppo.

ASM30

Con MPLAB IDE viene fornito un Assembler gratuito per dsPIC denominato ASM30. Si tratta di un macro-assemblatore basato su software open-source GNU, del quale peraltro esistono molte altre versioni per le più diverse piattaforme. Si noti che tale Assembler non è compatibile con il vecchio MPASM utilizzato dai PIC, richiedendo uno sforzo ulteriore per un eventuale porting di applicazioni scritte per essi.

C30

L’uso di un linguaggio di alto livello come il C semplifica notevolmente il compito dello sviluppatore. Il compilatore C30 rende possibile la stesura di un codice  più modulare, più facile da capire e da aggiornare, oltre ad aumentarne la portabilità. C30 è un compilatore ANSI C basato sul noto compilatore GCC (GNU C Compiler). Include una completa libreria ANSI C standard: questa rende disponibili funzioni per la manipolazione di stringhe, l’allocazione dinamica della memoria, funzioni matematiche trigonometriche, esponenziali ed iperboliche. In particolare, MPLAB C30 utilizza il formato IEEE-754 per i dati, un formato ottimizzato per la rappresentazione di tipi a 32 bit. C30 è un compilatore in grado di ottimizzare il codice prodotto.  Il processo di ottimizzazione ha lo scopo di ridurre l’occupazione di memoria del codice e di aumentarne la velocità di esecuzione. Sono disponibili numerose opzioni a riguardo, alcune generiche, altre specifiche per il tipo di dispositivo –vale a dire un DSC. L’ottimizzazione può ad esempio eliminare il codice non raggiungibile, evitare la duplicazione di stringhe, ottimizzare i salti condizionati e non, o realizzare la cosiddetta astrazione procedurale. Quest’ultima consiste nello spostare  porzioni  di  codice  comuni  a più parti del programma, in procedure che vengono eseguite con una chiamata. Il flusso dei dati durante il processo di compilazione è raffigurato nella figura 1.

Figura 1. Flusso dei dati del processo di compilazione

Figura 1. Flusso dei dati del processo di compilazione

MPLAB SIM30

MPLAB SIM30 è un potente debugger sourcelevel gratuito incluso con MPLAB IDE. Esso offre la possibilità di eseguire un debug del codice rapido ed economico senza la necessità di dover realizzare l’hardware sul quale dovrà effettivamente girare l’applicazione. MPLAB SIM30, oltre a simulare il set di istruzioni del dsPIC, è in grado di simulare anche le funzioni delle periferiche principali, tra cui I/O, i timer, i moduli A/D, l’UART. In particolare, la simulazione dell’UART  può  avvenire  abilitando  l’UART1  IO dalla finestra di dialogo Debugger >Settings: in tal modo l’input alla periferica sarà fornito tramite un semplice file di testo, e l’output potrà essere copiato su file o visualizzato nella finestra di Output, in corrispondenza della tab Sim UART1. Qualora si utilizzasse un compilatore  C, basterà inserire nel codice una chiamata alla funzione printf() per visualizzare l’output dell’UART. MPLAB SIM30 offre la possibilità di simulare il comportamento dell’hardware generando stimoli esterni. Gli stimoli possono rappresentare sia variazioni di livelli di tensione sui pin di I/O che variazioni del contenuto degli SFR. In MPLAB SIM30 gli stimoli vengono gestiti tramite lo Stimulus Dialog. Si veda a tal proposito la descrizione di un esempio di utilizzo che verrà fatta nel paragrafo dedicato al debug dell’applicazione d’esempio. MPLAB SIM30 risulta ideale per lo sviluppo degli algoritmi, in particolare per testare operazioni matematiche e  funzioni DSP. In questi casi, infatti, spesso testare il sistema nell’hardware reale può risultare problematico a causa della difficoltà nel ricreare un ambiente controllato, mentre fornire i dati di ingresso (eventualmente campionati da simulazioni reali) sotto forma di file di stimoli semplifica il test.

UN  ESEMPIO DI APPLICAZIONE PER  DSPIC

Vedremo ora un semplice esempio di applicazione in cui ci avvarremo di MPLAB IDE per la gestione del progetto e la compilazione, e di MPLAB SIM per il debug. Sebbene l’uso del linguaggio C sia comune nell’ambito  delle applicazioni di DSP, utilizzeremo il linguaggio assembly/assembler perché questo ci permetterà di capire meglio il modello di programmazione dei dsPIC, ed inoltre evidenzierà alcune caratteristiche dei tool di debug. Il programma d’esempio è l’equivalente del classico Hello world nel campo dei microcontrollori: il dsPIC viene utilizzato per far lampeggiare un led indicato come LED1 se un pulsante SW1 viene premuto, altrimenti il led rimarrà spento. Inoltre, qualora si verificasse un errore software o hardware, accenderà il led LED2.

Creazione del progetto

Per semplificare i passi successivi, creiamo innanzitutto la directory C:\Microchip\Projects\dsPIC\dsPIC_LED nella quale   andremo   a   copiare   il   file   sorgente dsPIC_LED.s. Per la creazione del  progetto  ci  avvarremo del Project Wizard. Una volta lanciato MPLAB IDE, dal menu   dell’IDE   selezioniamo   Project>Project Wizard, quindi premiamo il pulsante Avanti sulla finestra di benvenuto che apparirà. Comparirà una finestra di dialogo  in cui dovremo selezionare il dispositivo  su cui  girerà la nostra  applicazione. Selezioniamo dsPIC30F6014 e premiamo Avanti. Nella successiva finestra di dialogo dovremo scegliere la toolsuite (assemblatore/compilatore,  linker, ecc.) che verrà utilizzata per lo sviluppo del programma:  nel  nostro  caso  sceglieremo  dall’elenco Active toolsuite la Microchip ASM30 toolsuite. Controlliamo nella casella di testo sottostante che i vari componenti  della toolsuite  siano stati individuati dall’IDE (non deve comparire una x accanto al nome di un componente). In caso contrario potremo cercare i componenti premendo il pulsante Browse e navigando nel file system: se abbiamo installato MPLAB IDE come suggerito durante l’installazione, la toolsuite dovrebbe trovarsi nella directory C:\Programmi\Microchip\MPLAB ASM30 Suite\bin. Si veda la figura 2.

Figura 2. Project Wizard: scelta della toolsuite

Figura 2. Project Wizard: scelta della toolsuite

Premiamo  Avanti  per  continuare;  ora  dovremo assegnare  un  nome  al  progetto  e  scegliere  la directory che conterrà i file dello stesso: scriviamo dsPIC_LED come nome del progetto e selezioniamo (tramite il pulsante Browse) C:\Microchip\Projects\dsPIC\dsPIC_LED come directory. Nella successiva finestra dovremo aggiungere al progetto i file sorgenti e di supporto. Ora, navigando nel file system nella casella di sinistra, selezioniamo la directory C:\Programmi\Microchip\MPLAB   ASM30  Suite \Support\gld  e selezioniamo il file p30F6014.gld (figura 3).

Figura 3. Project Wizard: file del progetto

Figura 3. Project Wizard: file del progetto

Clicchiamo  su  Add  per  aggiungerlo nella casella di destra. Il file .gld viene utilizzato dal linker per eseguire le operazioni di allocazione che sono state descritte nel paragrafo dedicato a LINK30. Infine, premiamo il pulsante Avanti e poi Fine per creare il progetto e terminare il wizard. Comparirà nell’ambiente di lavoro dell’IDE la finestra Workspace dalla quale potremo selezionare i file da modificare con l’editor.

Compilazione del progetto

Per compilare il progetto,  selezioniamo Project>Make: si aprirà la finestra Output dove verranno visualizzate le informazioni relative al processo di compilazione. Se  tutto  andrà  bene,  l’ultima riga indicherà con BUILD SUCCEEDED che il processo è andato a buon fine. In caso di errori nel codice, sarà sufficiente cliccare sulla riga relativa nella finestra di Output per essere riportati alla riga di codice corrispondente. Nella finestra di Output, potremo visualizzare tra l’altro un utile report sull’occupazione della memoria del dsPIC da parte dell’applicazione. Per far ciò però è necessario, prima di compilare il progetto, selezionare dalla finestra di dialogo Project>Build Options>Project la scheda MPLAB LINK30, quindi selezionare dall’elenco categories la voce Diagnostics ed infine spuntare la checkbox accanto a Display memory usage. Notiamo anche che il file eseguibile risultante con estensione .cof viene convertito nel formato .hex dalla utility pic30-bin2hex.exe.

Debug dell’applicazione

Innanzitutto dal menu Debugger>Select tool clicchiamo su MPLAB SIM per indicare che lo utilizzeremo nella fase di debug. Per iniziare il debug del codice effettuiamo un reset dell’applicazione premendo F6, o in alternativa cliccando sul comando Debugger>Reset>Processor Reset. Notiamo che sulla barra di stato compare l’indicazione pc:0 che mostra che il program counter del dsPIC è stato azzerato. Diversamente da quanto ci aspetteremmo però, non compare la freccetta che indica nella finestra dell’editor la prossima istruzione che verrà eseguita. Questo perché l’istruzione che si trova nella locazione 0 è sempre una istruzione di salto all’entry point del programma che viene aggiunta automaticamente dal linker (utilizzando il famoso file .gld). Possiamo accertarci di ciò aprendo una finestra Program Memory, con View>Program Memory. Premendo  ora F7, che  corrisponde  al comando Debugger>Step Into, potremo effettuare l’esecuzione passo passo del codice.  Vediamo (figura 4) che nella finestra dell’editor  la freccetta si è spostata accanto alla linea di codice con l’etichetta     reset: è questo l’entry point del nostro programma.

Figura 4. Reset dell’applicazione

Figura 4. Reset dell’applicazione

Esistono altre modalità di esecuzione del codice:

Step Over, Step Out ed Animate. Step Over, selezionata con F8 o Debugger>Step Over, funziona come Step Into eccetto che se l’istruzione è una CALL esegue interamente la subroutine e poi ritorna, arrestandosi dopo la CALL. Step Out, selezionata con Debugger>Step Out, esegue interamente il resto della subroutine attualmente in esecuzione e si arresta dopo la CALL. Infine, Animate, selezionata con Debugger>Animate, è una serie di Step Into ripetute automaticamente a velocità ridotta. In ogni caso, si può interrompere l’esecuzione con F5, corrispondente a Debugger>Halt. Spesso è necessario interrompere l’esecuzione di un programma in punti determinati, in modo da poter esaminare i valori delle variabili o controllare il flusso di esecuzione del programma. Per far ciò si utilizzano i breakpoint, o punti di interruzione. Ad esempio, esaminando il codice, notiamo che esiste un loop identificato dall’etichetta Mainloop:

; Se il periodo e’ trascorso esce
Mainloop: btss IFS0, #T1IF
; altrimenti rifa’ il loop bra     Mainloop
bclr IFS0, #T1IF

questo loop viene eseguito fintantoché  il timer1 del dsPIC non avrà segnalato che è trascorso un certo intervallo di tempo (il flag T1IF verrà allora posto  ad 1), dopodichè  il flusso del programma riprenderà dall’istruzione  bclr.  È evidente che in tale caso risulta particolarmente scomodo eseguire il programma passo-passo  a causa del numero elevato dei passi: settiamo allora un breakpoint alla linea contenente l’istruzione bclr facendo doppio click sulla linea stessa. Alternativamente possiamo, sempre ponendo  il cursore in corrispondenza della linea dove vogliamo impostare il breakpoint, cliccare con il tasto destro del mouse e selezionare  dal  menu  contestuale che apparirà, la voce Set Breakpoint.  Effettuiamo  un reset con F6 e facciamo quindi eseguire il programma a velocità  normale  con  il  comando Debugger>Run   (o   con   F9): dopo un certo periodo di tempo, proporzionale al numero di  istruzioni  che  il  simulatore dovrà eseguire, l’esecuzione del programma si arresterà in corrispondenza del breakpoint (figura 5).

Figura 5. Arresto dell’esecuzione tramite un breakpoint

Figura 5. Arresto dell’esecuzione tramite un breakpoint

Con le versioni più recenti di MPLAB SIM è possibile anche imporre delle condizioni complesse di breakpoint, utilizzando il menu Debugger>Complex Breakpoints. Si tratta di breakpoint utili per intercettare delle occorrenze inusuali nel codice, dipendenti da un insieme di condizioni. Nello specifico, è possibile generare un breakpoint in funzione di:

  • una lettura/scrittura di un registro SFR o GPR;
  • lettura/scrittura di tabelle in program memory;
  • caricamento di una data istruzione.

Inoltre si può utilizzare un pass counter per far scattare il breakpoint solo dopo un certo numero di occorrenze o di cicli istruzione. I breakpoint avanzati possono essere usati  con una sequenza prestabilita (Sequenced Breakpoints) od in combinazione fra loro (ANDED Breakpoints). Per esaminare il contenuto delle variabili e degli SFR, possiamo utilizzare la finestra Watch, richiamabile da View>Watch. Potremo anche modificare il contenuto della memoria facendo doppio click nella casella della colonna Value. Selezioniamo ad  esempio  dall’elenco  a  sinistra l’SFR indicato come PORTD e clicchiamo su Add SFR per aggiungerlo all’elenco sottostante (figura 6).

Figura 6. Finestra Watch

Figura 6. Finestra Watch

Il contenuto  dei bit  1:0 di questo registro corrisponderà ai livelli logici presenti sui pin dove sono collegati i LED del nostro…sistema virtuale! Effettuiamo un reset con F6 ed eseguiamo il run dell’applicazione con F9: notiamo che ogni volta che  viene raggiunto  il  breakpoint  che  abbiamo impostato, il valore di PORTD cambierà commutando il bit 0 da 0 ad 1 e viceversa indicando che il LED1 lampeggia correttamente (il pulsante SW1 risulta premuto). Una caratteristica molto utile di MPLAB SIM è che  possiamo  controllare  l’intervallo  di  tempo che intercorre tra due eventi utilizzando la fine stra Stopwatch. Apriamo lo Stopwatch con Debugger>Stopwatch: in essa vengono visualizzati i cicli d’istruzione eseguiti ed il tempo trascorso sia tra due eventi (Stopwatch) che dall’inizio della simulazione (Total simulated). Si può azzerare lo Stopwatch in un dato punto della simulazione premendo il tasto Zero. Le tempistiche sono calcolate a partire dal clock del dispositivo: per settarlo correttamente dobbiamo aprire la finestra di dialogo Simulator Settings da Debugger>Settings, quindi selezionando la linguetta Osc/Trace impostiamo il valore di 20 MHz per la frequenza di clock. Ora possiamo utilizzare lo Stopwatch con la nostra applicazione: effettuiamo un reset con F6, premiamo  F7  finchè  il  cursore  non  si  porta  su Mainloop, premiamo il tasto Zero dello Stopwatch e quindi eseguiamo il programma con F9. L’esecuzione si arresterà in corrispondenza del breakpoint  che avevamo impostato  e lo Stopwatch mostrerà che l’intervallo di tempo  trascorso  è di circa 250 ms, corrispondente al periodo del timer1 così come impostato nel codice (figura 7).

Figura 7. Stopwatch: controllo del periodo del timer

Figura 7. Stopwatch: controllo del periodo del timer

Mediante il Trace Buffer possiamo visualizzare un elenco delle ultime istruzioni eseguite durante la simulazione. Il Trace Buffer può memorizzare un massimo di circa 65000 istruzioni; il buffer è circolare, perciò una volta riempito, le istruzioni più recenti sovrascrivono quelle più vecchie. Perché sia attivo è necessario controllare che nella finestra di dialogo Simulator Settings (Debugger>Settings), in corrispondenza della linguetta Osc/Trace sia spuntata la checkbox indicata da Trace All. Possiamo richiamare la finestra del Trace Buffer con View>Simulator Trace.

Stimulus Dialog

Come già accennato, MPLAB SIM30 offre la possibilità di simulare il comportamento dell’hardware generando stimoli esterni. Gli stimoli possono rappresentare sia variazioni di livelli di tensione sui pin di I/O che variazioni del contenuto degli SFR o dei GPR (General Purpose Register). Inoltre possono avvenire dopo un certo numero di cicli di clock o dopo un certo tempo, oppure quando è verificata una certa condizione, ad esempio, quando è raggiunta una data istruzione. Gli stimoli si distinguono fondamentalmente in:

  • sincroni: una serie predefinita di variazioni sui pin di I/O o variazioni del contenuto degli SFR o dei GPR;
  • asincroni: una serie analoga che si verifica però in un momento qualsiasi sotto controllo dell’utente.

In particolare, gli stimoli sincroni si distinguono in:

  • pin/register actions: variazioni di I/O e dei registri che avvengono in tempi determinati;
  • advanced pin/register: variazioni del tipo precedente che però possono avvenire in base a condizioni complesse, ad esempio in funzione del valore di altri registri;
  • clock stimulus: serie di impulsi sui pin I/O, sincronizzati dal clock del dispositivo, che iniziano e terminano in corrispondenza di un dato numero di cicli o di un valore di un pin, o ancora al raggiungimento di una data istruzione;
  • register injection: variazioni dei registri lette da file. Il trigger può essere on Demand, dipendente dal Program Counter, Message-based (per l’USART/UART).

A loro volta si distinguono due tipi di stimoli asincroni:

  • regular: l’azione dello stimolo  può  essere tipo Pulse, High, Low, Toggle;
  • message-based:  l’azione  dello  stimolo  è  una serie di messaggi (packets) contenuti  in file o immessi direttamente  nella finestra di dialogo. Tali stimoli sono utilizzati per l’USART/UART.

Le opzioni relative alla creazione ed all’utilizzo degli stimoli sono molto numerose ed esulano dallo scopo di questo articolo. Si faccia riferimento all’help online di MPLAB SIM per una trattazione completa. Vediamo un esempio di creazione ed uso di uno stimolo asincrono. Apriamo la finestra Stimulus con Debugger>Stimulus> New Workbook. Genereremo uno stimolo asincrono che utilizzeremo per simulare la pressione del tasto SW1. Nella finestra Stimulus che abbiamo aperto selezioniamo la scheda Asynch, immettiamo quindi i valori delle colonne così come compaiono  nella figura 8.

Figura 8. Esempio di stimolo asincrono

Figura 8. Esempio di stimolo asincrono

Ora rimuoviamo il breakpoint immesso in precedenza con un doppio click sulla linea relativa e settiamo un nuovo breakpoint in corrispondenza di per esempio:

; Testa SW1
TestSW1:       btsc PORTA, #12
; se non e’ premuto salta bra      SwitchOff
; altrimenti LED1 lampeggia btg     LATD, #0
; e rifa’ il ciclo bra      MainLoop
; Spegne LED1
SwitchOff: bset LATD, #0

Resettiamo con F6 ed eseguiamo con F9. L’esecuzione si arresterà in corrispondenza di TestSW1: in questo punto viene controllato il valore sul pin RA12. Se il valore logico è high (SW1 NON premuto) l’esecuzione salta all’etichetta SwitchOFF, altrimenti prosegue con l’istruzione successiva a quella di salto. Premiamo ora il tasto Fire in corrispondenza della riga RA12 della finestra Stimulus: poiché inizialmente il valore di RA12 è sempre low, dopo aver applicato lo stimolo diventerà high. Premendo ora F7 possiamo vedere che viene eseguita l’istruzione di salto a SwitchOFF. Se premiamo nuovamente F9 e successivamente applichiamo lo stimolo col tasto Fire, il valore di RA12 tornerà low (SW1 premuto), per cui il flusso del programma riprenderà dall’istruzione successiva a quella di salto.

 

 

Iscriviti e ricevi GRATIS
Speciale Pi

Fai subito il DOWNLOAD (valore 15€) GRATIS

STAMPA     Tags:, , ,

Una risposta

  1. Maurizio Di Paolo Emilio Maurizio Di Paolo Emilio 17 agosto 2017

Scrivi un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *

Iscriviti e ricevi GRATIS
Speciale Pi

Fai subito il DOWNLOAD (valore 15€) GRATIS