domenica 30 giugno 2013

Condensatori e variazioni di capacità indesiderata

Vi parlerò oggi di un aspetto poco pubblicizzato dei condensatori ceramici MLCC.

Con l’avanzare della tecnologia si sono prodotti condensatori sempre più piccoli e di capacità sempre maggiore. In particolare i moderni condensatori ceramici multistrato (MLCC) sembrano sostituire in diversi casi i più ingombranti e costosi condensatori elettrolitici.

Purtroppo non tutto è oro ciò che luccica.

Al diminuire delle dimensioni ed all’aumentare della tensione di polarizzazione (DC bias) si assiste in genere ad un calo della permettività elettrica che porta ad una diminuzione di capacità anche molto consistente e non trascurabile.

I condensatori di classe 2, con maggiore capacità per volume ma minor stabilità, sono particolarmente soggetti a questa problematica.

Un’immagine vale più di mille parole, ecco un grafico di condensatori con diverso coefficiente di temperatura, riportano una variazione di capacità rispetto alla tensione di polarizzazione molto diversa fra loro.

graph

Riportiamo per esempio alcuni dati tratti dal datasheet del condensatore UMK325BJ106KM-T. Possiamo trovare oltre alla tolleranza di fabbricazione di +-10% ben tre grafici relativi alla variazione di capacità: rispetto alla temperatura, alla tensione, ed alla frequenza.

umk

C’è quindi da prestare molta attenzione nella scelta laddove il condensatore assume un ruolo fondamentale, le variabili in gioco non sono poche.

Tecnicamente però il coefficiente di temperatura indica solamente la variazione di capacità rispetto alla temperatura e non è legato alla variazione di capacità rispetto alla tensione.

La cosa migliore per scegliere i propri condensatori rimane la consultazione dei datasheet o ancora meglio l’utilizzo di appositi programmi forniti dai produttori come SEAT (Selection Assistant of TDK components), SimSurfing di Murata, etc..

Generiamo col programma SEAT i grafici della variazione di capacità rispetto alla tensione di due condensatori MLCC particolarmente piccoli (0805) ma con capacità nominale di 10uF, valuteremo se potranno sostituire dei ben più costosi elettrolitici.

tdk

Il grafico riportato dal programma è particolarmente agghiacciante, nel modello con coefficiente di temperatura Y5V la situazione è critica a tensioni anche molto basse.

Un utilizzo a metà della tensione massima, che potrebbe sembrare ragionevole, comporta un calo di oltre il 90% della capacità. Nel modello X5R la situazione è leggermente migliore ma comunque non rosea.

Un utilizzo non consapevole dei componenti difficilmente darà i risultati sperati.

Il grafico di esempio presenta due componenti molto economici che difficilmente potranno sostituire degli elettrolitici di pari capacità nominale a tensioni superiori ad 1-2V.

Concludendo, in generale all’aumentare delle dimensioni fisiche del condensatore la situazione della tensione di polarizzazione migliora, c’è quindi da prestare molta attenzione quando prezzi accattivanti, dimensioni estremamente ridotte e capacità elevate si presentano assieme.

Da parte dei produttori la ricerca è molto attiva per risolvere questo problema, recentemente sono nate soluzioni basate su tecnologia ceramica BaTiO3 per cerca di minimizzare questo effetto indesiderato.

giovedì 27 giugno 2013

Introduzione ad ASF (quarta parte)

Indice degli articoli su ASF

Atmel Studio tramite il menù ASF ci offre lo strumento ASF Explorer che permette di visualizzare i moduli ASF presenti nel nostro progetto ed un collegamento diretto alla documentazione ed ai file header di ogni modulo aggiunto. Vengono mostrati anche i moduli dipendenti dal principale come sotto-voci.

asfexplorer

E’ proprio la documentazione a mettere spesso in difficoltà i programmatori che si avvicinano ad ASF per la prima volta, il codice sorgente rappresenta infatti un complemento indispensabile per il programmatore per compensare descrizioni certe volte minimali e non sufficienti per l’utilizzo corretto.

Facciamo adesso un esempio concreto di utilizzo della guida e del codice sorgente, apriamo la documentazione del modulo Delay routines facendo doppio click su API Documentation, si aprirà la pagina http://asf.atmel.com/docs/3.5.1/xmegaau/html/group__group__common__services__delay.html che riportiamo sotto per comodità:

doc

Notiamo che è presente una descrizione del modulo ed il contenuto che in questo caso è una serie di funzioni con il prototipo ed una breve descrizione. Cliccando sulle varie funzioni è possibile leggere qualche informazione aggiuntiva, ad esempio la pagina della funzione delay_init è sotto riportata:

delayinit

Che ci informa per esempio che il metodo è deprecato come abbiamo visto nell’articolo precedente. In questo caso, vista anche la semplicità e intuitività delle funzioni non sono presenti esempi di utilizzo. Per altri moduli è presente oltre alla voce API Documentation una utile voce Quick Start Guide con esempi ben descritti da cui consiglio sempre di partire.

Nell’immagine precedente possiamo notare nell’intestazione a piè pagina che la pagina è stata generata automaticamente tramite doxygen, in poche parole la documentazione è all’interno del codice sorgente, proprio tra il codice, ed un programma automatizzato ha provveduto a generare le pagine web di documentazione.

