Introduction au 68HC11(F1) Jean-Michel FRIEDT, Mai 1999 (March 6, 2000) 1 Introduction Le choix du 68HC11F1 a ´ et´ e fait selon le crit` ere d’avoir une microcontroleur ne n´ ecessitant pas de programmeur, pouvant ˆ etre pro- gramm´ e au vol ` a partir d’un port s´ erie 1 et comportant des convertisseurs analogique-num ´ erique (A/D) tout en permettant l’interfac ¸age avec une RAM externe. L’assembleur utilis´ e ici est disponible gratuitement par anonymous ftp ` a ftp.cmf.nrl.navy.mil dans /pub/kenh/ (il s’agit de asxxxx-v1.51.tar.gz en Novembre 1999, bien que la version puisse changer ult´ erieurement). Cet assembleur a l’avantage d’ˆ etre facilement adaptable ` a n’importe quel microcontroleur CISC (et inclut notamment des versions pour le 6809 et le Z80). La m´ ethode de compilation utilis´ ee, que ce soit sous DOS ou Linux, est la suivante : ´ ecrire le programme en assembleur dans un ´ editeur de texte (le fichier sera ici nomm´ e prg.asm). Par rapport aux exemple donn´ es dans le texte, il ne faut taper que la partie droite (par exemple pour une ligne du type 0000 8E 01 FF lds #0h01FF ; setup : stack il ne faut entrer que lds #0h01FF suivi ´ eventuellement des commentaires (le texte apr` es le ’;’). Le d´ ebut de la ligne est l’adresse o` u se situe la ligne de code (ici d´ ebut du programme donc adresse 0000), puis les opcode correspondant ` a cette ligne apr` es assemblage (ici 8E 01 FF). C’est la suite de ces opcodes que nous enverrons via la liaison s´ erie au 68HC11. l’assembler par as6811 -o prg.asm sous DOS ou as6811 -o prg.rel prg.asm sous Linux pour g´ en´ erer le fichier prg.rel qui contient le code en hexad´ ecimal et d’autres informations. retirer les lignes ne commenc ¸ant pas par un ’T’(grep ˆT) et les 8 premiers caract` eres des lignes restantes (qui sont le ’T’ suivi de l’adresse de d´ ebut de ligne : cut -c9-60) et mettre le r´ esultat dans prg.out : grep T %1.rel | cut -c9-60 > %1.out sous DOS ou grep T $1.rel | cut -c9-60 > $1.out sous Linux. enfin, programmer le 68HC11F1 en ex´ ecutant le programme DOS hc11.exe prg.out,r´ esultat de la compilation de hc11.pas fourni en annexe A de ce document. ` A noter que le num´ ero du port s´ erie est en hard dans le programme sous le nom de variable PortId. Les programmes pr´ esent´ es dans ce document ont ´ et´ e g´ en´ er´ es par as6811 -l prg.asm sous Linux (apr` es ´ edition des lignes inutiles). La mˆ eme fonction est disponible sous DOS par as6811 -l prg.asm qui g´ en` ere automatiquement le fichier .lst. 2 G´ en´ eralit´ es Les instructions de base. 2 registres 16 bits utilis´ es pour les acc` es m´ emoires : X, Y 2 registres g´ en´ eraux 8 bits : A, B qui peuvent se concat ´ ener en D=AB. Programme + data RAM Pile Registres ROM EEPROM vecteurs d’int. 0000 lds 03FF 1000 105F BF00 BFFF FE00 FFFF Les fonctions logiques habituelles : AND(A/B), LSL(A/B) (shift left), LSR(A/B) (shift right), ORA(A/B) Les op´ erations sur la pile : PSH(A/B/X/Y), PUL(A/B/X/Y) Les fonctions sur des bits : BCLR (bit clear), BSET (bit set) Les fonctions de saut relatif (court) : BRA (toujours), BNE ( 0), BSR (branch to subrou- tine), RTS Les fonctions de saut long : JMP, JSR, Les fonctions de chargement de valeur : LDA(A/B), LDD, LDS, LD(X/Y), ST(X/Y), STA(A/B), STD Les sauts avec test : BRCLR (branche si apr` es masquage avec les bits ` a 0, le r´ esultat est nul), BRSET (r´ ealise un ET logique avec le masque fourni, et branche si le r´ esultat est 0) Interruptions : CLI (autorise les interruptions), RTI, SEI (arrˆ ete les interruptions) Comparaison : CP(X/Y), CMP(A/B) Arithm´ etique : DEC(A/B), DE(X/Y), INC(A/B), IN(X/Y), SUB(A/B), SUBD, ADD(A/B), ADDD. 1 La restriction sur le port RS232 vient de l’utilisation d’un palmtop HP200LX comme programmeur. Cet ordinateur ne poss` ede qu’un port s´ erie comme extension (absence de port parall` ele). 1
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Intr oduction au 68HC11(F1)Jean-MichelFRIEDT, Mai 1999(March6, 2000)
1 Intr oduction
Le choix du 68HC11F1a ete fait selonle critered’avoir unemicrocontroleurne necessitantpasde programmeur, pouvant etrepro-grammeauvol a partir d’un port serie1 et comportantdesconvertisseursanalogique-numerique(A/D) tout enpermettantl’interfacageavecuneRAM externe.
L’assembleurutilise ici estdisponiblegratuitementparanonymousftp a ftp.cmf.nrl.navy.mil dans/pub/kenh/ (il s’agitde asxxxx-v1.51.tar.gz en Novembre1999,bien quela versionpuissechangerulterieurement).Cet assembleura l’avantaged’etrefacilementadaptablea n’importequelmicrocontroleurCISC(et inclut notammentdesversionspourle 6809et le Z80).
La methodedecompilationutilisee,quecesoit sousDOSou Linux, estla suivante:
ecrire le programmeen assembleurdansun editeurde texte (le fichier seraici nomme prg.asm ). Par rapportaux exempledonnesdansle texte, il nefauttaperquela partiedroite(parexemplepouruneligne du type0000 8E 01 FF lds #0h01FF ; setup : stackil ne faut entrerque lds #0h01FF suivi eventuellementdescommentaires(le texte apres le ’ ; ’). Le debut de la ligne estl’adresseou sesituela ligne decode(ici debut du programmedoncadresse0000 ), puis lesopcodecorrespondanta cetteligneapresassemblage(ici 8E 01 FF). C’estla suitedecesopcodesquenousenverronsvia la liaisonserieau68HC11.
1La restrictionsur le port RS232vient de l’utilisation d’un palmtopHP200LXcommeprogrammeur. Cet ordinateurnepossedequ’un port serie commeextension(absencedeport parallele).
1
Organisationdela memoire:1024 premiersoctets(0000-03FF): RAM. L’executioncommencea l’adresse0000 par un opcodefetch. Danscettememoire,
deconfiguration,la RAM et l’EEPROM an’importequelemplacementdela formex000(x=0..F).Danstouslescasnousdemarronsenbootstrapmode,maisil estpossibleensuitedepasserenmodeetenduetainsiaccedera unememoireexterieure.
3 Mise enRAM localed’un programmeet execution
L’objectif dansun premiertempsestde testerle montagede basecomprenantuniquementle microcontroleur68HC11et la logiquede communicationpar port RS2322 ainsi que les logiciel associes (programmede communicationdu cote du PC pour envoyer leprogrammea executerparle microcontroleur, et programmea executerlui meme).
Le montageproposeestle suivant:
Le circuitestcomposesde3 elementsprincipaux: le68HC11F1,leMAX232, le4066.Quelquescomposantsdiscretssupplementairesdefinissentlesniveauxdequelquesbrochesdu HC11.
Le MAX232a pour role de convertir les signauxTTL provenantdesdeuxbrochesde communicationserie (TxD et RxD) a desniveaux 12V requisparle port RS232du PC.
Le 4066a pour role de passerdu mode“chargementdu programmedu port serie” au mode“executiondu programmestocke enEEPROM”. En effet, le HC11 emetau boot (cf Annexe B, p.25) le caractere0h00sur la brocheTxD, puis semet en ecoutede cequi sepassesur la brocheRxD. Si le caractere0h00estrecu, l’executionpassetout de suiteau debut de l’EEPROM. Si le caracteren’est pas0h00maispasnon plus 0hFF, alorsle HC11 tentede changerde baudrate(frequencede receptiondesdonnees).Enfin, lareceptiond’un caractere0hFFsignifiequ’il fautrecevoir lesoctetset lesplacerenRAM (adressecommenc¸anten0h0000),jusqu’a lafin de la communication.Ainsi, nousconstatonsquecourt-circuiterRxD et TxD aubootpermetdepassertout desuitea l’EEPROM.Cependant,court-circuiterdefinitivementRxD etTxD fait perdrela possibilited’utiliser le portserieulterieurement.Le roledesswitchsanalogiquesdu 4066estde commanderle court circuit pendantseulementles 10 premieresms apresle RESETen commandantlesinterrupteursparun circuit RC (sousle 4066: la capacite de330nF et la resistancede100kΩ. La resistancede10 kΩ au-dessusdu4066sertderesistancedepull-up). Cecourtcircuit estdepluspermisparun strap: si cestrapestouvert, il n’y a pascourtcircuit et leprogrammeestchargeparle port serie.Si cestrapestferme, il y acourtcircuit etdoncsautendebut d’EEPROM.
Enfin, pour le 68HC11, seulementquelquescomposantsdiscretsexternessont necessaires: le quartzet sesdeux capacitesdequelquespF pour le faireosciller (avecun resistanceoptionnellede10 MΩ), desresistancesde pull up (en basdu HC11)sur lesfilsreliesaTxD, RxD etRESET. Il seradeplusnecessaire,encasd’utilisationdesinterruptions,d’ajouterdeuxresistancesdepull upentrelesbrochesIRQ et Vdd et XIRQ et Vdd (sinonle HC11estcontinuellementinterrompuet le programmesebloqueapresexecutiondel’instructioncli ).
Les strapsdisponiblessontdonc : sousle HC11 (horizontal)pour le RESET(il s’agit en fait plutot de court-circuitercesdeuxbrochesavecun objet conducteurpour effectuerle RESET),le strap(horizontal)a gauchedu 4066qui determines’il faut charger leprogrammesurle port serie(ouvert)ou executecelui stockeenEEPROM (ferme),et enfinlesdeuxstraps(verticaux)enhautdu HC11etqui doiventnormalementetrefermespourlancerle HC11enbootstrapmode.
2La memoireutiliseepourstocker le programmeestinclusedansle microcontroleur(contrairementaplusloin ou nousnousefforceronsd’interfaceruneRAM externeavecle 68HC11).
2
Nousprendronssoin, lors de la realisation,a placerdeuxsupportsde jumpersde facon verticaleen hautdu circuit (selectiondumodedefonctionnement: lesdeuxjumpersdoiventetremisenplacepourbooterenbootstrapmode)ainsiqu’un supportdejumperenbasdu circuit pourle Reset(realiseencourt-circuitanttemporairementcesupportdejumperavecun objetconducteurelectriquement).
0000 8E 00 FF lds #0h00FF0003 CE 10 00 ldx #0h10000006 86 FF ldaa #0hFF0008 A7 01 staa 0h01,x
000A 86 00 ldaa #0h00000C A7 00 boucle: staa 0h00,x000E 18 CE FF FF ldy #0hFFFF0012 18 09 wait: dey
0014 26 FC bne wait0016 4C inca0017 20 F3 bra boucle
Cepetit programmedetestfait defiler surle port A (horizontal,enbasdu circuit) la representationbinairedesnombresde0 a 255.Le resultatestvisualisableenconnectantun afficheur7 segmentsou unebarrettedeLEDssurle portA.
2. pourchaquenouvelleconversion,ecrirele numerodu convertisseur(entre0 et 7) qui doit effectuerla conversiondansle registre0x1030(dansl’exempleci-dessous,nousutilisonsle convertisseurnumero3)
3. attendrele signaldefin deconversion(parpolling du registre0x1030).
4. lire la valeurobtenuedansle registre0x1034.
0000 8E 00 FF lds #0h00ff0003 86 FF ldaa #0hff0005 B7 10 01 staa 0h10010008 86 90 ldaa #0h90000A B7 10 39 staa 0h1039000D start:
000D 86 23 ldaa #0h23000F B7 10 30 staa 0h10300012 8D 05 bsr ad_read0014 B7 10 00 staa 0h10000017 20 F4 bra start
Cetexemplelit la valeuranalogiquesurunedesvoiesdu port E (audessusdu 68HC11)- le canal3 - et renvoie la valeursurle portA (auquelonaurarelie unafficheur7 segmentsparexemple).Unevariationdela tensionappliqueesurla brocheduportE (entre0 et5V) doit setraduireparunvariationdela valeuraffichee.
5 La communication serie
Il faut:
1. mettrele portD enmodecommunication
2. determinerla vitesseet le protocoledetransmission
3. unefois cesinitialisationeffectuees,attendrela transmissiond’un caractereet le lire lorsqu’il a ete recu (parpolling).
Danslesprogrammesqui suivent, le 68HC11doit etrerelie parun cabledirect (non-croise) a un PCsur lequeltourneun logicield’emulationdeterminal(typeTerminalsousWindows3.11ou ProcomsousDOS).Dansle premierexemple,le 68HC11affichesurleportA (auquelonaurarelieunafficheur7 segmentsparexemple)la valeurASCII ducaractereenvoyeparle PC(parappuid’unetouchedu clavier du PC par exemple). Dansle secondexemple,le 68HC11envoie en continules caracteresASCII affichable: le terminaldoit continuellementafficherlessignesdeponctuation,leschiffreset l’alphabetenminusculesetmajuscules.Enfin, le dernierexemplecombinecesdeuxapplicationsparattendrel’envoi d’un caracteredu PCet le lui renvoyer.
Exempledelecturedesdonneesvenantsurle port seriedu68HC11:3Nousutiliseronsindifferemmentla notation0xyyyy(notationC),0hyyyy(notationassembleurnon-Motorola68HC11)ou$yyyy(notationPascal)pournoterle nombre
hexadecimalyyyy
3
0000 8E 00 FF lds #0h00FF0003 CE 10 00 ldx #0h10000006 86 FF ldaa #0hFF0008 A7 01 staa 0h01,x000A 1C 28 20 bset 0h28,x,#0h20
000D 6F 2C clr 0h2c,x000F CC 33 0C ldd #0h330C0012 A7 2B staa 0h2B,x0014 E7 2D stab 0h2D,x0016 1F 2E 20 FC rc: brclr 0h2E,x,#0h20,rc
Exempled’emissiondedonneessurle port seriedu 68HC11:
0000 8E 00 FF lds #0h00FF ; stack0003 CE 10 00 ldx #0h1000 ; config registers0006 86 FF ldaa #0hFF ; port A for output0008 A7 01 staa 0h01,x ; |000A 1C 28 20 bset 0h28,x,#0h20; port D OR mode
000D 6F 2C clr 0h2C,x ; set 2400 N81000F CC 33 0C ldd #0h330C ; |0012 A7 2B staa 0h2B,x ; |0014 E7 2D stab 0h2D,x ; |0016 86 20 ldaa #0h20 ; init value at ’ ’0018 1F 2E 80 FC boucle: brclr 0h2E,x,#0h80,boucle
001C A7 2F staa 0h2F,x ; send char001E 4C inca ; next char001F 81 7B cmpa #0h7B ; > ’z’ ?0021 26 F5 bne boucle0023 86 20 ldaa #0h20 ; restart at ’ ’0025 20 F1 bra boucle
Combinaisondesdeuxprogrammesprecedentspourlire unevaleursurle port serieet la renvoyerauPC:
0000 8E 00 FF lds #0h00FF0003 CE 10 00 ldx #0h10000006 86 FF ldaa #0hFF0008 A7 01 staa 0h01,x000A 1C 28 20 bset 0h28,x,#0h20
000D 6F 2C clr 0h2C,x000F CC 33 0C ldd #0h330C0012 A7 2B staa 0h2B,x0014 E7 2D stab 0h2D,x0016 1F 2E 20 FC xm: brclr 0h2E,x,#0h20,xm
001A E6 2F ldab 0h2F,x001C E7 00 stab 0h00,x001E 1F 2E 80 FC rc: brclr 0h2E,x,#0h80,rc0022 E7 2F stab 0h2F,x0024 20 F0 bra xm
6 Mise enEEPROM localeet executiond’un programme
6.1 Aspectlogiciel
L’EEPROM commenceen 0xFE00. Il nousfaut donc, en bootloadermode,charger un programmeen RAM dont la fonction estd’attendrele programmea stocker en EEPROM et executerla procedurede stockage.Nous avonschoisi de realiserla conversionhexadecimal-ASCIIversunevaleurnumeriqueauniveaudu PC(contrairementa l’AN1010 deMotorolaqui realisecettefonctionauniveaudu microcontroleur)etden’envoyerquelesoctetscorrespondantauprogramme(pasdechecksum,pasd’adressededebut ...).
0000 8E 00 FF lds #0h00FF ; stack0003 CE 10 00 ldx #0h1000 ; config registers offset0006 18 CE FE 00 ldy #0hFE00 ; start of EEPROM(cf 4.12 tech man)000A 86 00 ldaa #0h00 ; bprot - block protection disabled000C A7 35 staa 0h35,x ; |000E 1C 28 20 bset 0h28,x,#0h20 ; port D wired OR mode : set port D0011 6F 2C clr 0h2C,x ; set 2400 N810013 CC 33 0C ldd #0h330C ; |0016 A7 2B staa 0h2B,x ; |0018 E7 2D stab 0h2D,x ; |001A 86 FF ldaa #0hFF ; port A as output001C A7 01 staa 0h01,x ; |001E 86 22 ldaa #0h22 ; show ’22’ on display0020 A7 00 staa 0h00,x ; |0022 boucle:0022 1F 2E 20 FC brclr 0h2E,x,#0h20,boucle ; wait for datum0026 E6 2F ldab 0h2F,x ; store it in B0028 E7 00 stab 0h00,x ; echo on port A002A 86 16 ldaa #0h16 ; reset 1 byte002C 8D 12 bsr program ; write to location in EEPROM002E 86 02 ldaa #0h02 ; store 1 byte
0030 8D 0E bsr program ; write to location in EEPROM0032 18 08 iny ; goto next location in EEPROM0034 18 8C FF BF cpy #0hFFBF ; until we get to 0hFFBF0038 26 E8 bne boucle ; get next datum if not finished003A 86 08 ldaa #0h08 ; show ’8’ on display003C A7 00 staa 0h00,x003E 20 FE fin: bra fin
Le programmeee.asm dontle roleestderecevoir desdonneessurle port serie(2400,N81)et delesstocker enEEPROM.
6.2 Aspectmateriel
Nousavonsvu plus hautqu’uneserie d’interrupteursanalogiquesavaientete inclus sur la carte. Leur fonction estd’eventuellementpermettredecourt-circuiterpendantuntempsbref leslignesRxDetTxD decommunicationdemicrocontroleur. Eneffet, si a l’allumagele 68HC11estenbootstrapmode,il attendde recevoir un signalsur la brocheRxD et agit enconsequence.Si cesignalest0xFF, lebaudrateestcorrectet l’acquisitiondu programmea stockercommence.Si cesignalest0x00, l’executionsauteendebut d’EEPROM :le programmequi avait ete stocke la anterieurementestexecute. Danslesautrescas,le microcontroleurchangele baudrate.
Or a l’allumage,la premiereoperationduprogrammedubootloaderestd’envoyer0x00surla brocheTxD. Ainsi, encourt-circuitanttemporairementRxDet TxD, nouslanconsle programmeenEEPROM plutot qu’attendrel’acquisitiond’un programmea executerparle port serie.
Le court-circuitse fait simplementen connectantun circuit RC sur la commanded’un desinterrupteursanalogiqueselle memeconnectantla commanded’un autreinterrupteuranalogiquea la masse.La commandede cettesecondeporte logiqueestcependantmaintenuea l’ etathautparuneresistancedepull-upde10kΩ. Au reset,le niveaudela brocheRESETestbas.Cettebrocheestrelieeala commandedu premierinterrupteuranalogiquequi estdoncouvert,et la resistancedepull-upmaintientle secondinterrupteurferme,connectantTxD et RxD. Le circuit RC secharge, fermantle premierinterrupteurqui relie la commandedu secondinterrupteura lamasseet ouvredoncle contactentreTxD et RxD.
6.3 Aspectpratique
Le programmehc11.pas aeteprevupoureventuellementaccepterdeuxarguments.Nousavonsjusquela fourni unseulargument,leprogrammeenhexadecimala chargerdansla RAM du 68HC11.Si nousdonnonsdeuxargument,qui sontdansl’ordre le programme
4
ee.out vu plus haut,suivi du nom du programmea chargeren EEPROM (nomme ici prg.out , hc11.exe ee.outprg.outchargeradansun premiertempsee.asm dansla RAM du HC11 ee dont le role estd’attendrela receptionde prg.out sur le port serie etde le stocker enEEPROM. Cecisefait parun delai d’unesecondeentrela fin de l’ emissiondeee.out et le debut de l’ emissiondeprg.out (delai suffisantpour demarreree). Il faudradeplus pensera relocaliser, a la compilation,prg.asm a l’adressede debutdel’EEPROM (0hFE00,puisquel’EEPROM va de0hFE00a 0hFFBF)par l’ajout desdeuxlignessuivantesendebut deprogramme:.area code (ABS) et .org 0hFE00 .
7 Branchementd’une RAM externe
Dansle casdela connexion d’un composantexterne,il fautfairepasserle 68HC11enmodeetendudefacon a cequelesportsF, B etC soientutilisescommebusd’adresse(octetsdepoidsfaibleet fort) et busdedonnees(sur8 bits), et pour faire fonctionnerle signald’ecritureR/W#. Cetteoperationsefait de facon logicielle : eneffet, il nousfaut tout d’abordetreenbootstrapmodepourchargerleprogrammeenRAM internedu 68HC11avantdepouvoir accedera la RAM externe.
Le branchementdela RAM sefait facilementenreliantlesbusd’adresseetdedonneeset,poureviterlesrisquesdeconflit aveclesmemoiresinternes,nousavonsrelie lessignauxd’adresse13 et 14 auxsignauxd’activationdela RAM pourfairecommencerl’espaceadressabledecelle-cia 0x2000.
0000 8E 00 FF lds #0h00FF0003 CE 10 00 ldx #0h1000 ; config regis-ters offset0006 18 CE 20 00 ldy #0h2000 ; RAM offset000A 86 FF ldaa #0hFF ; set A port for output000C A7 01 staa 0h01,x ; |000E 1C 28 20 bset 0h28,x,#0h20; set SPI clock rate0011 6F 2C clr 0h2C,x ; 2400 bauds, N81
0013 CC 33 0C ldd #0h330C ; |0016 A7 2B staa 0h2B,x ; |0018 E7 2D stab 0h2D,x ; |001A 86 E5 ldaa #0hE5 ; set extended mode001C A7 3C staa 0h3C,x ; |001E 1F 2E 20 FC xmi: brclr 0h2E,x,#0h20,xmi; read char0022 E6 2F ldab 0h2F,x ; |0024 E7 00 stab 0h00,x ; store on port A
0026 18 E7 00 stab 0h00,y ; store in RAM0029 18 E6 00 ldab 0h00,y ; read from RAM002C 18 08 iny ; goto next RAM address002E 1F 2E 80 FC rec: brclr 0h2E,x,#0h80,rec; echo char to serial port0032 E7 2F stab 0h2F,x ; |0034 7E 00 1E jmp xmi
Cecircuit peutfacilementetremodifiepoury adapteruneRAM de32K 62256: relever lesbroches1, 20 et 22 dela RAM et relier1 a la broched’adresse14 du 68HC11tandisquelesbroches20 et 22 sontrelieesa la massepourtoujoursactiver la RAM.
8 Resultat final : acquisition dedonnees,stockageenRAM puis envoiepar port serie
initialise le portdecommunicationet lesconvertisseursA/D puispasseenmodeetendupourpouvoir accedera la RAM externe.
lit periodiquementla valeuranalogiquesur le convertisseur3 et stocke la valeurobserveeen RAM externetout en affichantlavaleurlue surle port A.
unefois la RAM externepleine,attendun caractere(quelconque)sur le port serie, et affiche “00” sur le port A pour indiquerl’attente.
envoie lesdonneessur le port serie lorsquela requetea ete faiteet affichela valeurdu caractererecu sur le port A pourindiquerquela transmissionestencours.transmission.
Il faudraserapportera l’annexe C pour le programmeen Turbo Pascalde receptiondesdonneesde la RAM li eeau HC11 versl’IBM PCunefois l’acquisitionfinie.
0000 8E 01 50 lds #0h0150 ; stack0003 CE 10 00 ldx #0h1000 ; config regis-ters offset0006 18 CE 20 00 ldy #0h2000 ; RAM offset000A 86 FF ldaa #0hFF ; port A: output000C A7 01 staa 0h01,x ; |
000E 1C 28 20 bset 0h28,x,#0h20; port D OR mode0011 6F 2C clr 0h2C,x ; 2400 bauds, N810013 CC 33 0C ldd #0h330C ; |0016 A7 2B staa 0h2B,x ; |0018 E7 2D stab 0h2D,x ; |
001A 86 E5 ldaa #0hE5 ; set extended mode001C A7 3C staa 0h3C,x ; |001E 86 90 ldaa #0h90 ; en-able A/D converters0020 A7 39 staa 0h39,x ; store OP-TION register
5
0022 CE 3F FF ad: ldx #0h3FFF0025 09 loop: dex ; wait be-fore next conversion0026 26 FD bne loop0028 CE 10 00 ldx #0h1000002B 86 23 ldaa #0h23 ; start conver-sion on AD3002D A7 30 staa 0h30,x ; |002F 8D 30 bsr ad_read0031 18 A7 00 staa 0h00,y ; store in RAM0034 A7 00 staa 0h00,x ; echo on port A0036 18 08 iny ; goto next RAM address0038 18 8C 24 00 cpy #0h2400 ; 256 values
003C 26 E4 bne ad ; get next da-tum if not finished003E 86 00 ldaa #0h00 ; displ. re-sult of convert on A0040 A7 00 staa 0h00,x ; |
0042 1F 2E 20 FC rcv: brclr 0h2E,x,#0h20,rcv; wait for 1 char0046 A6 2F ldaa 0h2F,x ; dis-play it on portA0048 A7 00 staa 0h00,x
; read from RAM0051 1F 2E 80 FC snd: brclr 0h2E,x,#0h80,snd; echo char to serial port0055 A7 2F staa 0h2F,x ; |0057 18 08 iny ; inc RAM @0059 18 8C 24 00 cpy #0h2400 ; end of filled RAM ?005D 26 EF bne read_ra ; get next datum005F 20 FE fin: bra fin
0061 A6 30 ad_read:ldaa 0h30,x0063 2A FC bpl ad_read ; wait convert end0065 A6 34 ldaa 0h34,x ; return res in A0067 39 rts
0
50
100
150
200
250
300
0 100 200 300 400 500 600
"out.dat"
0
20
40
60
80
100
120
140
160
180
0 200 400 600 800 1000 1200
"out.dat"
Exemple d’acquisition avec un fil du bus d’adressede la RAMdeconnecte (@5)
La selectionde l’esclave a qui le messageestenvoye sefait par l’activationde SS# qui, au lieu d’etreconnecteea la masse,estrelieea unebrochedu port B. Dansnotreexempleou nousavonssimplementun maıtre envoyantun messagea un seulesclave, nous
6
avonsdirectementrelie SS#del’esclave a la masse.Lesautresconnexionsconsistenta relier directementMOSI, MISOet SCK(signald’horloge)ainsiquelesmassesdesHC11communiquantentreeux.
Lesprogrammesqui suiventontpourbut detesterla communicationSPI: le maıtre emetdansunpremiertempslesnombresde0 a255surle portSPI(etsursonportA pourverification)et l’esclaveaffichesursonportA lesvaleurslues.LesdeuxafficheursconnectesauxportsA desortiedumaıtreetdel’esclavedoiventmontrerlesmemesvaleurs.Dansundeuxiemetemps,le maıtre lit desvaleurssurle port serieet lesaffichesursonport A toutenlestransmettanta l’esclave. Cesecondprogrammepermetdeverifierqu’il estpossibled’utiliser simultanementla communicationRS232etSPIqui sonttoutesdeuxconnecteesauport D dumaıtre.
0000 8E 00 FF lds #0h00FF0003 CE 10 00 ldx #0h10000006 86 FF ldaa #0hFF ; set port A for output0008 A7 01 staa 0h01,x000A 96 2F ldaa 0h2F ; SS# hi, SCk lo, mosi hi000C A7 08 staa 0h08,x ; store port D000E 86 38 ldaa #0h38 ; - - 1 1 1 0 0 00010 A7 09 staa 0h09,x0012 86 57 ldaa #0h57 ; 7=0111 : polarity, phase, rate1, rate0
; 5=0101 : int, enable, open drain, master0014 A7 28 staa 0h28,x ; set SPCR
0016 86 00 ldaa #0h00 ; start : counter=0
0018 A7 2A snd: staa 0h2A,x ; send datum001A A7 00 staa 0h00,x001C E6 29 wait: ldab 0h29,x001E 2A FC bpl wait ; wait until xfer finished0020 BD 00 26 jsr delay0023 4C inca0024 20 F2 bra snd
0026 18 CE FF FF delay: ldy #0hFFFF002A 18 09 wait_d: dey002C 26 FC bne wait_d002E 39 rts
Master: emissiondesnombresde0 a 255surle port SPI(D) et A.
0000 8E 00 FF lds #0h00FF0003 CE 10 00 ldx #0h10000006 96 2F ldaa 0h2F ; SS# hi, SCk lo, mosi hi0008 A7 08 staa 0h08,x ; store port D000A 86 38 ldaa #0h38 ; - - 1 1 1 0 0 0000C A7 09 staa 0h09,x ; store DDRD000E 86 47 ldaa #0h47 ; 7=0111 : polarity, phase, rate1, rate0
; 5=0101 : int, enable, open drain, master0010 A7 28 staa 0h28,x ; set SPCR0012 86 FF ldaa #0hFF
0014 A7 01 staa 0h01,x ; port A for output0016 86 88 ldaa #0h880018 A7 00 staa 0h00,x ; show 88 on port A while waiting001A rcv:001A E6 29 wait: ldab 0h29,x001C 2A FC bpl wait ; wait until xfer finished001E A6 2A ldaa 0h2A,x ; send datum0020 A7 00 staa 0h00,x0022 20 F6 bra rcv
Slave : receptiondessignauxsurle portSPIet affichagesurle portA
0000 8E 00 FF lds #0h00FF0003 CE 10 00 ldx #0h10000006 86 FF ldaa #0hFF ; set port A for output0008 A7 01 staa 0h01,x
; 5=0101 : int, enable, open drain, master0014 A7 28 staa 0h28,x ; set SPCR
; SERIAL PORT SETUP
; bset 0h28,X,#0h20 ; ne fontionne pas si D port en open-drain0016 6F 2C clr 0h2c,x0018 CC 33 0C ldd #0h330C ; set baudrate of serial port to 2400 baud, N81001B A7 2B staa 0h2B,x001D E7 2D stab 0h2D,x
001F 1F 2E 20 FC rs_rc: brclr 0h2E,x,#0h20,rs_rc; receive from RS2320023 E6 2F ldab 0h2F,x0025 E7 2A snd: stab 0h2A,x ; send datum to SPI0027 E7 00 stab 0h00,x0029 E6 29 wait: ldab 0h29,x002B 2A FC bpl wait ; wait until xfer finished002D 20 F0 bra rs_rc
Master: receptiondesvaleursASCII surle port seriepuisechosurle port SPIetA.
Les 3 bits de controle sont,de la brochede polarisation(versle bord de l’afficheur)versles brochesdu busde donnees: RSquideterminesi la valeursurle busdedonneesestuneinstruction(0) ouunedonnee(1), R/Wqui determinele sensdela transaction(0 pouruneecriture,1 pourunelecture),et E (enable)qui doit etrea 1 pour rendrel’afficheuractif. Suiventensuiteles lignesdedonneesencommenc¸antdela ligne0 (poidsle plusfaible)jusqu’ala ligne7 (poidsle plusfort, aubordduconnecteur).Enmodedecommunication4 bits,seulslesligne D4-D7sontutilisees.
Le modele plussimpled’utilisationestsur8 bitsdedonnees.Nousconnectonsle busdedonneesauportB du68HC11et le busdecontroleauport A. Lestableauxci-dessousresumentle brochage,lescommandesa envoyersurlesbusdedonneeset decontrole,ainsiquelesvaleurspossiblesdesvariablesdeconfigurationdel’ ecranet leur assignation(entreparentheses)dansnosexemples.
1 2 3 4 5 6 7 - 14Vss Vcc=+5V Vee 0V RS R/W E D0 - D7
Brochagedel’afficheurLCD (la broche1 estla plusprochedu borddel’afficheur)
7
RS R/W DB7 DB6 DB5 DB4 DB3 DB2 DB1 DB0ClearDisplay 0 0 0 0 0 0 0 0 0 1EntryModeSet 0 0 0 0 0 0 0 1 I/D SDisplayON/OFF 0 0 0 0 0 0 1 D C BFunctionSet 0 0 0 0 1 DL N F * *SetDD RAM address 0 0 1 A A A A A A AReturnHome 0 0 0 0 0 0 0 0 1 *CursorandDisplayShift 0 0 0 0 0 1 S/C R/L * *SetCGRAM address 0 0 0 1 A A A A A AReadbusyflag andaddress 0 1 BF A A A A A A AWrite datato CGor DD RAM 1 0 D D D D D D D DReaddatafrom CGor DD RAM 1 1 D D D D D D D DD (0) : displayon(1)/off(0)C (0) : curseuron(1)/off(0)B (0) : curseurclignotanton(1)/off(0)
DL (1) : interfacesur8 bits (4 bits si DL=0)N (1) : 2 lignesF (0) : font 5 x7
Nousn’utiliseronsqueles fonctionspresenteesdansla partiesuperieuredu tableau.Les fonctionsde la partieinferieureservent amodifierlescaracteresdisponiblessurl’afficheuret a lire l’ etatdu controleurdel’afficheur.
; goto a wanted position and display a char (automat-icly shifts right after)
; input : char value in register B and position in register A0042 8A 80 gotoxy: oraa #0h80 ; reg A -> set @ to reg A0044 A7 04 staa 0h04,x0046 8D E7 bsr funct0048 E7 04 stab 0h04,x004A 8D 01 bsr char004C 39 rts
; data bus (port A) a ete set to char | RS = 1 (draw char); input : char value in register B
; attente0060 A7 00 delai: staa 0h00,x ; met le registre A sur le port A0062 86 01 ldaa #0h010064 18 CE 2F FF dedans: ldy #0h2FFF ; ldab #0h06 et ldy #0hFFFF => 693 ms
; attente0032 A7 00 delai: staa 0h00,x ; met le registre A sur le port A0034 18 CE 3F FF ldy #0h3FFF0038 18 09 dedans2:dey003A 26 FC bne dedans2003C 39 rts
; data bus (port A) a ete set to action | RS = 0 (set function); input : function in register A
; goto a wanted position and display a char (automat-icly shifts right after)
; input : char value in register B and position in register A006B 8A 80 gotoxy: oraa #0h80 ; reg A -> set @ to reg A006D A7 04 staa 0h04,x006F 8D CC bsr funct0071 E7 04 stab 0h04,x0073 8D 01 bsr char0075 39 rts
; data bus (port A) a ete set to char | RS = 1 (draw char); input : char value in register B
entredeuxreprogrammationsafin denepasre-initialisera chaquefois l’ ecranLCD).
9
11 Les interruptions
11.1 Les interruptions materiellesIRQ#
11.1.1 Aspectmateriel
Modificationsau circuit initial : mettrele bit I du registrede controle par cli va rendreles interruptionsmateriellesactives. Pardefaut, toutesles sourcesinternesau 68HC11d’interruptionsmaterielles(principalementles timers)sont inactives. Il nousfaut deplusdesactiver lesbrochesd’interruptionsmateriellesXIRQ et IRQ (activesparun signalauniveaubas)enajoutantdeuxresistancesde pull-up entrel’alimentation(Vdd=+5V) et cesbroches.L’activationde l’interruption materielle IRQ sefait alorsen mettantcettebrocheauniveaubas(parexempleenfermantun interrupteurdansnotreexemple).
11.1.2 Aspectlogiciel
Principedespseudo-vecteurs: les vecteursd’interruptionssontsituesen ROM et ne sontdoncpasmodifiablespour pointervers lafonctiondel’utilisateur. Cesvecteurspointentversdespseudo-vecteurspre-definisqui sonteuxsituesenRAM. Il s’agit enfait detroisoctetsreservesa l’action aeffectuerlorsquel’interruptionestdeclenchee: uneinstructionJMP(0x7E)suivi des2 octetsdel’adressedela fonctiondel’utilisateur. La listedesadressesdespseudo-vecteursestdisponiblep. 3-18du68HC11ReferenceManualdeMotorola.
Le premierexempleque nousproposonsici sert a bien identifier la syntaxe permettantde recuperer l’adresseou se situe uneprocedure,et de voir commentmanipulercetteadresse.Dans le programmeci-dessous,la procedurenommee irq commenceal’adresse0x0026. Nousallonscherchercetteadresse,la stocker dansle registre16 bits X, puis transfererX dansD (qui esten faitla concatenationde A et B) de facon a pouvoir successivementaffichersur le port A les valeursdesregistresA et B et ainsipouvoirvisualiser(parexemplesurunafficheur7 segmentsconnecteauportA) l’adressedela procedure(cetteetapeintermediaire- le passagedeX a D - estobligatoirepour pouvoir visualiserla valeurstockeedansX. Il n’estpaspossibled’envoyer directementX, qui estsur16 bits, surun desportsd’entree-sortie8 bits). Il fautprendresoin,lors dela recherchedel’adressedela procedureirq , d’utiliser lasyntaxe ldx #irq qui renvoie l’adresseou setrouve irq (0h0023dansnotrecas),et nonpasldx irq qui renvoie le contenudel’octet setrouvanta l’adresseirq (0x86dansnotrecas,qui estl’opcodedel’instruction ldaa ).
IRQ
XIRQ
0000 8E 00 FF lds #0h00FF0003 86 FF ldaa #0hFF ; DDRA : output0005 B7 10 01 staa 0h10010008 86 7E ldaa #0h7E ; opcode de JMP000A 97 EE staa 0h00EE ; interrupt vector-1=JMP opcode000C CE 00 23 ldx #irq ; ISR de IRQ# : ldx irq=00 86 (opcode de jmp)->ldx #irq000F DF EF stx 0h00EF ; interrupt vector0011 CE 10 00 ldx #0h1000
; cli ; enable interrupts0014 18 DE EF ici: ldy 0h00EF ; BFF2=00 ; BFF3=EE ; 00EE=7E ; 00EF=86 ; F0=00; F1=240017 18 8F xgdy ; echange X et D0019 A7 00 staa 0h00,x ; afficher alternativement001B 8D 09 bsr delai ; ... A et B pour montrer001D E7 00 stab 0h00,x ; ... ce qui etait dans X001F 8D 05 bsr delai0021 20 F1 bra ici
0026 18 CE FF FF delai: ldy #0hFFFF002A 18 09 wait: dey002C 26 FC bne wait002E 39 rts
Programmedelecturedela valeurstockeedansunpseudo-vecteurdu 68HC11etaffichagesurle portA (verificationdela programmationdel’adressedela fonctiondegestiondesinterruptions)
L’instructioncli metle bit I du registredecontrole a 0 et metainsienmarchelesinterruptionsmaterielles.Application au casde la re-initialisationd’une variablepar uneinterruptionmaterielle. Il estnecessairede passerpar unezone
memoireen RAM car l’appel a une fonction provoqueun empilementdesregistresqui serontensuitere-initialises a leurs valeursinitiales lors de l’instruction rti . Ceprogrammefait defiler lesnombresbinairessur le port A, et remetle compteura 0 chaquefoisqu’uneinterruptionmaterielleestprovoqueeparla fermeturedel’interrupteur.
0000 8E 00 FF lds #0h00FF0003 86 FF ldaa #0hFF ; DDRA : output0005 B7 10 01 staa 0h10010008 86 7E ldaa #0h7E ; opcode de JMP000A 97 EE staa 0h00EE ; interrupt vector-1=JMP opcode000C CE 00 24 ldx #irq ; ISR de IRQ# : ldx irq=00 86 (opcode de jmp)->ldx #irq000F DF EF stx 0h00EF ; interrupt vector0011 CE 10 00 ldx #0h10000014 0E cli ; enable interrupts0015 86 00 ldaa #0h000017 97 E0 staa 0h00E00019 96 E0 ici: ldaa 0h00E0001B 4C inca
001C 97 E0 staa 0h00E0001E A7 00 staa 0h00,x0020 8D 07 bsr delai0022 20 F5 bra ici
0024 86 00 irq: ldaa #0h00 ; PAS ldaa #0h00 directmt car rti pop regs0026 97 E0 staa 0h00E00028 3B rti
0029 18 CE FF FF delai: ldy #0hFFFF002D 18 09 wait: dey002F 26 FC bne wait0031 39 rts
10
Exemplederemisea 0 parinterruptionmaterielled’un compteur: le portA affichelesvaleurscroissantesd’un constanted’un compteurqui estremisa 0 parla fermeturedel’interrupteurreliantla brocheIRQ a la masse.
11.2 Les interruptions materiellesli eesaux timers
Il fautpenser, pour touteutilisationdesinterruptionsmateriellesli eesaux timersinternesdu HC11,a effectuerla modificationsur lesbrochesIRQ et XIRQ (enlesreliantvia uneresistanced’environ 5 kΩ a l’alimentationVdd).
L’utilisationducompteurpresenteeici permetderealiserunschedulerlorsqueplusieurstachesdoiventetreexecuteessequentiellementavec une periodicite donnee, ou une modulationen largeur de pulse (PWM). Dans le but d’avoir le tempsde voir le compteurosciller, nousavons decide d’abaisserla frequencedu timer au 16eme de sa valeur par defaut en mettantPR1 et PR0 du registreTMSK2 (0h1024)a 1. Le compteurva de 0 a 65536 en 524.3/2ms (i.e. 4 µs par tic d’horloge). On le fait compterde 1 a0hDFFF=53248+3840+240+15=57343soit229.4msentredeuxincrementsducompteur.
La valeurdu compteur, incrementea chaqueinterruption,estafficheesurlesportsA et B. La broche6 duportA oscilledeplusa lafrequencedesinterruptions(sortiePWM).
0000 8E 00 FF lds #0h00FF ; stack0003 86 FF ldaa #0hFF ; set port A for output0005 B7 10 01 staa 0h1001 ; | on affiche cpt val sur A et B, et A6=PWM0008 86 7E ldaa #0h7E ; opcode de JMP000A 97 DC staa 0h00DC ; interrupt vector of OC2000C CE 00 2E ldx #int ; ISR de int000F DF DD stx 0h00DD ; interrupt vector+1 de OC2 = int @
0011 CE 10 00 ldx #0h10000014 1C 24 03 bset 0h24,x,#0h03 ; prescaler : ici, divise la vitesse par 16
0017 86 40 ldaa #0h40 ; only work on OC_2_0019 A7 23 staa 0h23,x ; clear any pending flag001B A7 22 staa 0h22,x ; enable OC2 interrupt001D 86 40 ldaa #0h40 ; intOC2 : 0h00 -> do not affect port A pin001F A7 20 staa 0h20,x ; 0h40 -> toggle output of port A6 on int
0021 86 00 ldaa #0h00 ; initialisation du compteur0023 97 E0 staa 0h00E0 ; octet en RAM stockant la valeur a afficher0025 0E cli ; enable interrupts : check pull ups on IRQ & XIRQ0026 96 E0 ici: ldaa 0h00E00028 A7 04 staa 0h04,x ; display counter value on port B002A A7 00 staa 0h00,x ; display counter value on port A002C 20 F8 bra ici
002E 96 E0 int: ldaa 0h00E0 ; PAS inca directmt car rti pop regs0030 4C inca ; incremente le compteur0031 97 E0 staa 0h00E0 ; stocke le result0033 CC DF FF ldd #0hDFFF ; 1/2 delay PWM<- duree entre 2 transitions0036 E3 12 addd 18,x ; add value of counter 2 to delay0038 ED 12 std 18,x ; store in counter -> time of next interrupt003A 86 40 ldaa #0h40003C A7 23 staa 0h23,x ; clear flag by setting 0100 0000 (OC2)003E 3B rti
11.3 Programmation multi-t a chesau moyendesinterruptions - l’instruction WAI
Jusqu’ici,nosprogrammesn’etaientcapablesqued’effectueruneoperationa la fois : soit faire l’acquisitionsde donneesprovenantdesconvertisseursanalogiques-numeriques,soit transmettredesdonneessur le port serie,soit attendrela receptionde donneessur leportRS232.L’utilisation desinterruptionsdansl’exemplequi suit vadonnerl’impressionquele 68HC11estcapabledesimultanementincrementerun compteurdefacon periodiquetout enetanta l’ ecoutedu port serie. De plus,mettretoutesles fonctionsa executerparle microcontroleursousinterruptionpermetuneeconomied’energieparl’ executiondel’instruction WAI lorsquequ’aucunetachen’estaexecuter. Cetteinstructionmetle 68HC11enmodeveille qui consommemoinsdecourant.Le microcontroleurestreactive lorsqu’uninterruptionqui a ete autorisee(dansnotrecasle timer, la receptiond’un messagesur le port serie ou l’activation de l’interruptionmateriellesurla brocheIRQ) estdeclenchee.
0000 8E 01 20 1 lds #0h0120 ; set stack0003 CE 10 00 2 ldx #0h10000006 86 00 3 ldaa #0h00 ; port A setup for input0008 A7 01 4 staa 0h01,x ; |
5000A 86 7E 6 ldaa #0h7E ; opcode de JMP000C 97 C4 7 staa 0h00C4 ; interrupt vector-1=JMP opcode000E CE 00 2F 8 ldx #irq ; ISR de IRQ# : ldx irq=00 86 (op-
28002F 1F 2E 20 FC 29 irq: brclr 0h2E,x,#0h20,irq ; reset serial port0033 A6 2F 30 ldaa 0h2F,x ; load received character0035 B7 01 00 31 staa 0h0100 ; store in memory0038 A7 05 32 staa 0h05,x ; display on port F003A 3B 33 rti ; end of interrupt service routine
Exempled’interruptiondeclencheea la receptiond’un caracteresurle port serie: le compteurestremplace parla valeurASCII du caractererecu.
0000 8E 01 20 1 lds #0h0120 ; set stack0003 CE 10 00 2 ldx #0h10000006 86 00 3 ldaa #0h00 ; port A setup for input0008 A7 01 4 staa 0h01,x ; |
56 ; setup serial port interrupt routine
000A 86 7E 7 ldaa #0h7E ; opcode de JMP000C 97 C4 8 staa 0h00C4 ; interrupt vector-1=JMP opcode <- se-
A Programmed’envoi desdonneesdu PC vers le 68HC11: hc11.pas (Turbo Pascal(7), DOS)
Le programmehc11.pas fonctionnedela faconsuivante(routineRunTerminal() : le programmeenvoietoutd’abordle caractere0hFFpourprevenirle HC11quele programmeseratransfereparle portserie,puisouvrele fichierqui estpasseenpremierargument.Cefichier contient,sousformedecaracteresASCII, unesuitedenombreshexadecimaux.Le programmeprendchaquepairedecaracteres(separesparun espaceou un retourchariot),les interpretecommeun nombreenhexadecimal,et envoie le resultatsur le port serie. Sideuxargumentssontpassesenligne decommande,le programmesupposequele premierprogrammeestee.out (dont le role estderecupererlesdonneessur le port seriepour lesstocker en EEPROM) et relancedoncl’ emissiondesdonneesstockeesdansle secondfichier apresavoir attendu1 spourpermettrel’executiondeee .
Le role deceprogrammeestdoncd’initialiser le port serie (choisidanscetexemplecommeCOM1 avecunevitessede transmis-sion de 2400bauds)et d’envoyer un programmestocke commeunesuitede valeurshexadecimalesdansla RAM du 68HC11. Si leprogrammeenvoye en RAM est le logiciel charge de stocker desdonneesen EEPROM, le passageen secondargumentdu nom duprogrammea chargerdansl’EEPROM du 68HC11lancerala routinede transmissiondecesecondprogrammeapresavoir execute lepremierprogrammestockeenRAM.
La procedureRunTerminal pourra etre modifie selon les besoinsde communicationpar le port serie, par exemplepour larecuperationdesdonneesluesenRAM parle 68HC11et renvoyeesauPCparle port serie.
ADDITIONS & MODIFICATIONS by jmfriedt* removed the interactive terminal part* added an ugly delay() in the sndchar() procedure
program TERMINAL;
******************************************************************* ******* TERMINAL Turbo Pascal 7.0 Demo Programm Written 1995 by Stephan A. Maciej Internet: [email protected] For any questions, please mail to [email protected] ! WWW:http://www.muc.de/˜stephanm ******************************************************************* ******* This program is for demonstration purpose only. Any commercial use with- out the written permission of the author is illegal. Please report bugs, corrections or any other ideas to [email protected]. You are allowed to distribute this program as often as you want as long as you do not change it or edit it anyway. The author is not responsible for any damage or destruction caused - directly or indirectly - by this program. ******************************************************************* *******
uses Crt;
constTxDataReg = 0; transmitter data register RxDataReg = 0; reciever data register DivLow = 0; divisor latch, low byte DivHigh = 1; divisor latch, high byte IntrEnable = 1; interrupt enable register IntrId = 2; interrupt identification register FifoCtrl = 2; first-in/first-out buffer controller LineCtrl = 3; line controll register ModemCtrl = 4; modem controll register LineStatus = 5; line status register ModemStatus = 6; modem status register ScratchReg = 7; scratch pad (free useable)
constQueueLen = 1024; Length of a queue in bytes
type The TQueue type TQueue = record
Content: array[0..QueueLen - 1] of byte;Start: word;Stop: word;end;
type The TQuadString type TQuadString = string[4]; For the Hex-function
var The two queues, one for incoming characters, the other for outgoing characters. InQueue: TQueue; The two queues: one for input buffering, OutQueue: TQueue; the other for output buffering
constSpeedCount = 19; Number of valid speeds stored below
constAllowedSpeeds: array[0..SpeedCount] of longint =
Just add any other speeds supported by your UART/Modem - don’t forget to increase the SpeedCount
var Some global variables... PortNr: byte; Number of the used port (1, 2 etc.) PortBase: word; I/O base address of the used port Speed: longint; Speed in baud UARTType: byte; UART type (one of the UART_xxxx constants UsedIRQ: byte; The number of the used IRQ
procedure SendEOI; assembler; Send a EOI to the Interrupt Controller asm
mov al, 20hout 20h, al
end;
function GetPortBase(N: byte): word; assembler; Read the I/O base address of the desired port from the BIOS data segment asm
Load the segment address of the BIOS data segment into ES mov ax, 0040hmov es, ax Calculate the offset of the I/O port base address xor ax, axmov al, Ndec alshl ax, 1mov si, ax Read the desired value and return mov ax, es:[si]
end;
procedure SetIntVec(N: byte; P: pointer); assembler; Set an interrupt vector to the given address asm
push ds Just use the MS-DOS function 25h to set the vector mov ah, 25hmov al, N ds:dx contains the vector to set lds dx, Pint 21hpop ds
end;
function GetIntVec(N: byte): pointer; assembler; Get the interrupt vector asm
push es Use the MS-DOS function 35h to read the vector mov ah, 35hmov al, Nint 21h Move the vector from es:bx to dx:ax mov ax, bxmov dx, espop es
end;
12
procedure ResetQueue(var Q: TQueue); Resets a Queue begin
Q.Start := 0;Q.Stop := 0;
end;
procedure PutQueueByte(var Q: TQueue; B: byte); Put a byte into the Queue begin
Put the byte into the Queue before incrementing the Queue end Q.Content[Q.Stop] := B;
Now increment the Queue end position. When Q.Stop reaches QueueLen, be sure you don’t increment Q.Stop but wrap it around to 0 again ! inc(Q.Stop);if (Q.Stop = QueueLen) then
Q.Stop := 0;
end;
function GetQueueByte(var Q: TQueue; var B: byte): boolean; Get a byte out of the Queue begin
if (Q.Stop = Q.Start) then If the Queue is empty, just return false. Don’t set B anyway. GetQueueByte := false
elsebegin
Queue is not empty: return true. GetQueueByte := true;
Get the first byte out of the Queue and return it in B. B := Q.Content[Q.Start];
Now increment the Queue position. Be sure to wrap it to zero if the Q.Start field reaches the QueueLen constant. inc(Q.Start);if (Q.Start = QueueLen) then
Q.Start := 0;end;
end;
procedure SerialInterrupt; interrupt; This procedure handles any incoming events from the UART. var
Id: byte;Trash: byte;
beginrepeat
Now read the Interrupt Identification register Id := Port[PortBase + IntrId];
Check if there’s any pending interrupt. if ((Id and 1) = 0) then
begin
Now select the event. case ((Id and 6) shr 1) of
$03: The Line Status register changed. begin
Just read the LSR to clear the event. Trash := Port[PortBase + LineStatus];
end;$02:
Data arrived at the UART. begin
Read out the data from the RxD register and store it in the incoming Queue. Trash := Port[PortBase + RxDataReg];PutQueueByte(InQueue, Trash);
end;$01:
The TxD register is empty. begin
If there’s any byte in the outgoing Queue, send it to the UART, else disable this interrupt. if (GetQueueByte(OutQueue, Trash)) then
Port[PortBase + TxDataReg] := Trashelse
Port[PortBase + IntrEnable] := $0D;
end;$00:
The Modem Status register changed. begin
Just read the MSR to clear the event. Trash := Port[PortBase + ModemStatus];
end;end;
end;
Handle all interrupts ! Just check if there’s one more interrupt pending.
until ((Id and 1) = 1);
Now tell the PIC our interrupt handler has finished it’s work. SendEOI;
end;
procedure SendChar(C: char); Send a char to the modem begin
Put the character into the outgoing queue. PutQueueByte(OutQueue, byte(C)); Enable the "Transmitter register empty" interrupt Port[PortBase + IntrEnable] := $0F;
end;
constUART_Bad = 0; Bad UART: not working or unidentifieable UART_8250 = 1; Standart 8250 UART UART_16450 = 2; 16450 UART (faster than 8250) UART_16550 = 3; 16550 UART (with buggy 16-byte FIFO) UART_16550A = 4; 16550A UART (with working FIFO)
function GetUARTType(Base: word): byte; assembler; Check which UART type is assigned to the appropriate port asm
First difference: The 16450 has a scratch register which is readable and writeable. Check if it’s there. If not, we’ve
@@1: Now check out if the UART has got a FIFO. If it has none, it’s a 16450, if it has one but it’s not working it’s a 16550. The UART will be identified as a 16550A if the FIFO is working. mov dx, Baseadd dx, FifoCtrlmov al, 01hout dx, alnopmov dx, Baseadd dx, IntrIdin al, dxand al, 0C0hcmp al, 0C0hjne @@2mov al, UART_16550Ajmp @@5
@@2: cmp al, 80hjne @@3mov al, UART_16550jmp @@5
@@3: cmp al, 0jne @@4mov al, UART_16450jmp @@5
@@4: mov al, UART_Bad@@5: nopend;
procedure UpCaseStr(var S: string); assembler; Convert all chars in a string to uppercase letters asm
les di, Sxor cx, cxmov cl, es:[di]inc di
@@1: mov al, es:[di]cmp al, ’a’jb @@2cmp al, ’z’ja @@2 Chars between ’a’ and ’z’ will be uppercased here. sub al, 20h
@@2: mov es:[di], alinc diloop @@1
end;
procedure GetCommandLine(var PortId: byte; var Speed: longint); Check the command line and extract all parameters var
S: string;I: byte;J: integer;
beginPortId := 2;Speed:=2400;end;
procedure EnableIRQ(IRQ: byte); assembler; Enable a given IRQ from 0 to 7 asm
procedure SetupPort(PortBase: word; Speed: longint; IRQ: byte); Setup the UART and prepare for communication. var
D: word;B: byte;
begin For startup, disable the IRQ for the UART. DisableIRQ(IRQ);
Get the address of the old interrupt handler and set the vector to our won interrupt handling procedure ("SerialInterrupt") OldInterruptVec := GetIntVec($08 + IRQ);SetIntVec($08 + IRQ, @SerialInterrupt);
Enable the "Recieved Data avaliable" interrupt so we can read all data out of the UART’s RxD register. Port[PortBase + IntrEnable] := $01;
13
Now clear all pending interrupts - if any repeat
Read all important registers to clear any interrupt types, B is just used for temporary result storage B := Port[PortBase + RxDataReg];B := Port[PortBase + LineStatus];B := Port[PortBase + ModemStatus];
Just repeat until no more interrupts are pending. until ((Port[PortBase + IntrId] and 1) = 1);
Enable the IRQ line for the UART after all pending interrupts have been cleared. EnableIRQ(IRQ);
Calculate the divisor latch contents for the desired baud rate D := (115200 div Speed);
Set the DLAB bit to 1, then write the divisor latch low and high bytes Port[PortBase + LineCtrl] := $80;Port[PortBase + DivLow] := Lo(D);Port[PortBase + DivHigh] := Hi(D);
Now set the divisor latch bit to 0 and write all other values Port[PortBase + LineCtrl] := $03;Port[PortBase + ModemCtrl] := $0B;Port[PortBase + IntrEnable] := $0F;
Check if a 16550A UART is present... if (UARTType = UART_16550A) then
begin Clear the FIFO queues Port[PortBase + FifoCtrl] := $07;
Enable the FIFO queues Port[PortBase + FifoCtrl] := $C1;
Print a message so the user recognizes the FIFO queues are on writeln(’Enabling 16550A FIFO queues...’);
end;end;
procedure RunTerminal(PortBase: word;s:string;s2:string); Run the Terminal var
fc:file of char; 0..255b1,b2,bl:char;cnt,i:integer;
sendchar(chr(0)); repeat until keypressed;i:=0;assign(fc,s);reset(fc);b1:=’ ’;sendchar(chr($FF)); set baud rate while not EOF(fc) do begin
while ( ((b1=’ ’) or (b1=chr(10)) or (b1=chr(13)) ) and not eof(fc)) doif not eof(fc) then read(fc,b1);
if (ord(b1)>47) then begincnt:=0;read(fc,b2);if (ord(b1)>96) then b1:=chr(ord(b1)-32); min -> majif (ord(b2)>96) then b2:=chr(ord(b2)-32);if (ord(b1)<58) then cnt:=(ord(b1)-48)*16 else cnt:=(ord(b1)-55)*16;if (ord(b2)<58) then cnt:=cnt+(ord(b2)-48) else cnt:=cnt+(ord(b2)-55);sendchar(chr(cnt));inc(i);delay(5);write(cnt,’d=’,b1,b2,’h ’);
end;if not eof(fc) then read(fc,b1);
end;close(fc);
for cnt:=i to 1024 do sendchar(chr(0));
delay(1000);writeln(’RAM done’);
if (s2<>’ ’) then beginwriteln;writeln(’Press any key to continue’);repeat until keypressed;b1:=readkey;assign(fc,s2);reset(fc);b1:=’ ’;while not EOF(fc) do begin
while ( ((b1=’ ’) or (b1=chr(10)) or (b1=chr(13)) ) and not eof(fc)) doif not eof(fc) then read(fc,b1);
if (ord(b1)>47) then begincnt:=0;read(fc,b2);if (ord(b1)>96) then b1:=chr(ord(b1)-32); min -> majif (ord(b2)>96) then b2:=chr(ord(b2)-32);if (ord(b1)<58) then cnt:=(ord(b1)-48)*16 else cnt:=(ord(b1)-55)*16;if (ord(b2)<58) then cnt:=cnt+(ord(b2)-48) else cnt:=cnt+(ord(b2)-55);sendchar(chr(cnt));
write(cnt,’d=’,b1,b2,’h ’);repeat until keypressed;b1:=readkey; delay(500);
end;if not eof(fc) then read(fc,b1);
end;for cnt:=0 to 1023 do sendchar(chr(cnt));close(fc);
end;
end;
procedure ResetPort(PortBase: word; IRQ: byte); Reset UART and reset interrupt vectors begin
Reset the DLAB bit. Clear all other registers. Port[PortBase + LineCtrl] := Port[PortBase + LineCtrl] and $7F;Port[PortBase + ModemCtrl] := 0;Port[PortBase + IntrEnable] := 0;
Disable the IRQ for the UART, then restore the old interrupt vector. DisableIRQ(IRQ);SetIntVec($08 + IRQ, OldInterruptVec);
Inform the user that the terminal session was aborted. Writeln;Writeln(’Port closed.’);
end;
function Hex(W: word): TQuadString; Convert a number into hexadecimal outfit const
HexChars: array[0..15] of char = ’0123456789ABCDEF’;begin
Hex := HexChars[W shr 12] +HexChars[(W shr 8) and 15] +HexChars[(W shr 4) and 15] +HexChars[W and 15];
end;
procedure WritePortInfo; Output some info about the selected port begin
write(’Using COM’, PortNr, ’ (base address ’, Hex(PortBase), ’, IRQ ’,UsedIRQ);write(’, UART is a ’);
Print the detected UART type case UARTType of
UART_8250:write(’8250’);
UART_16450:write(’16450’);
UART_16550:write(’16550’);
UART_16550A:write(’16550A’);
end;
writeln(’)...’);end;
--- Main Routine ---begin
Just output some information. ClrScr;if (paramcount>0) then beginwriteln;writeln(’TERMINAL Version 1.00 Written 1995 by Stephan A. Maciej’);writeln(’Internet: [email protected] http://www.muc.de/˜stephanm’);writeln;
Check for some correct parameters on the command line. GetCommandLine(PortNr, Speed);PortBase := GetPortBase(PortNr);if (PortBase = 0) then
beginwriteln(’COM’, PortNr, ’: no such port !’);halt;
B Programmed’envoi desdonneesdu PCversle68HC11: hc11 linux.c (gcc,Linux)
Le programmesuivantutilise la memesyntaxequecellevuedansla partieprecedente(A) pourprogrammerle 68HC11sousLinux. Leprogrammeestendeuxparties: le coded’initialisation du port seried’unepart (rs232.c ) et le codedelecturedu fichier contenantle programmea charger en hexadecimalet de communicationavec le HC11 (hc11 linux.c ). La compilationse fait par gcc -crs232.c;gcc-o hc11 linux hc11 linux.c rs232.o.
Le programmers232.c :
14
/* All examples have been derived from miniterm.c *//* Don’t forget to give the appropriate serial ports the right permissions *//* (e. g.: chmod a+rw /dev/ttyS0) */
#include "rs232.h"
extern struct termios oldtio,newtio;
int init_rs232()int fd;
fd=open(HC11DEVICE, O_RDWR| O_NOCTTY);if (fd <0) perror(HC11DEVICE); exit(-1); tcgetattr(fd,&oldtio); /* save current serial port settings */bzero(&newtio, sizeof(newtio)); /* clear struct for new port settings */
for (j=0;j<i;j++) k=(int)buf[j];if (k<0) k+=256;printf("%d ",k);printf("\n");
void send_hc11(FILE *f,int fd)char buf[255];int i=0,status;unsigned int j;
buf[0]=255;write(fd,buf,1); /* start with ’FF’ */do do status=fscanf(f,"%x",&j);buf[i]=(char)j;i++; /* read while !EOF */
while ((status!=EOF) && (i<255)); /* && less than 255 chars */
if (i<255) i--;vrfy_buf(buf,i);write(fd,buf,i);printf ("%d bytes sent\n",i);i=0;
while (status!=EOF);
void main(int argc,char **argv)int fd;FILE *f;
if (argc<2) printf("%s filename\n",argv[0]); else fd=init_rs232();f=fopen(argv[1],"r");send_hc11(f,fd);
/* free_rs232(); */
C Programme de r eceptiondesdonneesde la RAM : test ram.pas (Turbo Pascal(7), DOS)
Ceprogramme,tressemblableahc11.pas , apourrolededeclencherl’ emissiondesdonneesstockeesdansla RAM li eeauHC11(parl’envoi du caractere$20)et de recupererlesoctetstransmispar le microcontroleurpour lesstocker dansle fichier ram.dat . En faitla seuledifferenceparrapportauprogrammeprecedentresidedansla procedureRunTerminal() : nousenvoyonsun caracterepuisrecevonsram len octets(ram len etantpasse commeparametredeRunTerminal() ). Il suffit ensuitederealiserun petit traite-mentdeconversionduformatbinaire(suited’octets)versunesortiedansunfichierauformatASCII pourpouvoir afficherla courbedesresultatsobtenus(enTurboCsousDOS,fin=fopen("ram.dat","rb");for () fscanf(fin,"%c",&c);fprintf(fout,"%d",(int)c); .
Nousne fournissonsici quela nouvelle procedureRunTerminal()qui a ete modifieeet la procedureprincipale(entrele begin etend. final), le resteetantidentiqueahc11.pas .
RunTerminal(PortBase: word;ram_len:integer); Run the Terminal var
fc:file of char; 0..255b,b1,b2,bl:char;cnt,i:integer;
beginassign(fc,’ram.dat’);rewrite(fc);sendchar(chr($20));for cnt:=1 to ram_len 9000 do begin
while not(GetQueueByte(InQueue, byte(b))) do begin end;write(fc,b);writeln(byte(b));
end;close(fc);
end;
begin Just output some information. ClrScr;writeln;writeln(’TERMINAL Version 1.00 Written 1995 by Stephan A. Maciej’);writeln(’Internet: [email protected] http://www.muc.de/˜stephanm’);writeln;
Check for some correct parameters on the command line. GetCommandLine(PortNr, Speed);PortBase := GetPortBase(PortNr);if (PortBase = 0) then
beginwriteln(’COM’, PortNr, ’: no such port !’);halt;
end;UsedIRQ := 4 - ((PortNr - 1) and 1);UARTType := GetUARTType(PortBase); Reset both the incoming as well as the outgoing Queue. ResetQueue(InQueue);ResetQueue(OutQueue); Write some information about the selected port. WritePortInfo; Setup the port, run the terminal and reset the port when ready. SetupPort(PortBase, Speed, UsedIRQ);
if (paramcount>0) then beginval(paramstr(1),ram_len,cc);RunTerminal(PortBase,ram_len);endelse RunTerminal(PortBase,31736); $400 -> $7FF8