Motivació
Durant la venta del LDST2 s'han trobat diversos problemes:
- Els conversors FTDI emulen tan bé un port serie real que el Windows invoca el servei serenum que té la mania de confondre el port de TERMINAL amb un mouse serie cosa que acaba provocant que el LDST no arrenqui (el port està en ús) i que la màquina tingui un comportament erratic (rep ordres destinades a un mouse). No hi ha una manera senzilla de desactivar aquest comportament.
- No hi ha manera senzilla de afegir soport pel protocol d'alta velocitat i sembla que algunes màquines només volen parlar el protocol d'alta velocitat....
- El encapsulat del xip (FT2232H) és massa compacte per poder ser soldat a mà de manera fiable. (El volum de producció segurament no serà prou alt per justificar un ensamblat a màquina)
- Han aparegut alguns problemes amb la API del port serie que proporciona el Windows (Imposibilitat de sincronitzar un canvi de linia de control amb les dades o detectar quan s'ha acabat de transmetre, comportament inconsistent entre els diferents drivers de port serie....)
- Detecció de ports innecessariament complexe.
Per solventar tots aquests problemes s'ha optat per un nou diseny que no utilitzi el port serie.
Disseny del protocol
S'ha optat per continuar utilitzant la interficie USB per comunicar-se amb el PC. S'han estudiat diverses opcions:
| Tipus dispositiu | Pros | Contres |
|---|---|---|
| CDC/ACM |
|
|
| Vendor specific |
|
|
| HID |
|
|
Finalment s'ha escollit el dispositiu HID malgrat les limitacions ja que és relativament senzill d'implementar i algunes de les restriccions es poden esquivar amb facilitat.
Una de les restriccions més problemàtiques és la limitació d'EndPoints ( un endpoint tipus Interrupt en mode FullSpeed està limitat a 64KBytes/s ) però per sort és extremadament senzilla d'esquivar. Si el dispositiu s'identifica com a 'CompositeDevice' pot presentar fins a 255 dispositius lògics...
S'ha optat per presentar 2 dispositius lògics un per cada port (CASSETTE, TERMINAL)
Disseny del Hardware
Interficie HDLC/d'alta velocitat
Vist que no s'ha trobat cap xip amb una interfice de relativament bon conectar al PIC18F24J50PIC18F45J50, (La majoria de xips que està garantit que funcionaran correctament són dels anys 70-80 i utilitzen un bus de 8 bits compatible amb 80x86 o Z80) i com que s'haurà d'utilitzar igualment un PLA/CPLD per conectar els transceptors amb el xip que implementi el protocol HDLC, s'ha optat per integrar dins el propi CPLD la funcionalitat de (de)codificar el protocol HDLC.
Per simplificar la lògica a implementar en el CPLD, s'ha decidit que aquest només adapti la codificació de les dades el mínim necessari per que compleixin amb la senyalització el protocol SPI que és soportat directament per l'electrònica del PIC18F45J50 soporta directament.
S'ha optat per utilitzar un ATF1504ASV com a CPLD, ja que:
- el fabricant proporciona eines gratuites de programació
- encapsulat PLCC disponible cosa que el fa de bon soldar i també és senzill trobar socols per aquest encapulat
- hi han diversos fabricants que fabriquen xips compatibles i per tan serà fàcil d'obtenir en el futur
- es pot programar/reprogramar un cop està soldat al circuit.
Codificació
S'ha optat per utlitzar una etapa de potència semblant a la original tot i que s'ha substituit el SN75159 per un MC3487N per motius de disponibilitat. La electrònica és bàsicament la mateixa: Un PLA/CPLD controlant un transmisor de RS422/RS485 que s'utilitza com a driver del transformador. Podria esser interessant en un futur d'utilitzar un transformador amb un primari amb presa intermitja i utilitzar 2 sortides del CPLD en mode colector obert per controlar directament el transformador.
S'ha descartat la alternativa anterior per culpa de l'alt consum electric que representava (100mA o més per transmisor sense tenir en compte el consum fet per les línies de transmisió) i que feia que el consum de la placa excedis els 500mA màxims permesos per a dispositius alimentats via USB. Finalment s'ha optat per usar un transformador amb presa intermitja i s'ha usat com a driver portes NOT amb sortida en colector obert. Aquest sistema té els següents avantatges respecte a conectar el transformador directament al CPLD:
- Garanteix que encara que el CPLD quedi mal configurat, res es cremarà
- Separa els 5V que s'utilitzen per alimentar el transformador de els 3.3V del CPLD
- Es reaprofiten les portes NOT sobrants per construir un detector molt més sensible
Decodificació
S'ha utilitzat un disseny totalment diferent del original. Ja que:
- els xips requerits (o similars) són cada cop més dificils de trobar
- s'ha de ajustar a mà el resonador utilitzat per recuperar la senyal de rellotge per cada placa que es fabriqui....
- requereix molts components discrets auxiliars....
El disseny qe s'ha implementat utilitza optocouplers d'alta velocitat per detectar els pulsos de la senyal i envia directament la sortida dels optocouplers al CPLD per que aquest acabi la decodificació i recuperació de rellotge.
Aquest disseny té com a inconvenients que és molt menys sensible que l'original ja que els optocouplers necessiten un llindar de detecció de 1.8-2V i tampoc disposa d'una etapa amplificadora. Tot i això tests realitzats amb una unitat de dades Mayer han demostrat que rep correctament les dades fins i tot amb 10m de cable. Com a avantage requereix molts pocs components i no requereix cap ajust.
Per culpa dels canvis fets en la codificació, s'ha optat per aprofitar les portes NOT sobrants per fer un receptor molt més sensible (llindar de detecció a 0.7-0.8V) i que ajusta molt més bé l'impedància d'entrada. Com a contra ha augmentat la quantitat de components discrets necessaris ja que entre altres aquest disseny requereix diodes zener per protegir les portes NOT contra pics de voltatge.
Actualització/programació
Vista la complexitat del circuit implementat en el CPLD, és probable que es requereixi actualitzar la programació d'una capsa que ja està en mans del client, per tan s'ha optat per conectar els pins de programació del CPLD a la CPU de manera que aquesta pugui reprogramar el CPLD. Això també ens permet soldar un CPLD en blanc a la placa i programar-lo després.
Per sort, la programació del CPLD és relativament senzilla, ja que es pot programar via JTAG. Per desgràcia el fitxer BSDL IEEE 1532 subministrat per el fabricant no inclou la informació de programació.
Finalment aquest sistema de programació, al ser estandaritzat podria permetre substituir el CPLD per un altre model de més capacitat i/o fabricant.
Funcionament del CPLD
El CPLD utilitza un CLK=16.384MHz, és a dir 16x vegades el baudrate. Internament el CPLD divideix aquesta senyar per obtenir un CLK secundari de 1.024MHz sincronitzat amb les dades que està processant. Això també permet la generació de les senyals als moments adecuats per enviar/rebre dades via el protocol SPI.
Quan es compença una transmissió de dades o durant la recepció quan es rep un puls (CLK_SYNC) s'inicialitza el divisor al estat 0 per sincrontizar els rellotges.
Al llarg del cicle del divisor es realitzen diverses accions :
- nCLK=02 HDLC_DT_LATCH: Es llegeix un bit del HDLC i s'actualitza el SPI_DO si s'escau.
- nCLK=06...09: El CLOCK del bus SPI està a nivell actiu si hi ha una transferència de dades en curs
- nCLK=12 CPLD_DI_LATCH: Es llegeix un bit del SPI_DI si s'escau
| Estats del divisor | |||
|---|---|---|---|
| nCLK | CLK_SPI | Events | |
| 00 | 0 | <-Reset/CLK_SYNC | |
| 01 | 0 | ||
| 02 | 0 | ->HDLC_DT_LATCH | |
| 03 | 0 | ||
| 04 | 0 | ||
| 05 | 0 | ||
| 06 | 1 | ||
| 07 | 1 | ||
| 08 | 1 | ||
| 09 | 1 | ||
| 10 | 0 | ||
| 11 | 0 | ||
| 12 | 0 | ->CPLD_DI_LATCH | |
| 13 | 0 | ||
| 14 | 0 | ||
| 15 | 0 | ||
El CPLD té 4 estats principals:
| Estat | INPUTS | Descripció | ||
|---|---|---|---|---|
| RX_NTX | IRX_POS | IRX_NEG | ||
| TX_ACTIVE | 0 | x | x |
S'entra en aquest estat al rebre un flanc descendent RX_NTX (passa de 1->0) independentment del estat actual. Mentre estigui en aquest estat, el CPLD genera la senyalització necessaria per rebre dades del bus SPI que codifica i transmet per el HDLC. Si es reben 15 o més '1' segits i el numero total de bits rebuts es divisible per 8 llavors es passa al estat TX_IDLE. Si es rep un flanc ascendent de RX_NTX (passa de 0->1) llavors es passa al estat RX_IDLE. |
| TX_IDLE | 0 | x | x |
En aquest estat el CPLD no genera cap tipus de senyalització pel bus SPI i ignora qualsevol entrada excepte RX_NTX. Si rep un flanc ascendent de RX_NTX llavors passa al estat RX_IDLE. |
| RX_IDLE | 1 | 1 | 1 |
En aquest estat el CPLD espera indefinidament rebre dades del bus HDLC. Transcisiona a RX_ACTIVE el moment que rep un flanc descendent de IRX_POS o IRX_NEG. |
| RX_ACTIVE | 1 | x | x |
En aquest estat el CPLD captura les dades que rep per el bus HDLC i les recodifica i genera la senyalitació necessaria per enviar-les per el bus SPI. Es manté en aquest estat fins que detecta que el bus HDLC ha acabat de transmetre (rebuts 15 o més '1' seguits i el número total de bits rebuts és divisible per 8). |
Pinout CPLD
| Pinout ATF1504 PLCC-44 | ||
|---|---|---|
| PIN | Dir | Nom |
| 1 | I | GCLR |
| 2 | I | ctrl_clk |
| 3 | VCC | |
| 4 | O | rs_extra_out |
| 5 | I | hdlc_req |
| 7 | I | TDI |
| 8 | O | hdlc_rx_blink |
| 9 | O | hdlc_tx_blink |
| 10 | GND | |
| 11 | I/O | ctrl_res3 |
| 12 | I/O | ctrl_res2 |
| 13 | I | TMS |
| 15 | VCC | |
| 17 | O | rs_extra_in |
| 18 | O | tx_pos |
| 19 | O | tx_neg |
| 20 | I | nrx_neg |
| 21 | I | nrx_pos |
| 22 | GND | |
| 23 | VCC | |
| 29 | O | SPI_CLK |
| 30 | GND | |
| 31 | O | SPI_DO |
| 32 | I | TCK |
| 33 | I | SPI_DI |
| 34 | I | sense1_vneg |
| 35 | VCC | |
| 36 | I | sense2_vneg |
| 37 | I | sense1_vpos |
| 38 | O | TDO |
| 39 | I | sense2_vpos |
| 42 | GND | |
| 43 | I | GCLK |
| 44 | I | ctrl_oe |
PIC18F24J50 (CPU)
S'ha elegit aquest xip ja que:
- porta incorporats 2 ports serie
- té parcialment implementat per hardware el protocol USB
- capacitat d'auto reprogramar-se
- protecció de codi
- requeriments mínims de components auxiliars
- disponibles encapsulat de fàcil soldar
- eines de desenvolupament i mostres gratuites
S'ha optat per usar un cristall de 4MHz ja que és el de freqüència més baixa que encara permet usar el USB en mode FullSpeed. Ja que redueix les EMI i el consum del circuit.
S'utilitzen els dos ports serie del xip per el CASSETTE i el TERMINAL respectivament. S'ha utilitzat el mòdul MSSP2 per conectar el bus SPI amb el CPLD, ja que el MSSP1 comparteix pins amb un dels ports serie i per tan no es pot utilitzar mentre aquest estigui actiu. La resta de pins s'han utilitzat per les linies d'estat i control del port de CASSETTE, el botó FW_UPGRADE i el bus JTAG per poder reprogramar el CPLD durant una actualització de firmware.
S'ha optat per utilitzar com a adaptador TTL <-> RS232 el xip SP211 ja que malgrat que és força més car que un MAX232, al utilitzar condensadors més barats i en menor quantitat (cada SP211 ofereix més conversors que 2x MAX232) al final resulta a un preu semblant i utilitza menys area de PCB.
Organització del codi del PIC18F24J50
El PIC18F24J50 executa sempre el codi directament des de la FlashROM (Arquitectura Harvard amb la FlashROM com a memòria de codi) cosa que fa que s'hagi de vigilar amb la seqüència de esborrar/programar/verificar ja que si s'esborra algun fragment de codi que estigui en ús el programa fallarà.
Per solucionar aquest problema, s'ha separat el codi que es carrega en el xip en 2 programes independents:
- Bootloader:
És l'encarregat de gestionar l'actualització del firmware. Sempre arrenca primer i en principi no es pot reprogramar. Inclou una implementació minimalista del protocol USB per permetre actualitzar el firmware des del PC. Ocupa els primers 4Kbytes de la memòria per poder interceptar l'arrencada i el vector d'interrupcions i els últims 1Kbytes de la memòria per protegir la configuració del xip (protecció de codi, mode del cristall, divisors i multiplicadors de freqüència de la CPU....)
- Payload:
És el encarregat de el funcionament normal de la placa. Només invoca al Bootloader quan s'inicia una operació d'actualització del firmware o per obtenir informació protegida (Ex: identificació del dispositiu). Ha d'incloure al final del espai d'addreces disponibles el corresponent CRC-16-CCITT per que el Bootloader pugui validar que és correcte.
Actualització de firmware
Per actualitzar el firmware primer s'ha d'entrar en mode actualització. Hi ha 3 maneres d'entrar-hi:
- El Bootloader detecta que no hi ha payload o que esta corrupte o que falta programar el número de serie del dispositiu.
- El Bootloader detecta que el botó FW_UPGRADE està pulsat.
- El payload invoca el Bootloader directament o indirectament (finalitza la funció main() )
Un cop en mode actualització el Bootloader admet comandaments via USB. Tots els comandaments han de ser de 64Bytes i totes les respostes són de 64Bytes malgrat que realment no s'utilitzin. Enviar o rebre un número inferior donarà problemes amb qualsevol driver HID que respecti les especificacions dels descriptors.
Tots els comandaments excepte el de Reset es responen amb un ACK/NAK
| Format ACK/NAK a un comandament del Bootloader | |||
|---|---|---|---|
| Offset | Len | Nom | Descripció |
| 0 | 1 | OP_CODE | Op code del comandament al que es respon o '?' per comandament invàlid |
| 1 | 1 | ACK/NAK |
0x00->ACK 0x01..0xff->NAK |
| 2 | 62 | ARGS |
Arguments del comandament (si existeixen) amb un padding de zeros fins a omplir el camp |
Comandaments soportats:
| Format comandament Bootloader | |||
|---|---|---|---|
| OP_CODE | ARGS | Dades Resposta | Descripció |
| 'I' | 'B','X','0','0' | identificació | |
| 'A' | Reinicia la màquina d'estats encarregada de reprogramar la FlashROM | ||
| 'N' | B0,....,B31 |
Estableix el codi de serie de la placa en cas que no hi sigui.Ex BX1234L94321 B0..B31=cadena de 32 bytes formada per un descriptor d'string USB vàlid amb el codi de serie seguida de un checksum complementari de 8 bits i amb un padding de zeros | |
| 'S' | Blk,Salt |
Estableix el block a programar.S'ha d'enviar abans que el primer comandament 'B' Blk=núm block d'1KByte del payload a programar començant des de 0 Salt=0 reservat per ús futur | |
| 'B' | Blk,Frg,Salt2,dt0,...,dt35 | Blk,Frg |
Envia un fragment de 32 bytes + codi integritat. Els fragments s'han d'enviar en ordre ascendent.(primer el fragment0, fragment1,....) Blk=núm de block que s'esta programant ha de coincidir amb el block seleccionat previament en el comandament 'S' Frg=núm de fragment (0-31) Salt2=0 reservat per al futur dt0...dt35=dades encriptades a programar |
| 'W' | Blk | Blk,32 |
Inicia el cicle esborrat/programació del block seleccionat. No es pot grabar un block parcial. ha de anar precedit sempre de un comandament 'S' seguit de 32 comandaments 'W' Blk=núm de block que s'esta programant ha de coincidir amb el block seleccionat previament en el comandament 'S' |
| 'V' | Verifica que el payload s'hagi programat correctament (calcula el CRC) | ||
| 'E' | Blk |
Esborra un block del payload. Només usat per debug. Blk=núm de block a esborrar | |
| 'G' | Reset/Executar payload. no respon ni dades ni ACK/NAK. | ||
Format d'un fitxer d'actualització de firmware
Les dades estan guardades dins el fitxer en format de text ASCII. El fitxer és un conjunt de linies de 5 o més caràcters cada una. No admet comentaris ni espais en blanc.
Esta dividit en 2 seccions:
- Capçaleres: Es troben al principi del fitxer i tenen el format:
| Offset | len | Format | Descripció |
|---|---|---|---|
| 0 | 1 | 'H' | Marcador de capçalera |
| 1 | 3 | .{3} | tres caracters imprimibles ASCII que indiquen el tipus de capçalera |
| 4 | 1 | ':' | Separador |
| 5 | <200 | .* | Dades de la capçalera |
- Dades: Contenen el programa a carregar.
| Offset | len | Format | Descripció |
|---|---|---|---|
| 0 | 2 | [0-9a-fA-F]{2} | Núm de block en hexadecimal |
| 2 | 2 | [0-9a-fA-F]{2} | Núm fragment en hexadecimal |
| 4 | 1 | ':' | Separador |
| 5 | 72 | [0-9a-fA-F]{72} | dades del fragment codificades en hexadecimal |
Les dades del fragment són el resultat de:
- partint d'un fragment (block de 32 bytes de codi) en format binari
- se li afegeix el corresponent checksum de 16 bits (little-endian)
- se li afegeixen el número de block i fragment codificats cada un en un byte
- se li aplica un XTEA en mode OFB
- es converteix el resultat a hexadecimal
LCD BO1608D
Per facilitar la resolució de problemes i el depurat del firmware s'ha decidit afegir un LCD. Aquest cambi també ha permès suprimir alguns LEDs d'estat. El model de LCD elegit al final és el BO1602D. S'ha optat per aquest model ja que es comunica per I2C cosa que simplifica notablement tant el conexionat com la programació. També ha sigut un factor a favor que aquest model treballi a +3.3V.
S'ha conectat el LCD al MSSP1 (és l'únic dels dos MSSP que soporta I2C), per sort els pins d'I2C no entren en colisió amb cap altre funció que s'utilitzi de la CPU. Per minimitzar components s'ha optat per usar els pull-ups integrats en la CPU per les línies del I2C.
Interfície RS232
Interfície USB
Analisis de potència
I_init=I_CPU_Core+I_CPU_USB+I_Osc+I_CPLD = 23mA + 40mA + 10mA + 20mA = 93mA (MAX 100mA)
I_treball=I_CPU_Max+I_Osc+I_CPLD_Work+I_HDLC_Driver+I_LCD+2*I_SP211 =250mA + 10mA + 70mA + 40mA +2mA 2*30mA = 432mA (MAX 500mA)
Diseny mecànic i del PCB
S'ha optat per fer que el nou disseny sigui mecanicament compatible amb les capses de la caixa de comunicacions original ja que n'hi havia un stock significant, tot i això s'ha fet el possible per que es pugui aprofitar el nou disseny amb altres capses
Ha resultat massa problemàtic adaptar el disseny a la caixa vella. Sobretot ha resultat prohibitiu fer que els acabats i etiquetat quedessin bé a un preu raonable.
Finalment, s'ha optat per una caixa d'aumini anoditzat negre.
Anclatges
Conectors
- USB: Per garantir la màxima adaptabilitat a una possible caixa mecanicament diferent en el futur, hi ha 3 posicions possibles on soldar el conector USB:
- USB B en la cara inferior del PCB que encaixa amb el centre del forat per el PortA de la capsa
- MiniUSB en la cara superior en previsió a la pròxima versió de la capsa
- Connector de 4 pins SIL amb pas de 0.1in (comparteix 2 pins amb el USB B) per si es vol utilitzar un connector USB aeri
- Conector RJ45 Terminal
| Pin RJ45 | Nom | Dir | Pin DB25 |
|---|---|---|---|
| 1 | CTS | ← | 5 |
| 2 | DSR | ← | 6 |
| 3 | RxD | ← | 3 |
| 4 | GND | — | 7 |
| 5 | DCD | ← | 8 |
| 6 | TxD | → | 2 |
| 7 | DTR | → | 20 |
| 8 | RTS | → | 4 |
- Connector 2x20:
Agrupa tots els pins del port de CASSETTE , el port de TERMINAL ,linies RS232 extres i el connector ICSP per carregar la programació inicial a la CPU.
| PINOUT | |||
|---|---|---|---|
| Nom | PIN | PIN | Nom |
| C_BuffSTOut | 1 | 2 | C_TXD |
| O_EXTRA | 3 | 4 | C_RXD |
| C_BuffSTIn | 5 | 6 | C_RTS |
| N.C. | 7 | 8 | C_MstSndData |
| N.C. | 9 | 10 | N.C. |
| N.C. | 11 | 12 | 0V |
| C_Operable | 13 | 14 | N.C. |
| N.C. | 15 | 16 | N.C. |
| N.C. | 17 | 18 | N.C. |
| C_Diff_P | 19 | 20 | C_Eject |
| C_Diff_N | 21 | 22 | 0V |
| 3.3V | 23 | 24 | ICSP_CLR |
| ICSP_DAT | 25 | 26 | ICSP_CLK |
| GND | 27 | 28 | T_TxD |
| I_EXTRA1 | 29 | 30 | T_RxD |
| I_EXTRA2 | 31 | 32 | T_RTS |
| N.C. | 33 | 34 | T_CTS |
| N.C. | 35 | 36 | T_DSR |
| N.C. | 37 | 38 | 0V |
| T_DTR | 39 | 40 | T_DCD |
El pinout del conector està pensat per que es pugui usar cable pla sense necessitat de permutar pins per connectar amb els connectors DB25 dels ports de Cassette i Terminal i es pugui fer sense exposar els pins de ICSP al exterior.
- Connector IDC 2x13
| PINOUT | |||
|---|---|---|---|
| Nom | PIN | PIN | Nom |
| N.C. | 1 | 2 | C_BuffSTOut |
| C_TXD | 3 | 4 | O_EXTRA |
| C_RXD | 5 | 6 | C_BuffSTIn |
| C_RTS | 7 | 8 | N.C. |
| C_MstSndData | 9 | 10 | N.C. |
| N.C. | 11 | 12 | N.C. |
| 0V | 13 | 14 | C_Operable |
| N.C. | 15 | 16 | N.C. |
| N.C. | 17 | 18 | N.C. |
| N.C. | 19 | 20 | C_Diff_P |
| C_Eject | 21 | 22 | C_Diff_N |
| 3.3V | 23 | 24 | ICSP_CLR |
| ICSP_CLK | 25 | 26 | ICSP_DAT |