Interfaccia sperimentale TSPpic

  • Scheda sperimentale con PIC16F877 / 877A
  • Bootloader seriale all'indirizzo 1F00H
  • Comunicazione seriale 38400 8 N 2
  • Alimentazione 9..25Vcc, assorbimento 20mA
  • Regolatore 5V
  • Adattatore livelli RS232/TTL.
  • LED indicatori trasmissione/ricezione
  • Porte A B C D prolungate su morsettiere e connettore IDC 34 poli
  • All'accensione/reset viene letto un jumper sul pin RE0, se chiuso si avvia il bootloader, altrimenti si salta alla locazione 0003H dove deve esserci il programma applicativo.

La scheda

La scheda non e' la solita demoboard dotata di pulsanti / display / rele' ecc, ma e' piuttosto pensata per un uso sperimentale spartano "al volo", mette infatti a disposizione in modo rapido le porte di un PIC16F877, sia attraverso un connettore IDC da 34 poli (che porta anche le alimentazioni) sia attraverso dei comuni morsetti a vite, comodi ad esempio per il collegamento ad una breadboard con spezzoni di filo rigido.




Puo' essere alimentata attraverso un jack coassiale, un morsetto o attraverso i due pin a lato del morsetto (con dei coccodrilli). Un diodo protegge dall'inversione di polarita'. Il regolatore e' alettato in modo da poter alimentare a 5V anche circuiti esterni che richiedono qualche centinaio di mA. Per evitare il surriscaldamento e' bene non superare i 4W di dissipazione, il che vuol dire assorbire sui 5V una corrente massima di 200mA se si alimenta il tutto a 25V, che puo' salire fino a 1A alimentando il tutto a 9..10V

Sulla scheda trova posto il classico convertitore RS232/TTL realizzato con l'integrato MAX232, con l'aggiunta di due LED verdi che evidenziano il passaggio dei dati (si accendono quando transitano i bit a zero).

Per quanto riguarda il PIC i pochi componenti necessari sono i condensatori e il quarzo per il clock, il pulsante di reset, e il jumper con la resistenza di pull-up.




Il bootloader

Prima di essere inserito sulla scheda, il pic va preprogrammato con l'apposito bootloader nell'ultima pagina da 256 bytes della memoria, e con le tre istruzioni di salto nei primi tre indirizzi, questo permette di usare la scheda come interfaccia/periferica seriale trasferendovi di volta in volta l'applicativo necessario tramite un apposito programma loader su PC.

Una volta caricato il programma applicativo, la scheda lo puo' eseguire automaticamente ad ogni accensione (o reset), per fare questo basta aprire il jumper sul pin RE0. Se questo jumper viene invece tenuto chiuso allora all'accensione la scheda si predispone sempre in modalita' bootloader attendendo comandi dalla seriale.

ATTENZIONE! Per non perdere la funzionalita' bootloader, ogni programma applicativo deve sempre iniziare con le istruzioni di salto al bootloader stesso:

               ORG   0
               MOVLW HIGH 1F00H
               MOVWF PCLATH
               GOTO  1F00H
      

Il bootloader salta poi all'indirizzo 3, quando trova aperto il jumper, o quando gli viene comandato dalla seriale. La figura seguente schematizza i salti che avvengono.





Le funzioni del bootloader

Il bootloader configura dapprima tutte le porte come ingressi, poi controlla lo stato del jumper e se lo trova aperto salta all'indirizzo 3 (in realta' non fa un GOTO ma una CALL, in modo che, se servisse, con un semplice RETURN l'applicativo potrebbe ripassare il controllo al bootloader).

Se trova il jumper chiuso si mette in ascolto sulla seriale. La trasmissione/ricezione seriale e' realizzata a software in modo da lasciare libera la USART interna. Nonostante l'uso di un quarzo a soli 4MHz, la velocita' di comunicazione raggiunta e' di 38400 bit/secondo grazie ad un uso ottimizzato dei cicli macchina nelle subroutines di trasmissione e ricezione.

Il bootloader ha tre funzioni che si attivano quando vengono ricevuti i bytes 31 32 e 34, la prima e' una semplice richiesta di sincronismo, il modulo risponde con la stringa "MOK" (contrazione di modulo OK), la seconda riceve i dati da scrivere nella memoria flash, la terza e' un "esegui" e forza una CALL all'indirizzo 3, praticamente in questo modo si avvia il programma applicativo senza bisogno di resettare il micro o aprire il jumper, e la scheda funziona quindi come interfaccia/periferica esterna del PC.