Così come sono state presentate le funzioni potremmo credere di poter utilizzare all’interno del nostro codice l’istruzione

delay_us(1)

Senza particolari problemi, compilando e caricando il programma utilizzante questa istruzione scopriamo amaramente che a tale istruzione il programma si blocca.


E’ normale in questa situazione avere dell’amaro in bocca, anche perché si potrebbe scoprire che non funziona con un clock di default di 2 MHz ma funziona con un clock impostato a 32 MHz. Si rimane addirittura confusi.


In situazioni del genere se una breve ricerca su internet non porta a risultati interessanti che ci possono aiutare e la documentazione non accenna a problemi del genere, non specifica infatti in questo caso dei limiti temporali a cui restringere l’utilizzo della funzione, la strada da seguire è lo studio del codice sorgente della funzione.


Lo studio del sorgente richiederà uno sforzo in più, non sempre è facile leggere codice scritto da altri, non preoccupatevi quindi se non capite completamente quanto descritto di seguito, anche se è segno che avete una confidenza col linguaggio C che probabilmente necessita di una risploverata.


Apriamo dunque il file delay.h (sotto riportato senza commenti per brevità):


delayh


Notiamo che in realtà esistono dietro le quinte due funzioni: cpu_delay_ms ed cpu_delay_us, la funzione in secondi non fa altro che convertire in millisecondi il ritardo e chiamare la relativa funzione. La definizione F_CPU grazie ad una funzione di un altro modulo da cui questo dipende, come visto nello scorso articolo, recupera la frequenza della CPU.


A questo punto per seguire la funzione facciamo click destro sul nome della funzione e scegliamo Goto implementation, possiamo in alternativa premere la combinazione Alt+G


goto


Verrà aperto il file cycle_counter.h che riportiamo:


cycle_counter


Notiamo dalle ultime due righe che in realtà le due funzioni sono dei #define che chiamano una ulteriore definizione chiamata delay_cycles che intuitivamente ritarderà di un certo numero di cicli l’esecuzione del programma. Il numero di cicli dipenderà dalla frequenza del microcontrollore. Il parametro passato a delay_cycles è quindi la conversione da us (nel caso in esame da cui siamo partiti, la funzione delay_us) a cicli da ritardare. Notiamo che questa conversione avviene tramite la definizione cpu_us_2_cy .


