Ohjelmisto


[edellinen sivu] [seuraava sivu] [sisällysluetteloon] [etusivulle]

Ohjelmiston suunnittelu aloitettiin tärkeimmästä laiteohjaimesta, LCD-näyttöjä päivittävästä rutiinista. Koska sen rakenteella oli vaikutuksia laitteiston suunnitteluun, täytyi se laatia jo hyvin varhaisessa vaiheessa (yksityiskohdat tosin täydentyivät myöhemmin). Kuten edellä on kerrottu, johtaa LCD-päivitysvaatimuksista poikkeaminen näyttöjen vaurioitumiseen pysyvästi, joten päivitysprosessin vaatimukset vaikuttavat myös koko muun ohjelmiston suunnitteluun.

Näyttöjen laiteohjaimen jälkeen laadittiin muut laiteohjaimet, koottiin tarvittavat aliohjelmakirjastot ja viimeiseksi laadittiin pääohjelma. Seuraavissa kappaleissa tarkastellaan vielä ohjelmiston rakenteeseen vaikuttaneita päätöksiä ennen ohjelmiston toteutuksen suppeaa esittelyä.

Ohjelmiston aikakriittiset toiminnot on laadittu assembler-kielellä, kuten osa muustakin ohjelmistosta (mm. valmiina käytetty liukulukukirjasto). C-kieltä on käytetty sellaisten osien tekemiseen, joiden suoritusajalla ei ole suurempaa väliä. Ohjelmankehitystyökalujen valinnasta on oma kappaleensa.

Jäljempänä esitetyt ohjelmaesimerkit on otettu suoraan käytössä olevasta ohjelmistosta, mutta pieniä muutoksia on tehty esityksen helpottamiseksi (mm. symbolisia vakiota on korvattu absoluuttisilla arvoilla).

Laitteiston ohjelmistolle asettamat rajoitukset

LCD-näyttöjen päivittämisestä ja valitusta kellotaajuudesta on edellä johdettu suurin mahdollinen aika, jonka keskeytykset saavat olla estettyinä, n. 200 kellojaksoa, eli

Kaikkien 68HC11 CPU:n suorittamien käskyjen suoritusaika on ilmoitettu datakirjoissa. Käskyjen suoritusajat ovat myös suoritusjärjestyksestä tms. riippumatta samat, joten ohjelman tarvitsema kokonaissuoritusaika on helposti laskettavissa.

Yleisimpien käskyjen suoritusajat vaihtelevat 2-7 kellojakson välillä, joten yllä olevat vaatimukset ovat varsin tiukkoja (muutamat poikkeukset, esim. jakolaskukäskyt, käyttävät enemmän aikaa).

Mahdollisuus valmiiden ohjelmistokomponenttien käyttämiseen

68HC11:lle tarkoitettua ohjelmakoodia on tarjolla kohtuullisesti Internetin ohjelma-arkistoissa. Mm. Motorola jakaa ohjelmia omasta ftp-palvelimestaan. Käytettäväksi soveltuvia ohjelmistokomponentteja etsittiin projektin alkuvaiheessa. Seuraavien käyttämistä tutkittiin:

Ohjelmiston rakenne

Ohjelmisto jaettiin aluksi seuraaviin kokonaisuuksiin:

Tärkeät toiminnot, joita ei ohjata "ulkoisilla ärsykkeillä", toteutettiin ajastimella tuotettavia keskeytyksiä hyväksi käyttäen. LCD-päivityksen, jonka toimivuus on ehdottomasti varmistettava, käyttämälle keskeytykselle annettiin muita korkeampi prioriteetti (68HC11:n sisäisten I/O-toimintojen generoimista keskeytyksistä (15 erilaista) yksi voidaan määrätä muita tärkeämmäksi. Muilla on kiinteä, ennaltä määrätty prioriteettijärjestys). Myös kellonajan päivittäminen ratkaisiin ajastimen avulla (reaaliaikakellopiiriltä voidaan lukea aika, mutta mitään ilmoitusta ajan muuttumisesta ei siltä saada).