La funzione load e' la piu' complessa, richiede due bytes che specificano l'indirizzo di memoria in cui scrivere, seguito da 4 words (8 bytes). Il PIC 16F877 potrebbe scrivere in memoria una word alla volta, ma la versione 877A richiede la scrittura di 4 word alla volta e inizianti a indirizzi che hanno i due bit bassi a zero, quindi 0, 4, 8, 12 ecc. Il bootloader di questo progetto utilizza il metodo della versione 877A in modo da poter usare entrambe le versioni senza alcuna modifica.

I valori dell'indirizzo e delle words vengono ricevuti sempre prima il byte basso e poi il byte alto. La scrittura nella flash comprende la verifica automatica, la funzione load risponde con la stringa "WOK" se tutto e' andato a buon fine, e con "WKO" se si e' riscontrato un errore durante la rilettura dei dati.

La figura seguente riassume le tre funzioni del bootloader:







boot.zip Sorgente e .HEX del bootloader, compreso il programma di test lamp.asm




Il loader

Il bootloader sul PIC attende comandi sulla seriale, quindi sul PC occorre una controparte che glieli invii: il loader.

Il loader ha il compito di leggere un file .HEX prodotto dall'assemblatore MPASMWIN, estrarre le informazioni necessarie, ed inviarle al bootloader secondo quanto richiesto dalla funzione load.

Un programma per fare questo puo' essere scritto in qualsiasi linguaggio di programmazione che possa accedere ai files su disco e alla porta seriale. Per le prove con questa scheda il loader e' stato scritto in python, e puo' usare indifferentemente sia porte seriali reali che seriali virtuali attraverso convertitore USB/RS232:


#----------------------------------------------------------------
# SIMPLE_LOADER.PY - Loader per PIC16F877/877A
#
# Program by Claudio Fin 26/10/2008
#
# REQUISITI:
# - Interprete Python 2.5 installato sul PC
# - Estensioni per Windows installate
# - Modulo pySerial installato
#
# Scrivere nel programma il nome della porta seriale
# che si vuole usare (esempio com1) e il nome del
# file .HEX (esempio lamp.hex). Il file HEX si deve
# trovare nella stessa directory del programma.
#----------------------------------------------------------------
import serial
import struct
ser = serial.Serial("com1", 38400, 8, "N", 2, timeout=1)
print "TRASFERIMENTO IN CORSO..."
try:
    for riga in file("lamp.hex", "r"):
        riga = riga.rstrip("\n")
        if riga[7:9] == "00":
            print riga,
            ind = int(riga[3:7], 16) / 2
            dati = riga[9:len(riga)-2].ljust(16, "F")
            if len(dati) > 16:
                dati = dati.ljust(32, "F")
            while dati:
                trasm = [32, ind % 256, int(ind / 256)]
                for h in xrange(0, 16, 2):
                    trasm.append(int(dati[h:h+2], 16))
                ser.write(struct.pack("B"*len(trasm), *trasm))
                risp = ser.read(3)
                if risp != "WOK": raise IOError
                dati = dati[16:]
                ind += 4
            print "OK"
    print "\nTRASFERIMENTO COMPLETATO\n"
except IOError:
    print "--\n\n* ERRORE * TRASFERIMENTO FALLITO!\n"
ser.close()
raw_input("Invio per terminare...")


Nota sui files .HEX

Qui sotto e' riporato il file .HEX del programma di prova lamp.asm, e di seguito la scomposizione in colonne per identificare i dati che ci interessano. La prima indica la lunghezza in bytes del campo dati, la seconda in blu l'indirizzo a cui iniziano, la terza indica il "tipo record", a noi interessano le righe con "00" che sono quelle che contengono i dati che dobbiamo caricare. La quarta colonna sono i singoli bytes dati espressi in esadecimale. La quinta e' un checksum. Tutti i valori sono espressi in esadecimale.



Il loader deve estrarre dalle righe che ci interessano l'indirizzo e il campo dati. L'indirizzo va diviso per due in quanto il file hex conta gli indirizzi in bytes, mentre gli indirizzi per la scrittura nella flash si contano in words. Il campo dati puo' contenere da 2 a 16 bytes (da 1 a 8 words), pertanto per la scrittura nella flash (che richiede 4 words al colpo) si devono eventualmente aggiungere dei bytes fittizi a 0FFH per completare il blocco di 4 words.