L’utilizzo di definizioni (#define) al posto di normali funzioni avviene per motivi prestazionali ed è pratica usuale nella libreria ASF, a complicare la lettura spesso il fatto che alcune definizioni dipendono da altre definizioni. In questo caso alcune definizioni dipendono dalla presenza della definizione __DELAY_CYCLE_INTRINSICS__ che non è definita. Il codice da considerare è quindi solamente quello dentro ai rettangoli rossi.


Analizziamo ora cpu_us_2_cy definita sopra nel rettangolo rosso nel mezzo, e poniamo attenzione al fatto che coi nostri parametri vengono eseguiti alcuni calcoli che possiamo credere corretti anche senza approfondire la loro natura.


Analiticamente: numero_cicli = ((microsecondi * frequenza_cpu) + 999.999) / 6.000.000


Il risultato verrà passato alla funzione delay_cycles che altro non è che la funzione __portable_avr_delay_cycles nel rettangolo rosso sopra. La funzione accetta in ingresso un numero N senza segno intero che viene decrementato prima dell’utilizzo.


A questo punto si iniziano ad intravedere le situazioni limite, il parametro N non dovrà mai essere minore di 1, se fosse zero il decremento lo porterebbe a 4294967295 visto che il numero non può essere negativo, è infatti unsigned long, e quindi il ritardo diventerebbe molto grosso, il massimo permesso per la precisione ed il programma sembrerebbe a prima vista bloccato.


Qual’è la condizione per cui il numero dei cicli è sempre maggiore di zero? Per rispondere a questa domanda risolviamo rispetto l’espressione analitica che abbiamo visto sopra imponendola >= 1 supponendo che nell’incertezza di come venga arrotondata la divisione sia sempre meglio raggiungere almeno il primo numero intero, troviamo:


((microsecondi * frequenza_cpu) + 999.999) / 6.000.000 >= 1


microsecondi * frequenza_cpu >= 6.000.000 - 999.999


Il prodotto del ritardo in microsecondi per la frequenza in Hertz del microcontrollore deve quindi essere maggiore o uguale a 5.000.0001


Con una frequenza di 2 MHz ed un ritardo di 1 us avremmo: 1 * 2.000.000 < 5.000.0001 che non soddisfa la relazione trovata. La soluzione può essere quindi aumentare il ritardo o la frequenza del microcontrollore, con 32 MHz il ritardo funzionerà correttamente.


Abbiamo quindi trovato un’importante relazione che limita il ritardo minimo che possiamo apportare in base alla frequenza, purtroppo di questa relazione non c’è traccia nella documentazione ed il codice della funzione ASF non gestisce il caso in cui il ritardo sia così piccolo da generare un problema, il codice di ASF però ci permette di capire in profondità il funzionamento della libreria e risolvere eventuali problemi come abbiamo visto.


Concludo l’articolo riportando l’analoga relazione per la funzione delay_ms() deducibile nello stesso modo che abbiamo visto per la funzione delay_us():


millisecondi * frequenza_cpu >= 5001


E ricordando che le funzioni di ritardo ammetteranno sicuramente un limite superiore legato al tipo di dati utilizzato.

mercoledì 26 giugno 2013

Introduzione ad ASF (terza parte)

Indice degli articoli su ASF
Vediamo in questo articolo come aggiungere al nostro programma HelloASF nuovi moduli ASF, aggiungeremo per la precisione il servizio Delay routines che ci fornirà nuovi metodi per inserire dei brevi ritardi temporali nel nostro codice.
Apriamo il nostro progetto HelloASF creato negli articoli precedenti e scegliamo dal menù ASF la voce ASF Wizard
menu
Apparirà una schermata da cui potremmo scegliere i moduli da aggiungere al nostro progetto, selezioniamo la voce Delay routines (service) dall’elenco di sinistra e premiamo il pulsante Add,il modulo apparirà anche nell’elenco di destra.
asfwizard
Possiamo aggiungere in un colpo solo anche più moduli ma per il momento ci basterà il modulo che abbiamo scelto, premiamo il pulsante Apply, una finestra riepilogativa ci informerà delle operazioni che verranno compiute.
summary
E’ possibile notare che oltre al servizio scelto verranno aggiunti altri servizi, questo perché Delay routines dipende da altri servizi e driver che dovranno essere inclusi per il corretto funzionamento.
Facciamo click su OK e aspettiamo che Atmel Studio compia le operazioni indicate
tree
Tramite il Solution Explorer possiamo notare che sono state aggiunte al progetto diverse nuove cartelle e file. L’aggiunta di un modulo è proprio la copia di questi file.
In particolare è stato aggiunto anche il servizio System Clock Control che è fondamentale e ci permetterà di cambiare il clock del nostro microcontrollore che all’avvio è sempre di 2 MHz da un’oscillatore RC interno.
Rispetto ai micro ATTiny ed ATMega si ha un grande cambiamento, il clock non viene più impostato tramite i fuse ma a runtime. Questo può evitare condizioni particolarmente spiacevoli come l’inutilizzabilità di un micro saldato su una scheda senza oscillatore se per sbaglio si è impostato il rispettivo fuse per il clock da cristallo esterno. Permette di cambiare inoltre in modo dinamico al frequenza operativa per ottenere il massimo risparmio energetico o la massima velocità a seconda delle necessità
Il servizio Delay routines necessita del servizio System Clock Control per sapere la frequenza attuale del microcontrollore, a sua volta il servizio sysclk (abbreviazione per System Clock Control da ora in poi) ricava questa informazione dal file di configurazione conf_clock.h che dovrà essere impostato correttamente dal programmatore oltre ad offrire utili funzioni per la gestione del clock.
Iniziamo ad intravedere una stessa struttura logica coerente, i moduli spesso richiedono dei parametri tramite un file conf_X.h (dove X è il nome del modulo) nella cartella config mentre i file sorgenti dei moduli sono inseriti nelle cartelle common ed xmega in base alla loro tipologia (servizi o driver).
E’ da notare che non avviene nessun “collegamento” a librerie esterne ma i sorgenti vengono copiati nel progetto, sia i file di intestazione (.h) sia i file di codice (.c). Questo fatto comporta vantaggi ma anche svantaggi, non è consigliato apportare modifiche ai file di codice sorgente perché eventuali aggiornamenti a nuove versioni di ASF sovrascriveranno i file e le nostre modifiche andranno perse e riapplicate manualmente.
Modifichiamo ora il nostro programma nel seguente modo:
code
Abbiamo inserito la chiamata alla funzione sysclk_init() che in base al file conf_clock.h imposterà il clock di sistema. Come il modulo IOPORT e BOARD ritroviamo dunque che la prima cosa in genere da fare è chiamare la funzione _init. Per il momento non apportiamo nessuna modifica al file conf_clock.h, diamo però una rapida occhiata alla prima parte di questo file:
conf_clock
Notiamo che è composto esclusivamente da #define e le righe commentate forniscono una sorta di documentazione che può evitarci l’apertura della guida, per cambiare il clock di sistema dai 2 MHz di default ai 32 MHz sarà sufficiente commentare la prima riga e togliere il commento dalla seconda.
Vedremo maggiori dettagli sul servizio sysclk in un successivo articolo, per il momento ci basta sapere che non “toccando” nulla avremo un clock di 2 MHz.
Torniamo adesso al nostro codice, riportato sotto per comodità di lettura:
code
Il servizio Delay routines ha la funzione delay_init() deprecata, questo significa che non è consigliato chiamarla ed è presente solamente per compatibilità. Non è infatti più necessaria per il funzionamento del servizio nelle nuove versioni di ASF. Nel codice è presente commentata proprio per ricordare questo fatto.
Nel ciclo infinito while sono presenti nuove istruzioni che faranno lampeggiare il primo led (quello rosso), abbiamo già incontrato l’istruzione ioport_set_pin_level che imposta il livello logico di un pin, sotto notiamo l’istruzione delay_s il cui scopo è fermare l’esecuzione per i secondi indicati come parametro. Avremo quindi un ciclo ON/OFF di due secondi che ci permetterà di osservare il lampeggio del led.
Il segnale che controllerà il led visto dall’oscilloscopio sarà un’onda quadra
oscilloscope
Il servizio Delay routines ci offre anche altri due metodi per generare ritardi più brevi, delay_ms() per ritardi in millisecondi e delay_us() se necessitiamo di brevissimi ritardi in microsecondi.

martedì 25 giugno 2013

Programmare gli XMega tramite USB con Atmel FLIP ed Atmel Studio

Vediamo in questo articolo come programmare il nostro microcontrollore tramite il programma Atmel FLIP.

atmelusb

La nostra scheda di sviluppo EWS ATXMega32A4U contiene un bootloader compatibile con il protocollo FLIP USB DFU (descritto dall’Application Note AVR4023) che permette la programmazione tramite interfaccia USB senza la necessità di programmatori aggiuntivi.

Una nota per gli appassionati della piattaforma Arduino: anche su Arduino Uno e Mega2560 è presente il bootloader USB sul chip Atmega8U2 che è possibile aggiornare con FLIP (http://arduino.cc/en/Hacking/DFUProgramming8U2).

Prima di tutto installiamo il programma Atmel FLIP e colleghiamo la nostra scheda di sviluppo tramite USB. Tenendo premuto il pulsante SW2 (PC3) premiamo adesso il pulsante SW1 (RST) per effettuare il reset. Rilasciamo prima il pulsante di reset e dopo qualche istante il pulsante SW2.

Se abbiamo un micro XMega non appartenente alla serie A4U o C4 possiamo utilizzare di default altri pin secondo la seguente tabella tratta dall’Application Note AVR1916 che spiega nel dettaglio tutta la procedura:

table

Alternativamente è possibile ricompilare e ricaricare il bootloader tramite un programmatore per impostare un pin a piacimento scaricando i sorgenti del bootloader da http://www.atmel.com/Images/AVR1916.zip

All’avvio il bootloader controllerà (nel nostro caso con un ATXMega32A4U) se il pin PC3 è collegato a massa, quindi se il pulsante SW2 è premuto e in tal caso avvierà l’esecuzione del DFU (Device Firmware Upgrade) ed inizierà l’enumerazione USB del dispositivo che permetterà la programmazione da pc.

Aprendo Atmel Flip possiamo scegliere il nostro Device dal menù Device / Select dopodiché possiamo aprire la comunicazione USB tramite il menù Settings / Communication / USB e scegliendo il pulsante Open dalla finestra di dialogo che ci verrà presentata.

open

Per velocizzare le operazioni in alternativa è possibile utilizzare i primi due pulsanti grafici.

flip

Siamo adesso pronti a caricare il nostro programma che possiamo compilare tramite il menù Build/Build Solution di Atmel Studio una volta aperto il progetto. Scegliamo adesso in Atmel FLIP la voce File / Load HEX file.. ed indichiamo il file con estensione .hex appena generato, in genere è presente nella cartella col nome della configurazione scelta (Debug o Release) come ad esempio HelloASF\HelloASF\Debug\HelloASF.hex per il progetto HelloASF.

Verifichiamo che nel gruppo Operations Flow siano marcate tutte le spunte per una programmazione completa e facciamo click su Run, se tutto è andato a buon fine i pallini diventeranno tutti verdi e cliccando su Start Application (con la spunta Reset abilitata) il nostro codice inizierà a prendere vita.

Programmiamo il dispositivo direttamente da Atmel Studio

La guida in linea di Flip presenta qualche problema di compatibilità con Chrome ed è consigliato l’utilizzo di Internet Explorer, al suo interno sono presenti tutti i dettagli relativi al programma Flip, a BatchIsp, una utility a linea di comando in grado di svolgere tutte le operazioni di FLIP ed alla Atmel's ISP functions library, una serie di DLL per chi volesse scrivere un proprio programma per la programmazione ISP, sia Flip sia BatchIsp utilizzano questa libreria per il loro funzionamento.

Alle successive programmazioni Flip si ricorderà del device impostato ma sarà necessario ogni volta indicare il file da caricare, aprire la connessione USB, premere Run e Start Application, un procedimento non molto agile soprattutto in quelle occasioni in cui è necessario compilare e caricare molte volte il firmware per la verifica della correttezza del programma.

Utilizzando BatchISP è possibile rendere più agile la programmazione dei nostri dispositivi senza neppure uscire da Atmel Studio creando un apposito menù e pulsante. Purtroppo nativamente Atmel Studio non supporta ancora la programmazione tramite USB ma vediamo come rimediare.

Apriamo Atmel Studio, scegliamo Tools / External Tools ed inseriamo le seguenti informazioni:

Title: Upload with Atmel &FLIP
Command: C:\Program Files\Atmel\Flip 3.4.7\bin\batchisp.exe
Arguments: -device atxmega32a4u -hardware usb -operation erase f memory FLASH blankcheck loadbuffer "$(TargetPath)" program verify start reset 0

ext

Dove il percorso del programma BatchIsp ed il modello di microcontrollore dovrà corrispondere a quello utilizzato

Seguendo la guida è possibile modificare i parametri passati al programma per evitare ad esempio l’avvio automatico del firmware dopo l’upload o la sua verifica se non desiderata.

E’ possibile adesso aggiungere il pulsante del comando Upload with Atmel FLIP appena creato scegliendo External Command 1 nella finestra di dialogo Add Command presente in Tools/Customize/Commands e scegliendo la toolbar Device and Debugger

addcmd

Il risultato sarà molto più pratico, un comando accessibile sia da menù che da barra degli strumenti che in un click effettuerà la cancellazione della memoria Flash, l’upload del firmware ed il successivo reset sulla nostra scheda di sviluppo.

vs

Ad upload terminato tramite la finestra Output sarà possibile verificare il corretto svolgimento delle operazioni

output

Buona programmazione.. in un colpo di click

domenica 23 giugno 2013

Introduzione ad ASF (seconda parte)

Dopo aver visto una panoramica dei file creati dal template apriamo il file main.c

main

La funzione main come consueto sarà il punto d’ingresso per il nostro programma, notiamo le prime due istruzioni con suffisso _init, avremo spesso a che fare con funzioni di inizializzazione che spesso andranno semplicemente chiamate come in questo caso, diciamo che è una convenzione dei moduli ASF.

La prima istruzione ioport_init() inizializza il servizio IOPORT e va necessariamente chiamata prima di utilizzare qualsiasi altra funzione di questo servizio che permette di gestire i pin GPIO (General Purpose Input/Output)

La seconda funzione board_init() in realtà chiama una nostra funzione, nel senso non appartenente dal principio ad ASF ma scritta durante la stesura del template.

Una domanda che è lecito chiedersi è come fa il compilatore a sapere dove sono le due funzioni che abbiamo visto, il trucco è presto svelato, nell’header asf.h sono presenti le inclusioni ai file header (es. ioport.h, board.h) che contengono le definizioni delle funzioni ed il compilatore è già normalmente impostato per includere i percorsi che gli serviranno per recuperare tali file.

compiler

La funzione board_init() è all’interno del file asf\common\boards\user_board\init.c presente nel nostro progetto, qui sotto riportato

init

La funzione utilizza a sua volta due funzioni del servizio IOPORT che quindi è stato necessario chiamare prima di board_init.

Il codice è molto semplice, il suo funzionamento si basa su due funzioni del modulo IOPORT, il codice di ASF è sostanzialmente C quindi non ci sono classi complesse da istanziare e risulta di semplice comprensione:

ioport_set_pin_dir: imposta la direzione per una singolo pin specificato dal primo parametro che potrà quindi essere un pin di ingresso (IOPORT_DIR_INPUT) o di uscita (IOPORT_DIR_OUTPUT) in base a quanto specificato nel secondo parametro

ioport_set_pin_mode: imposta la modalità per un singolo pin specificato dal primo parametro, in questo caso le modalità specificate nel secondo parametro posso essere molteplici

ioportmode

Il codice imposta i pin relativi ai 3 led presenti sulla scheda come uscite ed il pulsante come ingresso con modalità pull-up, ovvero il pin sarà collegato tramite una resistenza interna al micro alla linea di alimentazione VCC ed alla pressione del pulsante si instaurerà un collegamento verso GND ma non un cortocircuito grazie proprio alla resistenza di pull-up di diverse decine di kilo-ohm che limiterà la corrente e leggeremo uno stato logico basso. Quando il pulsante non sarà premuto l’ingresso non rimarrà volante (floating) e quindi soggetto a disturbi ma avrà una connessione a VCC e leggeremo quindi uno stato logico alto. La logica sarà quindi invertita, ricapitolando: pulsante premuto –> ingresso basso, pulsante non premuto –> ingresso alto. Il punto è proprio quello di prevenire i disturbi che generano false pressioni dovute all’ingresso floating (o detto anche in alta impedenza).

Nel codice è possibile notare come i pin sono specificati tramite dei nomi facilmente comprensibili (es. LED0_GPIO, GPIO_PUSH_BUTTON_0), questi “nomi” sono definiti nel file user_board.h:

user_board

Come è possibile vedere le definizioni avvengono tramite una funzione IOPORT_CREATE_PIN che in realtà non è una vera e propria funzione ma una funzione MACRO che viene sostituita nel codice dal preprocessore per ottenere la massima velocità.

ioportcreate

La funzione macro converte la porta prima in un nome es. IOPORT_PORTB che ha una definizione che l’associa ad un numero (in questo caso 1 come è possibile notare dal codice sopra) che viene poi moltiplicato per 8 e viene sommato al numero del pin.

In sostanza la funzione converte ogni pin in un numero univoco che sarà utilizzato per identificare il pin senza possibilità di errori ed utilizzato dalle altre funzioni del servizio IOPORT.

Nel file sono presenti alcune definizioni legati all’oscillatore presente sulla scheda, nel nostro caso un cristallo da 12 MHz, queste informazioni saranno utilizzate col modulo System Clock Control che vedremo prossimamente.

Tornando adesso al nostro file main.c (riportato sotto per semplicità di lettura) dopo aver dilagato sugli internals delle prime due istruzioni e aver visto qualcosa sotto al cofano

main

Notiamo che dopo l’inizializzazione viene utilizzata una nuova funzione del servizio IOPORT che non abbiamo ancora visto:

ioport_set_pin_level: imposta un pin specificato dal primo parametro al livello logico specificato dal secondo parametro. Il livello può essere IOPORT_PIN_LEVEL_HIGH oppure IOPORT_PIN_LEVEL_LOW, il tipo del secondo parametro è un bool quindi potremmo passare equivalentemente anche true oppure false ma a mio parere l’utilizzo dell’enumerativo (es. IOPORT_PIN_LEVEL_HIGH) rende il codice di intenti più chiari.

Vengono quindi accesi tutti e tre i led della nostra scheda dopodiché notiamo un while(true) che è semplicemente un ciclo infinito dove dovremmo inserire il nostro codice che sarà ripetuto fino ad un reset o allo spegnimento del micro.

venerdì 21 giugno 2013

Introduzione ad ASF (Atmel Software Framework)

Scopriamo in una serie di articoli il framework di Atmel per la programmazione dei microcontrollori

asf_structure

ASF è un framework organizzato in strati a livelli di astrazione diversi, facciamone una panoramica:

Boards rappresenta i dettagli della scheda fisica es. pin, led, pulsanti, etc..

Drivers offrono funzionalità di basso livello per interfacciarsi con le periferiche, esempi di Drivers sono ADC, DAC, DMA, SPI, TC (Timer Counter), IOPORT etc.. non hanno nulla a che fare coi Driver di Windows, nonostante il nome sono in genere semplici da usare, sono normali funzioni C

Components come HX8347A Display Controller Low Level driver offrono funzionalità per componenti esterni come display LCD, sensori, etc..

Services come SPI, PWM, FIFO, FatFS, etc.. che spesso offrono funzionalità a più alto livello dei Drivers. Ad esempio il driver SPI offre funzionalità come spi_get ed spi_put per leggere o scrivere un byte sull’interfaccia mentre il servizio SPI offre funzionalità come spi_write_packet che permettono di scrivere pacchetti (sequenze di byte). Un altro esempio è il servizio

Applications sono semplicemente gli esempi da cui è possibile partire scegliendo New Example Project dalla schermata iniziale

Utilities sono funzioni utilizzate trasversalmente da tutti gli strati

Your Code sarà il codice che scriveremo noi

A mio parere personale ASF è più propriamente una libreria piuttosto che un framework in quanto il nostro codice chiama la libreria al posto di essere chiamato dal framework. Ma diciamo che è una sottile distinzione e visto che la sigla contiene la parola framework lo utilizzerò intercambiabilmente con entrambi i termini.

atxmega32a4u_breakout_board-500x500Utilizzeremo nel nostro viaggio la scheda EWS ATXmega32A4U Breakout Board (link produttore, schema) che sostanzialmente espone con semplicità tutti i pin del micro ATXMEGA32A4U ed è precaricata col bootloader Atmel Flip che permette di caricare i nostri programmi tramite USB senza l’acquisto di un programmatore aggiuntivo.

Gli XMega sono una “via di mezzo” tra i micro ad 8 bit e i micro a 32 bit e permetteranno di esplorare parecchi moduli della libreria ASF che non sarebbero utilizzabili con degli ATTiny o ATMega.

Per semplificare l’utilizzo della scheda ho creato un template per creare rapidamente nuovi progetti: scarica il template

Per installare il template una volta aperto Atmel Studio andare su File/Import/Project Template e selezionare il file .zip scaricato

0.importtemplate

Al riavvio di Atmel Studio scegliendo New Project sarà disponibile un nuovo tipo di progetto EWS ATXMEGA32A4U

1newproject

Diamo il nome HelloASF al progetto e scegliamo OK, verrà creata una serie di file che serviranno come infrastruttura per il nostro firmware e l’utilizzo della framework ASF.

Iniziamo con l’analizzare la struttura di file creata col Solution Explorer che troviamo di default sulla barra di destra, dentro la cartella src è presente:

solexpl- cartella asf
relativa ad ASF, contiene a sua volta diverse cartelle

     - cartella common
contiene dei file interessanti nella cartella boards (illustrati sotto), la cartella services relativa ai vari moduli che si aggiungeranno e sarà popolata automaticamente, la cartella utils relativa a file che in genere non vanno modificati e sono di supporto alla programmazione

     - cartella xmega
codice di supporto per i micro XMega, è possibile ignorarla in quanto difficilmente da modificare

- cartella config
è la cartella dove verranno inseriti tutti i file di configurazione per i moduli ASF scelti, ad esempio il servizio System Clock Control aggiungerà il file conf_clock.h che permetterà di impostare la frequenza del clock da utilizzare.

- asf.h  
file automaticamente generato, include tutti gli header necessari per utilizzare i moduli ASF selezionati, non va modificato manualmente

- main.c  
il file iniziale del nostro firmware, contiene la funzione main e un’include alla libreria asf

 

Vediamo adesso alcuni file particolarmente interessanti che consiglio di leggere mentre i rimanenti file delle cartelle services, utils e xmega possono essere ignorati e visti come file di supporto.

asf/common/boards/user_board/init.c contiene una funzione per inizializzare la scheda, vengono impostati i pin dei led come uscite e dei pulsanti come ingressi

asf/common/boards/user_board/user_board.h
contiene #define che danno ai pin dei led e dei pulsanti nomi mnemonici, contiene impostazioni sull’oscillatore presente sulla scheda

asf/common/boards/board.h
sostanzialmente il file non è da modificare, contiene degli include condizionali in base a dei #define definiti nelle opzioni del compilatore

config/conf_board.h
aggiunge se non presente #define CONF_BOARD_H che però non è utilizzato, è il posto dove inserire dei propri #define per personalizzare la configurazione della scheda

Per il momento è tutto, lascio un utile link: http://asf.atmel.com che contiene la documentazione ufficiale ASF e segnalo il canale video di Atmel http://www.youtube.com/user/AtmelCorporation che contiene numerosi video tra cui alcuni dedicati ad ASF

Prossimamente analizzeremo nel dettaglio il file main.c e vedremo come aggiungere nuovi moduli al nostro progetto

giovedì 20 giugno 2013

Prestazioni XMega in modalità Debug e Release

Atmel Studio, che ricordiamo essere una shell di Visual Studio personalizzata da Atmel, permette di gestire diverse configurazioni all’interno di uno stesso progetto.
Ogni configurazione imposta diversi parametri del compilatore e del linker, normalmente troviamo già pronte le configurazioni Debug e Release.
Vediamo superficialmente alcune differenze a livello prestazionale su un XMega32A4U a 32 MHz:











Istruzioni (all’interno di un ciclo continuo) Debug Release
ioport_set_pin_level(PORTA1, LOW);
ioport_set_pin_level(PORTA1, HIGH);
208.3 KHz8.333 MHz
PORTA.OUTSET = PIN1_bm;
PORTA.OUTCLR = PIN1_bm;
3.571 MHz8.333 MHz
PORTA.OUTTGL = PIN1_bm;
3.125 MHz6.250 MHz

A prima vista, noncuranti della configurazione impostata che normalmente è Debug, l’utilizzo delle API IOPORT potrebbe sembrare molto più lento rispetto alla manipolazione diretta dei registri.

Semplicemente passando alla configurazione Release si otterranno però performance molto simili, in alcuni casi quasi 40 volte superiori alla configurazione Debug.

debug_release

Come curiosità per i lettori che utilizzano la scheda Arduino, su un ATMega328P a 16 MHz utilizzando le istruzioni
void setup() {                
  noInterrupts();
  DDRB = B00000001;
  while(true)
  {
    PORTB = B00000001; 
    PORTB = B00000000; 
  }
}
void loop() {
}

è possibile ottenere una frequenza di 4.000 MHz che cala ad 1.064 MHz (con lunghe pause tra un onda quadra e la successiva) se il ciclo avviene all’interno della funzione loop() a causa del maggiore overhead presente nella chiamata alla funzione loop().


void setup() {                
  noInterrupts();
  DDRB = B00000001;
}
void loop() {
  PORTB = B00000001; 
  PORTB = B00000000;
}

mercoledì 19 giugno 2013

XMega I/O

Gli XMega (in realtà il vero nome è ATXMega ma utilizzerò XMega per brevità) sono i microcontrollori fratelli maggiori degli ATMega, familiari anche agli utenti della piattaforma Arduino.



Approcciarsi utilizzando il C inizialmente può però sembrare difficile, ad esempio un compito semplice come "alzare un pin" può essere svolto in più modi:
- Utilizzando direttamente i registri del microcontrollore
- Utilizzando il framework ASF
  - API GPIO
  - API IOPORT

Il framework ASF permette un livello di astrazione maggiore, internamente manipola i registri del microcontrollore che sono la strada maestra per la sua programmazione ma richiedono spesso un'approfondita conoscenza del datasheet.

I "nuovi" spesso cercando in internet rimangono confusi dalla molteplicità di istruzioni che trovano per svolgere la solita azione, in questo caso possono trovare ben tre "set" di istruzioni diverse, alcune addirittura con diverse varianti.

Tralasciando le API GPIO che sono deprecate vediamo un esempio con entrambi gli approcci.

Supponiamo di voler impostare come uscita, alzare ed abbassare il pin 1 della PORT A

Utilizzando i registri:

PORTA.DIRSET = PIN1_bm;   // set pin to output
PORTA.OUTSET = PIN1_bm;   // set to high
PORTA.OUTCLR = PIN1_bm;   // set to low

Utilizzando ASF (API IOPORT):

#define PORTA1 IOPORT_CREATE_PIN(PORTA,1)      // create a pin name alias
ioport_init();                                 // initialize IOPORT
ioport_set_pin_dir(PORTA1, IOPORT_DIR_OUTPUT); // set pin to output
ioport_set_pin_level(PORTA1, HIGH);            // set to high
ioport_set_pin_level(PORTA1, LOW);             // set to low

Entrambi gli approcci hanno vantaggi e svantaggi tipici della programmazione a basso livello contro una programmazione di livello maggiore.


La sintassi tramite i registri è molto diversa rispetto alla famiglia ATMega dove erano presenti ad esempio i registri DDRx e PORTx, è però meglio organizzata tramite delle strutture accessibili tramite una sintassi PORTx.REGISTER dove REGISTER è il registro della porta che si vuole impostare e può essere per esempio sull’ATXMega32A4U uno dei seguenti valori (tratto dal file header iox32a4u.h)


port structure


Un ulteriore vantaggio di questa sintassi è senza ombra di dubbio l’intellisense dell’ambiente Atmel Studio che alla pressione del punto ci proporrà visualmente uno dei possibili registri


intellisense


Per chi si trovasse male con la sintassi col punto può optare per utilizzare l’underscore al suo posto, ad esempio potrà scrivere in maniera equivalente

PORTA_DIRSET = PIN1_bm;
PORTA_OUTSET = PIN1_bm;
PORTA_OUTCLR = PIN1_bm;

ricordando però che non potrà utilizzare un #define per impostare la sola porta come ad esempio è possibile con la sintassi con le strutture:


#define MYPORT PORTA   
MYPORT.DIRSET = PIN1_bm;


Il prezzo da pagare per questa ulteriore flessibilità (utilizza del punto o dell’underscore) è un’ulteriore confusione per i novizi che troveranno quindi molti modi per gestire i pin. Una volta consci delle molteplici possibilità non si avranno però problemi.


Aggiungo come nota al codice ASF che quasi tutte le API hanno una funzione nomeAPI_init() che deve essere chiamata prima dell'utilizzo delle restanti funzioni.

Per chi volesse valutare o iniziare a programmare gli XMega personalmente consiglio di partire dalla libreria ASF che ha buona parte delle API corredate da una documentazione minimale ma con un'ottima sezione Quick Start che permette di fare i primi passi in tempi molto brevi, per IOPORT il link è http://asf.atmel.com/docs/latest/xmegaau/html/ioport_quickstart.html, accessibile anche da ASF Explorer direttamente dall'interno di Atmel Studio

AL422B

Immagini provenienti da una telecamera (o webcam o camera) rappresentano un flusso dati molto veloce che spesso i microcontrollori non riescono a gestire in tempo reale.

Per poter ovviare al problema è possibile utilizzare una memoria esterna che immagazzini rapidamente i byte dell'immagine permettendo una lettura in differita più lenta.

Il prezzo da pagare sarà inevitabilmente la perdita di qualche frame ma in alcune applicazioni potrebbe non rappresentare un problema.

L'integrato AL422B consiste di una memoria FIFO DRAM da 3M bits (393.216 byte) utile a questo scopo
Il funzionamento è abbastanza semplice ed intuitivo e nasconde le complessità delle memorie DRAM.

Dallo schema si evince una cache SRAM che come si legge da datasheet comporta una lettura almeno 128 byte prima della scrittura. Quando si scrive l'indirizzo 200 si potrà quindi al massimo leggere fino all'indirizzo 72.

I dati presentati come byte in ingresso (DI0-DI7) sono memorizzati al fronte di salita del segnale di clock WCK che deve essere fornito all'integrato, ed in genere proveniente dal Pixel Clock della camera, se il segnale /WE (Write Enable) è al livello logico basso. L'indirizzo interno di scrittura sarà automaticamente incrementato e non sarà necessario preoccuparsi di altro.

La lettura è pressoché analoga, i dati sono presentati in uscita (DO0-DO7) ai fronti di salita del clock RCK quando il segnale /RE (Read Enable) è al livello logico basso.

Il clock di scrittura e lettura deve sempre essere fornito all'integrato (quindi deve essere generato in modalità detta free running) anche quando non si vuole leggere o scrivere la memoria perché il più veloce dei due segnali servirà a rinfrescare la DRAM. Non è possibile fornire costantemente solo uno dei due clock pena la corruzione dei dati in memoria. La frequenza di entrambi deve essere almeno 1 MHz come da datasheet.
Questo esclude l'utilizzo di microcontrollori troppo lenti, quindi non adeguati a trattare immagini.

Coi clock "sempre andanti" si utilizzeranno quindi i segnali di abilitazione per iniziare la lettura e la scrittura.

Il segnale /OE (Output Enable) se a livello alto servirà per "scollegare l'uscita", ovvero per mandare in alta impedenza i segnali DO0-DO7.

La prima cosa da fare all'avvio della memoria è inizializzare a zero l'indirizzo di lettura e scrittura della memoria tramite i segnali /RRST ed /WRST.

Su internet è reperibile una datasheet risalente al 2001 che purtroppo presenta alcune mancanze, pubblico il Datasheet AL422B v1.5 del 2006 che chiarisce che per un reset corretto il segnale /RE non deve mai essere basso sul fronte di salita del segnale /RRST

Col segnale /RE mal impostato il reset non funziona e si ottengono letture e scritture praticamente casuali, problema particolarmente fastidioso da correggere. Prossimamente vedremo come verificare il corretto funzionamento dell'AL422B.

Alla prossima

Nota: La versione "PBF" del chip, funzionalmente identica, indica il package "Pb free"

martedì 18 giugno 2013

Hello World

Benvenuti nel mio nuovo blog, spero di poter iniziare a scrivere presto su argomenti come logiche programmabili (CPLD e FPGA), microcontrollori (ATMega, XMega), circuiti integrati di vario tipo (DDS, memorie, etc..) ed elettronica analogica (filtri, amplificatori operazionali, power led etc..)