Asynkroninen sarjaliitäntä (SCI) antaa keskeytyksen, kun uusi merkki on vastaanotettu tai edellinen merkki on lähetetty. Myös anturin pulssien laskennasta saadaan keskeytyksiä, koska se on liitetty ajastimeen sisältyvään laskuriin.

Muut laiteohjaimet sekä prosessit käsitellään keskeytyspalveluiden ulkopuolella. Laiteohjaimistakin osa voitaisiin käsitellä prosesseina.

Toteuttaminen MCX11-kernelin avulla

Aluksi tarkoituksena oli käyttää apuna Motorolan julkistamaa MCX11-kerneliä. Se sisältää lähinnä prosessien tuen ja kolme mekanismia prosessien väliseen kommunikointiin (semaforit, viestit ja jonot) sekä ajoituspalvelut. MCX11 on pieni (n. 2 kilotavua koodia) ja sisällytetään lähdekoodina muuhun ohjelmistoon (mm. prosessien määrä kiinnitetään käännösvaiheessa). Se ei sisällä mitään I/O-ominaisuuksia.

Ensimmäinen arvio oli, että MCX11 sopisi tähän projektiin varsin hyvin. Sen käyttämisellä olisi kuitenkin ollut haittavaikutuksia, jotka arveltiin saavutettavia hyötyjä suuremmiksi.

MCX11:n prosesseilla on kiinteä prioriteettijärjestys, joka toimii samalla prosessien numerointina (jokaisella prosessilla on siis muista eroava prioriteetti). Siten ajovuoron saa aina prosessi, jota suuremmalla prioriteetilla olevat prosessit eivät ole ajovalmiita. Ajovuoro vaihtuu välittömästi, kun jokin suurempiprioriteettisista prosesseista saavuttaa valmiuden.

Edellä luetelluista ohjelmiston osista olisi ollut helppoa muodostaa ainakin 4-6 prosessia. Myös prosessien prioriteetit olisi ollut mahdollista määrätä kiinteästi (alimmalla prioriteetilla toimisi mittaustulosten laskenta- ja esitysprosessi, koska se on käytännössä koko ajan ajossa), joskin prioriteetiltaan samanarvoisista prosesseista olisi voinut olla hyötyä (toiseksi matalan prioriteetin prosessiksi olisi sopinut sarjaliitäntäprosessi).

Useista prosesseista seuraa muistin käytön kannalta haittavaikutuksia: jokaisella prosessilla on oma pino, jolle täytyy varata tilaa muistista. Lisäksi MCX11 tarvitsee oman pinonsa ja prosessien hallintaa varten muutaman tavun muistia/prosessi (jälkimmäinen tilantarve on pieni).

Oman pinon varaaminen jokaiselle prosessille kasvattaa muistin tarvetta suhteellisen paljon: Jos oletetaan, että keskimäärin pinolle riittää esim. 50 tavua, tarvitaan kuudelle prosessille 300 tavua muistia, n. 30% käytettävissä olevasta muistista (MCX11:n pinon ja muuttujien lisäksi). Vaikka vaatimusten määrittelyssä arvioitujen tarpeiden mukaan (tarvearvio 0.5kt, kontrollerissa on 1kt) muistia pitäisi olla riittävästi, kannattaa yrittää säästää muistia mahdollisia myöhempiä ohjelmiston laajennuksia varten.

Muistin säästämiseksi ohjelmisto päätettiin toteuttaa yhtenä prosessina, jossa toteutetaan aiemmin esitetty jako prosesseihin tilakoneiden avulla. Tilakonetoteutuksesta on suhteellisen helppo siirtyä erillisten prosessien käyttämiseen jälkikäteen, jos siihen löytyy tarvetta.

Toteuttaminen tilakoneilla

