Sistemi a Microcontrollore - Programmazione e Debug Anno Accademico 2018/2019 - UniCa
←
→
Trascrizione del contenuto della pagina
Se il tuo browser non visualizza correttamente la pagina, ti preghiamo di leggere il contenuto della pagina quaggiù
Sistemi a Microcontrollore 6. Programmazione e Debug Anno Accademico 2018/2019
Indice • Programmazione Flusso di Programmazione Librerie • Debug Debugger Comunicazione Seriale
Indice • Programmazione Flusso di Programmazione Librerie • Debug Debugger Comunicazione Seriale
Utilizzo di in un Microprocessore/Microcontrollore Le applicazioni in un microprocessore possono esser viste attraverso diversi livelli di astrazione che vanno dal software all’hardware: l’Instruction Set Architecture (ISA) costituisce l’interfaccia tra i due mondi. high-level program (e.g. C, Java) compilation SOFTWARE Instruction Set Architecture HARDWARE execution dispositivo hardware
Utilizzo di in un Microprocessore/Microcontrollore In realtà il flusso di programmazione di un microprocessore/microcontrollore tipicamente contiene più livelli e più passaggi intermedi high-level source code 1 program compiler assembly program object (blocks code) 2 machine assembler language program 3 executable machine linker language machine library language program 4 Flash loader memory
Compilatore • Il compilatore traduce un linguaggio di alto livello (es. C) in assembly, forma simbolica del linguaggio macchina in passato molti sistemi operativi erano scritti direttamente in assembly per via della capacità ridotta delle memorie e dei compilatori inefficienti con il progresso dei compilatori e delle memorie, oggi la compilazione produce programmi assembly quasi come uno sviluppatore esperto di assembly
Assembler • L’assembler ha il compito principale di tradurre il programma in linguaggio assembly nel corrispondente codice macchina (oggetto) • L’assembler si occupa in particolare di tradurre pseudo-istruzioni in istruzioni native dell’ISA ottimizzare i salti in base agli spostamenti necessari estendere le istruzioni con funzionalità speciali (es. nel MIPS consente load immediate di due parole contemporaneamente tramite un registro dedicato)
Linker • Il linker ha il compito di raggruppare tutti gli oggetti (codice macchina, dati e informazioni supplementari) corrispondenti alle procedure del programma e di creare l’eseguibile corrispondente • Il linker si occupa di posizionare il codice e i dati in memoria determinare l’indirizzo di dati e delle etichette dei salti • L’eseguibile ha il formato di un file oggetto ma non contiene riferimenti non risolti
Loader • Il loader è lo strumento che permette di scaricare il programma nel dispositivo target ed eseguirlo • In particolare, il loader determina la dimensione dei segmenti (text e data) del programma crea uno spazio di indirizzi che contenga i segmenti copia istruzioni e dati in memoria inizializza i registri della macchina (stack pointer) salta a una routine di inizializzazione (prologo del main)
Indice • Programmazione Flusso di Programmazione Librerie • Debug Debugger Comunicazione Seriale
Librerie • Le librerie e le routine precompilate/preassemblate sono parti (blocchi) del programma che possono essere utilizzate all’occorrenza, senza necessità di svilupparle ogni volta da capo tipicamente sono blocchi di programma che non cambiano e che sono utili a gestire funzionalità specifiche (es. driver, chiamate a sistema) velocizzano lo sviluppo del codice e, se precompilate/preassemblate, la programmazione (linker) lo sviluppatore stesso può definire nuove librerie
Link Statico di Librerie • Il link alle librerie utilizzate nel programma viene fatto prima dell’esecuzione del programma (in compilazione). • È il modo più rapido per chiamare routine di libreria, ma presenta degli svantaggi: le routine di libreria divengono parte del codice eseguibile, per cui nuove versioni delle librerie non verrebbero integrate se non si rigenera l’eseguibile tutte le routine di libreria chiamate in qualunque parte dell’eseguibile vengono caricate, anche se successivamente non vengono effettivamente eseguite, causando uno spreco di risorse di memoria
Link Dinamico di Librerie • Nelle librerie con link dinamico (DLLs, dynamically linked libraries) le routine non sono linkate e caricate prima dell’esecuzione, ma vi sono informazioni aggiuntive nelle librerie e nel programma relative alla collocazione delle routine di libreria. le prime DLLs avevano un loader che faceva il link dinamico sfruttando tali informazioni aggiuntive per trovare le routine di libreria e aggiornarle nell’eseguibile (vi era comunque il caricamento di tutte le routine di libreria a prescindere dal loro effettivo utilizzo) le DLLs recenti effettuano il link di ogni routine solo dopo che la stessa routine viene chiamata (in tempo di esecuzione)
Esempio: avr/io.h • Un esempio di libreria per i microcontrollori AVR è la quella definita dall’header avr/io.h che, per l’ATmega328p richiama a sua volta avr/iom328p.h int main(void) { volatile int* PORTB = (volatile int*) 0x0025; // declare and initialize PORTB pointer volatile int* DDRB = (volatile int*) 0x0024; // declare // decalre and and initialize init ADC DDRB pointer pointers long int i; // declare volatile index i= (volatile int*) 0x007C; int* ADMUX char state = 0x00; // declare volatile and initialize int* ADCSRA led state = (volatile int*) 0x007A; *DDRB = 0x02; // set port B as output volatile int* ADCH = (volatile int*) 0x0079; int main(void) { volatile int* ADCL = (volatile int*) 0x0078; while(1) { // infinite loop i = 0; = (volatile int*) 0x002A; volatile int* DDRD // initialize // declare index and initialize int adc_read (int {i ch) DDRB pointer while(i
Esempio: avr/io.h • La libreria avr/io.h facilita l’accesso agli input e output del microcontrollore fornendo i puntatori delle risorse mappate in memoria e l’indice dei relativi bit di interesse attraverso delle variabili rappresentative #define DDRB _SFR_IO8(0x04) #define ADCL _SFR_MEM8(0x78) #define DDB0 0 #define ADCL0 0 #define DDB1 1 #define ADCL1 1 #define DDB2 2 #define ADCL2 2 #define DDB3 3 #define ADCL3 3 #define DDB4 4 #define ADCL4 4 #define DDB5 5 #define ADCL5 5 #define DDB6 6 #define ADCL6 6 #define DDB7 7 #define ADCL7 7
Esempio: avr/io.h • La libreria avr/io.h definisce anche le variabile per la gestione degli interrupt ed in particolare assegna un identificativo ai vettori corrispondenti alle sorgenti supportate dal microcontrollore /* Interrupt Vectors */ /* Interrupt Vector 0 is the reset vector. */ … #define INT0_vect_num 1 #define INT0_vect _VECTOR(1) /* External Interrupt Request 0 */ … #define TIMER0_COMPA_vect_num 14 #define TIMER0_COMPA_vect _VECTOR(14) /* TimerCounter0 Compare Match A */ …
Esempio: avr/interrupt.h • La libreria avr/interrupt.h definisce i costrutti per poter utilizzare gli interrupt nel codice di alto livello (C) occorre specificare che una porzione di codice (una funzione) è una interrupt service routine (ISR) o meno in modo che il compilatore inserisca delle opportune istruzioni di salto nelle locazioni fisse associate alla specifica sorgente di interrupt
Esempio: avr/interrupt.h • La libreria avr/interrupt.h mette a disposizione dei costrutti per specificare l’ISR relativo a ogni sorgente di interrupt vector specifica il vettore a cui si riferisce l’ISR a differenza di SIGNAL, il costrutto ISR permette di specificare funzionalità aggiuntive (abilitazione globale interrupt, no prologo ed epilogo) attraverso gli attributi /** Introduces an interrupt handler function (interrupt service routine) that runs with global interrupts initially disabled by default with no attributes specified.**/ #define ISR(vector, [attributes]) /** Introduces an ISR that runs with global interrupts initially disabled.**/ #define SIGNAL(vector)
Esempio: avr/interrupt.h • La libreria avr/interrupt.h tra l’altro espone direttamente al programmatore C le istruzioni di sei e cli che consentono di abilitare o meno gli interrupt globalmente l‘istruzione di reti per il ritorno da interrupt (utile quando si definisce un ISR senza prologo ed epilogo) /** Disables all interrupts by clearing the global interrupt mask.**/ #define sei() /** Disables all interrupts by clearing the global interrupt mask. **/ #define cli() /** Returns from an interrupt routine, enabling global interrupts. **/ #define reti()
Indice • Programmazione Flusso di Programmazione Librerie • Debug Debugger Comunicazione Seriale
Debug • Il debug di un programma sviluppato per il microcontrollore consiste nella sua esecuzione in condizioni simili a quelle reali e la verifica che il comportamento sia quello desiderato • Se si verificano errori o anomalie, il programma viene corretto e testato nuovamente si procede iterativamente finché il comportamento non è quello desiderato per ogni condizione operativa SVILUPPO TEST
Debug • Tipicamente i microcontrollori forniscono delle funzionalità di debugging • Il debugger è un software che si connette al microcontrollore per monitorarne il comportamento in tempo reale i principali compiti del debugger sono: connettersi alla scheda di sviluppo, programmare il microcontrollore, debuggare il programma talvolta il debugger richiede circuiteria addizionale (spesso integrata nelle schede di sviluppo)
Debug • Il debugger solitamente ha accesso al microcontrollore tramite una porta dedicata che può supportare una o più interfacce di debug Joint Test Action Group (JTAG) Serial Wire Debug (SWD) Background Debug Mode (BDM) debugWIRE
Debug • Strumenti del debugger breakpoints/watchpoints monitoraggio variabili monitoraggio registri/memorie monitoraggio stack
Breakpoints/Watchpoints • I breakpoint e i watchpoint forniscono un modo per interrompere l’esecuzione del programma in in base al raggiungimento di una prefissata riga di codice (breakpoint) in base al cambiamento del valore di una variabile o di un’espressione (watchpoint) • Il numero di breakpoint consentiti per un’esecuzione può essere limitato a seconda del microcontrollore
Monitoraggio Variabili • È possibile monitorare delle variabili durante l’esecuzione le variabili monitorate possono essere lette o modificate quando l’esecuzione viene interrotta • Talvolta è anche possibile monitorare espressioni che vengono calcolate in tempo di esecuzione anche in questo caso le espressioni possono essere lette o modificate solo quando l’esecuzione viene interrotta
Monitoraggio Registri/Memorie • Spesso il debugger permette di monitorare il contenuto dei registri (interni alla CPU, speciali e relativi alle periferiche) e delle memorie presenti nel sistema è possibile monitorarne il contenuto quando l’esecuzione viene interrotta spesso è anche possibile modificarne il contenuto, sempre previa interruzione
Monitoraggio Stack • Alcuni debugger consentono il monitoraggio della gerarchia delle chiamate attraverso l’accesso allo stack dallo stack è possibile risalire alle funzioni chiamate a partire dal rispettivo stack frame è possibile leggere il contenuto dello stack solamente quando l’esecuzione viene interrotta questa funzionalità risulta essere particolarmente utile nei microcontrollori che supportano il multi-threading
Indice • Programmazione Flusso di Programmazione Librerie • Debug Debugger Comunicazione Seriale
Comunicazione Seriale • Al di là del debugger, uno strumento molto utilizzato per la verifica di un programma nei microcontrollori è la comunicazione seriale • Anche se il microcontrollore non ha bisogno di comunicare serialmente con un’altra periferica, durante la fase di sviluppo si ha quasi sempre bisogno di utilizzare una comunicazione seriale per connettere il sistema all’esterno durante l’esecuzione
UART • Il dispositivo hardware più utilizzato per la comunicazione seriale nei microcontrollori è lo Universal Asynchronous Receive-Transmit (UART) tx rx UART rx tx UART 0 1 GND GND
USART • I dispositivi Universal Synchronous- Asynchronous Receive-Transmit (USART) sono un’evoluzione degli UART che consentono anche trasmissioni sincrone, ovvero temporizzate da un segnale di clock (raggiungono data rate maggiori) tx rx UART rx tx UART 0 clk clk 1 GND GND
UART In trasmissione, la UART converte dei dati paralleli (es. a 8 bit), che arrivano dal dispositivo che la controlla (tipicamente una CPU) in seriali (a 1 bit) per inviarli ad una UART ricevente parallel serial UART … input output In ricezione, la UART converte dei dati seriali (a 1 bit), ricevuti da una UART trasmittente, in paralleli (es. 8 bit) per inviarli al dispositivo che la controlla (tipicamente una CPU) serial parallel UART … input output
Funzionamento della UART • La UART trasmette i dati in maniera asincrona non è previsto nessun clock per sincronizzare la trasmissione tuttavia per consentire una corretta ricezione sono aggiunti dei bit di start e di stop al pacchetto di dati che viene trasmesso • i bit di start e di stop definiscono l’inizio e la fine del pacchetto, in modo tale che la UART ricevente sappia quando iniziare a leggere i bit di dato
Funzionamento della UART • Quando la UART ricevente trova un bit di start, inizia a leggere i bit successivi a una frequenza specifica detta baud rate (bit per secondo, bps) entrambe le UART devono operare allo stesso baud rate (errore massimo del 10% tra i due baud rate) entrambe le UART devono anche essere configurate per trasmettere e ricevere lo stessa struttura del pacchetto dati
Funzionamento della UART START DATA PARITY STOP 1 bit 5-9 bit 0-1 bit 1-2 bit • Il pacchetto dati contiene 1 bit di start da 5 a 9 bit di dato 1 bit di parità opzionale 1 o 2 bit di stop
Funzionamento della UART START DATA PARITY STOP 1 bit 5-9 bit 0-1 bit 1-2 bit • START bit le linee di comunicazione della UART sono normalmente poste a 1 (livello di voltaggio alto) quando non vi è una trasmissione quando la UART trasmittente inizia un trasferimento, pone la linea a 0 per un periodo di baud quando la UART ricevente legge uno 0 sulla linea inizia a leggere i bit di DATA al baud rate prestabilito
Funzionamento della UART START DATA PARITY STOP 1 bit 5-9 bit 0-1 bit 1-2 bit • DATA bit la porzione DATA contiene i dati che vengono trasmessi in un certo istante può contenere da 5 a 8 bit se viene usato il bit di parità può contenere da 5 a 9 bit se non viene usato il bit di parità spesso il dato è trasmesso a partire da bit meno significativo (LSB)
Funzionamento della UART START DATA PARITY STOP 1 bit 5-9 bit 0-1 bit 1-2 bit • PARITY bit il bit di parità costituisce un metodo di rilevazione di errore nella trasmissione gli errori sono causati da radiazioni elettromagnetiche, baud rate non coincidenti o distanze troppo lunghe il valore del PARITY bit dipende dal numero di 1 del dato • se il numero di 1 in DATA è pari, PARITY sarà 0 • se il numero di 1 in DATA è dispari, PARITY sarà 1
Funzionamento della UART START DATA PARITY STOP 1 bit 5-9 bit 0-1 bit 1-2 bit • STOP bit il bit di stop segnala la fine del pacchetto trasmesso lo stop viene indicato mandando la linea di trasmissione a 1 per 1 o 2 periodi di baud durante una trasmissione dunque vi è sempre un passaggio da 0 a 1 garantito dalla presenza dei bit di start e di stop
TRANSMITTED DATA 1 0 1 1 0 0 1 0 LSB MSB SRC UART tx START DATA[0] DATA[1] DATA[2] DATA[3] DATA[4] DATA[5] DATA[6] DATA[7] PARITY 0 0 1 0 0 1 1 0 1 0 1 STOP rx DST UART Funzionamento della UART LSB MSB 1 0 1 1 0 0 1 0 RECEIVED DATA
Vantaggi e Svantaggi della UART • Vantaggi • sono necessarie solamente due connessioni (tx e rx) • non è necessario un segnale di clock • è possibile rilevare degli errori con il bit di parità • la struttura del pacchetto dati può essere modificata • Svantaggi • la grandezza massima dei dati trasmessi è di 9 bit • non è possibile avere UART con master e/o slave multipli • i baud rate degli interlocutori possono differire massimo per un 10% dal valore nominale
UART negli AVR • L’AVR ATmega328p integra un dispositivo USART con modalità di funzionamento asincrona o sincrona generatore di baud rate ad alta risoluzione supporto per campo dati a 5, 6, 7, 8 o 9 bit e per 1 o 2 bit di stop generazione e verifica di parità interrupt per tx completata, registro tx vuoto e rx completata due velocità in modalità asincrona
UART negli AVR XCKn TxDn RxDn parity parity generator check baud rate generator Tx shift register Tx shift register oscillator UBRRnL/H UDRn Tx UDRn UDRn Rx UCSRnA UCSRnB UCSRnC USART n TOVn IRQ data bus
UART negli AVR • Modalità di funzionamento del dispositivo USART nei microcontrollori AVR a seconda della modalità di funzionamento dell’USART e della frequenza operativa del microcontrollore, occorre settare un diverso valore di UBRRn per avere un certo Baud Rate (BAUD) operating mode baud rate calculation UBRRn calculation asynchronous normal BAUD=fclk/(16*UBRRn+1) UBRRn=fclk/(16*BAUD) - 1 (U2Xn=0) asynchronous double speed BAUD=fclk/(8*UBRRn+1) UBRRn=fclk/(8*BAUD) - 1 (U2Xn=1) synchronous master BAUD=fclk/(8*UBRRn+1) UBRRn=fclk/(8*BAUD) - 1
Baud Rate nell’ATmega328p fclk = 16 MHz Baud Rate (bps) U2Xn=0 U2Xn=1 UBRRn error UBRRn error 2400 416 -0.1% 832 0.0% 4800 207 0.2% 416 -0.1% 9600 103 0.2% 207 0.2% 14.4k 68 0.6% 138 -0.1% 19.2k 51 0.2% 103 0.2% 28.8k 34 -0.8% 68 0.6% 38.4k 25 0.2% 51 0.2% 57.6k 16 2.1% 34 -0.8% 76.8k 12 0.2% 25 0.2% 115.2k 8 -3.5% 16 2.1% 230.4k 3 8.5% 8 -3.5% 250k 3 0.0% 7 0.0% 0.5M 0 0.0% 3 0.0% 1M 0 0.0% 1 0.0%
UART negli AVR RXB TXB 7 6 5 4 3 2 1 0 • USART I/O Data Register (UDRn) tramite lo stesso indirizzo mappato in memoria, è possibile accedere al Receive data Buffer (RXB) o al Transmit data Buffer (TXB) a seconda del fatto che si acceda rispettivamente in lettura o in scrittura RXB e TXB contengono il dato ricevuto e il dato da inviare nella comunicazione seriale
UART negli AVR RXCn TXCn UDREn FEn DORn UPEn U2Xn MPCMn 7 6 5 4 3 2 1 0 • USART Control and Status Register A (UCSRnA) USART Receive Complete (RXCn): settato quando ci sono dati non letti nel registro RXB USART Transmit Complete (TXCn): settato quando un dato è stato inviato completamente e non ci sono altri dati da trasmettere USART Data Register Empty (UDREn): indica se il registro TXB è vuoto e quindi pronto a ricevere altri dati
UART negli AVR RXCn TXCn UDREn FEn DORn UPEn U2Xn MPCMn 7 6 5 4 3 2 1 0 • USART Control and Status Register A (UCSRnA) USART Frame Error (FEn): settato quando il dato ricevuto nel registro RXB contiene degli errori di stop bit USART Data OverRun (DORn): settato quando è stato ricevuto un dato (RXB pieno e non letto) e un nuovo dato da ricevere è pronto sullo shifter register USART Parity Error (UPEn): settato quando il dato ricevuto nel registro RXB contiene degli errori di parità
UART negli AVR RXCn TXCn UDREn FEn DORn UPEn U2Xn MPCMn 7 6 5 4 3 2 1 0 • USART Control and Status Register A (UCSRnA) Double the USART Transmission Speed (UX2n): ha effetto solo in modalità asincrona e, se settato, raddoppia la velocità di trasmissione Multi-Processor Communication Mode (MPCMn): abilita la modalità multi-processore (possibilità di ricezione da sorgenti multiple mediante indirizzamento)
UART negli AVR RXCIEn TXCIEn UDRIEn RXENn TXENn UCSZn2 RXB8n TXB8n 7 6 5 4 3 2 1 0 • USART Control and Status Register B (UCSRnB) RX Complete Interrupt Enable (RXCIEn): maschera di abilitazione dell’interrupt RX Complete TX Complete Interrupt Enable (TXCIEn): maschera di abilitazione dell’interrupt TX Complete USART Data Register Empty Interrupt Enable (UDRIEn): maschera di abilitazione dell’interrupt UDRE
UART negli AVR RXCIEn TXCIEn UDRIEn RXENn TXENn UCSZn2 RXB8n TXB8n 7 6 5 4 3 2 1 0 • USART Control and Status Register B (UCSRnB) Receive Enable (RXENn): abilita il ricevitore USART Transmit Enable (TXENn): abilita il trasmettitore USART Character Size (UCSZn2): indica il numero di bit DATA Receive Data Bit 8 (RXB8n): nono bit del dato ricevut Transmit Data Bit 8 (TXB8n): nono bit del dato trasmesso
UART negli AVR UMSELn1 UMSELn2 UPMn1 UPMn2 USBSn UCSZn1 UCSZn0 UCPOLn 7 6 5 4 3 2 1 0 • USART Control and Status Register C (UCSRnC) i bit UMSEL1:0 selezionano la modalità di funzionamento del dispositivo USART UMSELn1 UMSELn0 operation mode 0 0 asynchronous USART 0 1 synchronous USART 1 0 reserved 1 1 master SPI
UART negli AVR UMSELn1 UMSELn2 UPMn1 UPMn2 USBSn UCSZn1 UCSZn0 UCPOLn 7 6 5 4 3 2 1 0 • USART Control and Status Register C (UCSRnC) i bit UPM1:0 selezionano la modalità di generazione/valutazione del bit di parità UMSELn1 UMSELn0 parity generation/validation mode 0 0 disabled 0 1 reserved 1 0 enabled, even parity 1 1 enabled, odd parity
UART negli AVR UMSELn1 UMSELn2 UPMn1 UPMn2 USBSn UCSZn1 UCSZn0 UCPOLn 7 6 5 4 3 2 1 0 • USART Control and Status Register C (UCSRnC) Stop Bit Select (USBSn): determina il numero di bit di stop. Se a 0 vi sarà 1 bit di stop, se a 1 ve ne saranno 2 Clock POLarity (UCPOLn): determina la polarità del clock (quando cambia il dato rispetto al periodo di clock) nella modalità sincrona. Se a 0 il dato trasmesso cambia nei fronti positivi e quello ricevuto va campionato in quelli negativi, se a 1 viceversa
UART negli AVR UMSELn1 UMSELn2 UPMn1 UPMn2 USBSn UCSZn1 UCSZn0 UCPOLn 7 6 5 4 3 2 1 0 • USART Control and Status Register C (UCSRnC) i bit UCSZn2:0 selezionano il numero di bit dei dati UCSZn2 UCSZn1 UCSZn0 descrizione 0 0 0 5-bit 0 0 1 6-bit 0 1 0 7-bit 0 1 1 8-bit 1 0 0 reserved 1 0 1 reserved 1 1 0 reserved 1 1 1 9-bit
Esempio: Inizializzazione UART #include int freq = 16000000; // calc ubrr value int baud = 9600; int ubrr = freq/(16*baud) – 1; UBRR0H = (ubrr >> 8); // set baud rate UBRR0L = (ubrr); // enable rx and tx UCSR0B = (1
Esempio: Trasmissione/Ricezione UART #include // wait till tx buffer is empty while( !(UCSR0A & (1
Puoi anche leggere