Tilakonetoteutuksessa laitteistossa toimii vain yksi varsinainen prosessi, eli kaikki ohjelmiston osat käyttävät samaa pinoa. Reaaliaikavasteita toteuttavat osat toimivat keskeytysten avulla laiteohjainten osina ja kaikki muut toiminnot hoidetaan pääohjelmasta aliohjelmakutsujen kautta.

Edellä kuvattu prosessimalli toteutetaan kuvaamalla jokainen prosessi tilakoneilla. Prosessin toteuttava aliohjelma laaditaan siten, että se ei missään vaiheessa jää odottamaan mitään tapahtumia eikä suorita kertatoimenpiteitä, jotka eivät valmistu kohtuullisessa ajassa. Varsinainen pääohjelma vastaa kernelin skeduleria, se vain kutsuu ikisilmukassa jokaista prosessialiohjelmaa.

Tilakonetoteutuksen erona perinteisiin prosessitoteutuksiin verrattuna on siis tietynasteinen käänteisyys: "Normaali" prosessi voi jäädä odottamaan tapahtumaa esim. tekemällä käyttöjärjestelmäkutsun, josta palataa vasta kun prosessi on taas ajovalmis. Tilakonealiohjelmana toteutettu prosessi taas suorittaa normaalin aliohjelmasta paluun, kun sen täytyy odottaa tapahtumaa. Asiaa voidaan kuvata vaikka sanomalla, ettei käyttöjärjestelmä ole sovelluksen alla vaan päällä.

Tätä prosessimallia käytettäessä kullekin prosessille kuuluvat yksityiset muuttujat varataan yhteisestä muistista kiinteästi, koska prosessien vaihtojen yli säilyvää lokaalia muistia (joka yleensä varataan pinosta) ei ole. Tarvittavan muistin määrää voidaan pienentää käyttämällä samaa muistialuetta eri tarkoituksiin prosessin tilan määräämänä. C-kielen union-tyypi sopii tähän tarkoitukseen erittäin hyvin.

Prosessien laatiminen muuttuu myös yksinkertaiseksi yhteisten tietorakenteiden käsittely osalta, koska kyseessä ei ole keskeyttävä moniajo eikä yhteisiä tietorakenteita siten tarvitse lukita. Keskeyttävän moniajon puuttumisen takia on noudatettava tiukasti edellä mainittuja aliohjelmien suunnittelusääntöjä.

Esimerkki prosessin toteutuksesta

Tämän sovelluksen tilakoneprosessit on laadittu kokonaisuudessaan C:llä. Koska koodia on suhteellisen paljon, on tässä esitettäväksi valittu osa käyttöliittymäprosessista. Kyseessä on funktio, jota kutsutaan oikean toiminnon valitsemiseksi, kun yhtä neljästä laitteen ohjausnapista on painettu (käyttöliittymän rakenne on kuvattu edellä vaatimusten määrittelyn yhteydessä).

Käyttöliittymän ohjaustietojen kuvaamiseen on käytetty struktuuria ui_sel, joka sisältää mm. tiedot ohjausnappien käyttötarkoituksista, sekä pointterin näytön yläosan päivittämiseen tarvittavaan funktioon.

/* uistruct.h */

#define	NUM_BUTTONS	4
	
struct	ui_sel	{
	char	*mode_name;
	int	(*update_screen)();
	int	flags;
	
	struct	button	{
		char		*description;
		struct ui_sel	*(*funct)();
		void		*arg;
	} button[NUM_BUTTONS];
};

extern	struct ui_sel	*ui_state;
Käyttöliittymän tilan määrää yksikäsitteisesti pointteri ui_state, joka osoittaa kulloinkin aktiivisena olevaan struktuuriin. Alla on struktuurien initialisointikoodista pala, joka kuvaa ajanottofunktion käyttöliittymää. Kannattaa huomioida, että nämä struktuurit sijoitetaan kokonaisuudessaan ROM-muistiin. Tässä ei kuitenkaan käytetä const-sanaa määrittelyn yhteydessä, koska käytetty C-kääntäjä on ns. vanhan määrittelyn mukainen [Ker78] eikä tue ANSI C-standardin mukanaan tuomia laajennuksia.
struct  ui_sel  ui_m_timer = {
        NULL, ui_tmr_update_screen, DISPLAY_BUTTON_TEXTS|REP_CALL_UPDATE_FUNCT,
                {{ " =0 ", ui_tmr_clear_timer, &ui_m_timer },
                 { "käy ", ui_tmr_start_timer, &ui_m_timer },
                 { "seis", ui_tmr_stot_timer, &ui_m_timer },
                 { "-->>", ui_select_segdisp_mode, SEGDISP_MODE_1 }}
};
Kun yhtä käyttöliittymän napeista painetaan, kutsutaan funktiota ui_select_function, joka saa parametrikseen painetun napin numeron (1..4):
ui_select_function(key)
unsigned int	key;	/* 1..NUM_BUTTONS (1..4) */
{
	struct ui_sel	*(*f)();

	if(--key < NUM_BUTTONS) {
		if(f = ui_state->button[key].funct) {
			ui_state = (*f)(ui_state, ui_state->button[key].arg);
			update_screen();
		}
	}
}
Tämän funktion koodi käännettiin kahdella erilaisella C-kääntäjällä. Syntyneen koodin määrästä on yhteenveto alla olevassa taulukossa. Assembleriksi käännettyjen tiedostojen käännöslistaukset on esitetty liitteessä, koska ne vaativat suhteellisen paljon tilaa.
KääntäjäKoodin koko tavuina
GCC, ei optimointia190
GCC, optimointi (-O)102
5+c, ei optimointia131

Kääntäjistä on lisää tietoja kappaleessa ohjelmistotyökalujen valinta.

Esimerkkejä laiteohjaimista

Seuraavissa kappaleissa on esitetty elintärkeään, LCD-näyttöjen päivittämiseen liittyvä ohjelmakoodi. Se havainnollistaa lähinnä ajastimen ja SPI-liitännän yhteiskäyttöä.

LCD-näyttöjä käsittelevän osuuden jälkeen selostetaan hieman I2C-väylän simulointia ohjelmallisesti. Laitteistorajoitteiden (esim. tässä tapauksessa I2C-väylän tuen puuttumisen) kiertäminen ohjelmallisesti on käytännön toteutuksissa hyvinkin yleistä, muttei aina suoraviivaista.

LCD-näyttöjen ohjaus

LCD-näyttöjen päivittäminen hoidetaan ajastimen ja SPI-liitännän avulla.

Ajastin on ohjelmoitu antamaan keskeytys säännöllisin välein. Samanaikaisesti saadaan ajastimesta ulos signaali (OC2), joka ohjaa näyttöjen Lp-signaalia (Lp siirtää siirtorekisterin sisällön LCD-elementtiä ohjaavan piirin ulostuloihin). Ajastimen antaman keskeytyksen palvelurutiini siirtää tarvittavan määrän tavuja näyttöjen siirtorekistereihin odottamaan seuraavaa Lp-pulssia (joka annetaan seuraavan keskeytyksen yhteydessä).

Menettelytavasta seuraa, että ajastimen antama keskeytys voidaan palvella missä vaiheessa vain näyttöjen päivityssykliä, kunhan keskeytysrutiini ehditään suorittaa kokonaisuudessaan ennen seuraavaa samasta syystä aiheutuvaa keskeytystä (etteivät näytöt vaurioidu).

Alla on esitetty näyttöjen päivitykseen liittyvä ohjelmakoodi kokonaisuudessaan.

Ajastimen ja SPI-väylän alustus

SPI-liitäntä initialisoidaan:

initspi
	ldaa	#$54	; SPI:n tila= ei keskeytyksiä, SPI enabloidaan,
			;   SPI:n master mode, polariteetti näytöille sopivasti
			;   ja SPI:n kello = CPU-kello / 2
	staa	SPCR	; asetetaan em. ehdot voimaan
	ldaa	SPSR	; nollataan mahdollisesti päällä oleva SPIF-lippu
	ldaa	SPDR	; poistetaan vanha data, jos sellaista oli
Ajastimen alustus:
inittmr	
	ldaa	#$60		; estetään muut ajastimen keskeytykset paitsi
	staa	TMSK1		;  TOC2:lta (näytöt) ja TOC3:lta (500ms) tulevat
	ldaa	#$FF		; kuitataan mahdollisesti voimassa olevat
	staa	TFLG1		;  keskeytykset

	ldaa	#$80		; Ulostulojen toiminta: OC2=nollataan vertailun
	staa	TCTL1		;  seurauksena, OC3 on tavallinen I/O-linja

Keskeytysaliohjelma

Ensimmäiseksi keskeytysrutiini asettaa OC2-ulostulon takaisin 1-tilaan. I/O-linjaan ei voi vaikuttaa suoraan (portin A kontrollointirekisterien kautta), koska se on initialisoinnissa annettu ajastimen kontrolloitavaksi.

intr_TOC2
	ldaa	#$C0
	staa	TCTL1	; alustetaan OC2 asetettavaksi
	ldaa	#$40
	staa	CFORC	; Pakotetaan TOC2-vertailu: 1 -> OC2-pinni 
Seuraavaksi asetetaan ajastin keskeyttämään ja nollaamaan OC2 uudestaan oc2delay:n määräämän ajan kuluttua.
	ldaa	#$80		; asetetaan OC2 nollattavaksi,
	staa	TCTL1		; kun vertailu tapahtuu

	ldd	TOC2		; otetaan edellinen vertailuaika,
	addd	oc2delay	; lisätään siihen viive,
	std	TOC2		; ja talletetaan takaisin vertailurekisteriin
	ldaa	#$40
	staa	TFLG1		; Nollataan ajastimen keskeytyspyyntö
Ajastin on nyt alustettu seuraavaa keskeytystä varten.

Seuraavaksi valmistaudutaan lähettämään näyttöjen siirtorekistereihin edellisen datan komplementti.

	ldx	#seg_img	; X osoittaa lähetettävän datan puskuriin

	ldy	#4*7-1		; Y on lähetettävien tavujen lukumäärä - 1
				; 4 näyttöä, 7 tavua / näyttö

	com	sencpl		; komplementoidaan lippu, joka määrää 
	bmi	int_scpl	;   lähetettävän datan komplementoinnista
Ohjelman suorituksen jatkuessa suoraan lähetetään puskurin sisältö sellaisenaan. Joka toisella kerralla hypätään osoitteeseen int_scpl, jolloin lähetetään data komplementoituna (alempana).

Lähetysrutiineja on siis kaksi, joista toinen näyttää turhalta - olisihan toki mahdollista sisällyttää lähetysrutiiniin XOR-operaatio yllä olevan sencpl-muuttujan kanssa, jolloin pärjättäisiin yhdellä lähetyssilmukalla. Selitys on varsin yksinkertainen: Ensimmäinen rutiini, joka lähettää datan komplementoimatta, on nopein mahdollinen toteutus datan lähettämiseksi. SPI käyttää kunkin tavun lähettämiseen juuri saman määrän kellojaksoja jonka kukin silmukan kierros kestää. Siten siirron valmistumisesta kertovaa SPIF-lippua (SPI Interrupt complete) ei tarvitse testata, mutta SPSR (SPI status register) täytyy lukea, jotta seuraava tavu voidaan lähettää.

spinxt1
	ldaa	,x		; 4 ; otetaan tavu puskurista
	ldab	SPSR		; 4 ; luetaan SPSR SPIF-lipun nollaamiseksi
	staa	SPDR		; 4 ; lähetetään tavu
	inx			; 3 ; osoitetaan seuraavaa
	dey			; 4 ; ja vähennetään jäljelläolevia
	bne	spinxt1		; 3 ; hyppää jos Y != 0
Numero kommenttikentän alussa kertoo käskyn käyttämien CPU-kellojaksojen lukumäärän.

Viimeinen tavu lähetetään erikseen. Koodia syntyy 8 tavua enemmän, mutta suoritusaikaa säästyy 10 kellojaksoa. Ajan säästäminen kannattaa, koska CPU:n kellotaajuus on tarkoitus laskea niin alas että tämän keskeytyksen palveleminen vie suhteellisen suuren osan kokonaisajasta.

	ldaa	,x		; 4 ; viimeinen puskurista
	ldab	SPSR		; 4 ; nollaa SPIF
	staa	SPDR		; 4 ; ja matkaan

	rti			; palataan keskeytyksestä
Viimeisenä on jäljellä komplementoidun datan lähettäminen. Nyt aikaa kuluu 2*28 kellojaksoa edellistä enemmän coma-käskyjen takia.

Komplementoitu data voitaisiin myös muodostaa etukäteen RAM-muistiin (jota kuluisi silloin 28 tavua enemmän), mutta komplementointi ajon aikana on turvallisempaa: Jos joku muu osa ohjelmistota korruptoi lähetyspuskuria, mutta tämä keskeytyspalvelu toimii yhä (ja vaikka se olisi ainoa ohjelmiston toimiva osa), eivät LCD-näytöt vaurioidu.

int_scpl 
spinxt2
	ldaa	,x		; 4
	coma			; 2 ; komplementoi
	ldab	SPSR		; 4
	staa	SPDR		; 4
	inx			; 3
	dey			; 4
	bne	spinxt2		; 3

	ldaa	,x		; 4
	coma			; 2
	ldab	SPSR		; 4
	staa	SPDR		; 4

	rti
Keskeytyspalvelun suoritusaika

Edellä olevan rutiinin kokonaissuoritusajaksi saadaan 670 kellojaksoa, kun data lähetetään sellaisenaan ja 726 kun se invertoidaan. Ajat eivät sisällä keskeytyksen käsittelyyn tarvittavaa aikaa. Yleisemmin suoritusajaksi saadaan invertoimattomassa tapauksessa

54 + n * 154 kellojaksoa,
Missä n on näyttöjen lukumäärä (esimerkkikoodissa 4).

Pahimmassa tapauksessa muut keskeytykset ovat estettynä siis n. 750 CPU-kellojakson ajan.

Rutiinin suoritusajan laskemisen jälkeen voitiin määrittää tarvittava kellotaajuus (kts. edellinen luku).

Segmenttitietojen muodostaminen

Ohjelman kannalta on yksinkertaisinta, jos näytölle voidaan kirjoittaa ASCII-merkkejä. Silloin sama merkkijono voidaan tulostaa sellaisenaan myös alfanumeeriselle LCD-näytölle tai lähettää sarjalinjan kautta.

Tässä käytettyjä moduleita ohjataan kuitenkin segmenteittäin. LCD-näyttöjä ohjaaviin siirtorekistereihin lähetetään bittijono puskurista seg_img. Puskurissa on näyttöä kohti 56 bittiä, joista 49 ohjaa näyttömodulin segmenttejä ja yksi näytön backplanea (6 on käyttämättömiä). Segmenttejä ohjaavien bittien sijainti lähetyspuskurissa riippuu vain siirtorekisterien kytkennästä näyttöön, eli piirilevyn rakenteesta. Järjestys on siten lähes satunnainen.

Näytöille kirjoittamisen helpottamiseksi tehtiin merkkigeneraattori, joka muodostaa taulukon avulla ASCII-merkeistä 7-segmenttinäytöille sopivaa dataa (eli täyttää em. seg_img-puskurin). ASCII-merkkejä käytetään, koska silloin sama tulostettava data voidaan näyttää segmenttinäytöillä, lähettää sarjalinjasta ulos tai näyttää alfanumeerisella LCD-modulilla (vaikka 7-segementtinäytöt on tarkoitettu ensisijaisesti numeroiden näyttämiseen, voidaan suurin osa kirjaimistakin esittää ymmärrettävästi).

Erikoispiirteitä I2C-väylän simuloinnissa

I2C-väylän simuloiminen ohjelmallisesti on kohtuullisen yksinkertaista. Väylä on periaatteessa synkroninen sarjaväylä: Se käyttää kontrollerista kaksi I/O-linjaa, joista toinen on kellosignaali kontrollerilta kellopiirille päin, toinen on kaksisuuntainen datalinja. Väylässä käytetään yksinkertaista protokollaa, jossa lähetetään kohteen osoite, komento (read/write) ja data.

Datalinjan kaksisuuntaisuus on piirre, joka vaikuttaa ohjelmiston rakenteeseen. Kellopiiri nimittäin vaihtaa oman linjansa suuntaa antaakseen ACK-pulsseja (0-tila) aina vastaanotettuaan 8 bittiä. Väärin tehdyllä ohjelmistolla on teoriassa mahdollista vahingoittaa joko kontrolleria tai kellopiiriä.

68HC11:n I/O-portit sisältävät, kuten monien muidenkin kontrollerien ja I/O-laitteidenkin, erilliset rekisterit dataa ja linjojen suuntia varten. Linja käyttäytyy eri tavalla riippuen siitä onko se määritelty tuloksi vai lähdöksi. Jos linja määrätään lähdöksi, se joko syöttää tai nielee virtaa riippuen datarekisterin tilasta (1/0). Tuloksi määriteltäessä ei virtaa juurikaan kulje.

Ongelmia saattaa syntyä, jos I/O-portin datalinjaksi määrätty linja on tilassa 1 kun kellopiiri vetää datalinjan tilaan 0 ACK-pulssia varten (tällöin kulkee tuntemattoman suuruinen virta mikrokontrollerista kellopiiriin).

Oikea tapa hoitaa kommunikaatioita on siksi ohjelmoida I/O-portin lähtö olemaan aina 0, ja vaihtaa lähdön tilan sijasta linjan suuntaa, kun halutaan lähettää 1-bittejä. Kontrollerin ja kellopiirin välisissä kytkennöissä on ulkoiset ylösvetovastukset, jotka huolehtivat siitä, että linjan tila tulkitaan 1:ksi jos molempien piirien portit ovat input-tilassa.

Toinen erikoisuus, jonka kytkentäkaaviota tarkkaan lukeva huomaa, on I2C-väylälle käytettyjen I/O-linjojen käyttäminen myös lisämuistipiirin ylimpinä osoitelinjoina. Tällä menettelyllä säästetään kaksi I/O-linjaa, joilla tuntuu olevan yleisenä taipumuksena loppua viimeistään laitteiden jatkokehityksen yhteydessä. I/O-linjat voidaan tässä tapauksessa käyttää kahteen tarkoitukseen pyörittämällä ne sopivan sekvenssin kautta oikeaan tilaan kun niitä tarvitaan osoitelinjoina: I2C-väylän osoitteellisuus takaa, että kellopiiri ei sotkeennu asiaan, kun ei anneta sen osoitetta, ja tämän kyseisen piirin spesifikaatioiden sallima minimisiirtonopeus (0Hz) antaa mahdollisuuden jättää linjat oikeaan tilaan osoitelinjoina käyttämistä varten.


[edellinen sivu] [seuraava sivu] [sisällysluetteloon] [etusivulle]

[versio 1.6, 1996/03/10 20:08:32] [Lähetä palautetta Laurille]

Copyright © 1996 Lauri Aarnio. All Rights Reserved.