Projet de TDO Mémoires FLASH et bus de données Etude et

publicité
Projet de TDO
Mémoires FLASH et bus de données
Etude et comparaison
Sophie Sivignon
Florent Castelli
Groupe 2
Mars 2005
Introduction
Actuellement, sans forcément le savoir, nous sommes tous entourés par ce qui est une des
dernières révolutions technologiques. Cette révolution a ouvert de nombreuses portes et
énormément réduit les coups de fabrication. Celle-ci est la mémoire Flash. La mémoire Flash
se retrouve partout : ordinateurs, mémoires pour appareils photos, clés USB, cartes contrôleur
ou d’extension et bien d’autres applications. Cette mémoire si répandue de nos jours dépend
du périphérique sur lequel elle est connectée. Et ce périphérique communique avec d’autres et
échange des informations ; cela se fait par l’intermédiaire d’un bus de données. Tout le monde
connaît au moins l’USB. Mais il en existe d’autres qui ont chacun leurs avantages et nous
allons en étudier quelques uns dans ce rapport.
Nous verrons donc une explication sur le fonctionnement des mémoires Flash. Ensuite nous
nous intéresserons au fonctionnement du bus SPI et Microwire. Nous verrons en détail le bus
I²C et enfin une comparaison entre ces déférents bus.
Introduction _______________________________________________________________ 2
I – Mémoires Flash _________________________________________________________ 3
II – Bus de données _________________________________________________________ 5
1)
SPI ______________________________________________________________________ 5
2)
Microwire ________________________________________________________________ 6
3)
I²C ______________________________________________________________________ 7
Présentation _________________________________________________________________________ 7
Protocole ___________________________________________________________________________ 7
Driver______________________________________________________________________________ 8
4)
Comparaison______________________________________________________________ 8
Conclusion _______________________________________________________________ 10
Annexe __________________________________________________________________ 11
Driver I²C pour 6502 __________________________________________________________ 11
2
I – Mémoires Flash
La mémoire flash est une mémoire à semi-conducteurs, non volatile et réinscriptible, c'est-àdire une mémoire possédant les caractéristiques d'une mémoire vive mais dont les données ne
disparaissent pas lors d'une mise hors tension (mémoire de masse). Ainsi, la mémoire flash
stocke les bits de données dans des cellules de mémoire, mais les données sont conservées en
mémoire lorsque l'alimentation électrique est coupée.
En dépit de sa relative lenteur, la durée de vie et la consommation faible (et même nulle au
repos) de la mémoire flash la rendent utile pour de nombreuses applications : appareils photo
numériques, téléphones cellulaires, assistants personnels (PDA), ordinateurs portables ou
dispositifs de lecture et d'enregistrement sonore comme les baladeurs MP3, clef USB. De
plus, ce type de mémoire ne possède pas d'éléments mécaniques, ce qui lui confère une assez
grande résistance aux chocs.
La mémoire flash est un type d'EEPROM (Electrically Erasable Programmable ReadOnly
Memory) qui permet la modification de plusieurs espaces mémoires en une seule opération.
La mémoire flash est donc plus rapide lorsque le système doit écrire à plusieurs endroits en
même temps.
Elle existe sous deux formes: flash NOR et NAND, d'après le type de pont logique utilisé
pour chaque cellule de stockage.
La mémoire flash NOR est la première à être développée par Atmel. Les temps d'effacement
et d'écriture sont longs mais elle possède une interface d'adressage permettant un accès
aléatoire à n'importe quelle position. Elle est adaptée à l'enregistrement de programmes
informatiques qui sont rarement mis à jour, comme dans les appareils photo numériques ou
les organisateurs personnels. Elle peut supporter de 10 000 à 100 000 cycles d'effacement.
La mémoire flash NAND fut développée par Toshiba. Elle est plus rapide à l'effacement et à
l'écriture, offre une plus grande densité, un coût moins important par bit et une durée de vie
dix fois plus importante. Toutefois son interface d'entrée / sortie n'autorise que l'accès
séquentiel aux données. Elle est donc utilisée pour le stockage d'informations et est moins
utile en tant que mémoire pour ordinateurs.
Dans la mémoire flash NOR, chaque cellule de mémoire est similaire à un transistor standard
MOSFET, excepté qu'il y a deux portes au lieu d'une. Une des deux portes est le CG (Control
Gate) comme dans les autres transistors MOS et la seconde est la FG (Floating Gate) qui est
isolée par une couche d'oxyde. Ainsi les électrons, passant au dessus, se retrouvent
emprisonnés et stockent l'information.
Lorsque les électrons sont sur la FG, ils modifient partiellement le champ magnétique venant
du CG qui modifie la tension de la cellule. De ce fait, lorsque la cellule «est lue» une tension
spécifique est placée sur le CG, le courant électrique passe ou ne passe pas selon la tension de
la cellule qui est, elle, commandée par le nombre d'électrons stockés sur le FG. La présence
ou l'absence de courant électrique est traduite par des 0 et des 1, reproduisant ainsi les
données stockées.
Dans un dispositif à plusieurs niveaux de cellules, qui stocke plus de 1 bit de données par
cellule, connaître le flux de passage du courant électrique plutôt que simplement sa présence
ou son absence permet de mieux déterminer le nombre d'électrons stockés sur le FG.
3
Une NOR flash cellule est programmée en utilisant un processus appelé hot-electron injection
qui consiste à placer un haut voltage sur le CG pour obtenir un champ électrique assez fort
pour déplacer le flux d'électrons d'un pôle à un autre. La plupart des composants des
mémoires flash NOR modernes sont divisés en segments effaçables appelés blocs ou secteurs.
Toutes les cellules mémoires d'un bloc doivent être effacées en même temps.
La programmation NOR peut généralement être exécutée à un octet ou mot à la fois.
En ce qui concerne la NAND flash, elle utilise le procédé de tunnel injection pour l'écriture et
le tunnel release pour l'effacement.
4
II – Bus de données
1) SPI
Le « Serial Peripheral Interface Bus » ou bus SPI de Motorola est un standard de contrôle
adapté à presque tous les équipements électroniques qui acceptent un flux de bits en série et
avec une horloge.
SPI est très peu cher car il utilise très peu de fils et donc moins de place sur un circuit intégré
et il ne multiplie donc pas les broches sur les composants. On peut aussi l’implémenter en
software avec peu de pattes d’entrée / sortie d’un microcontrôleur.
Le bus SPI est capable de travailler en duplex et il est donc un très bon choix pour des
systèmes de transmission de données.
Le bus SPI n’a besoin que de 4 fils sur chaque circuit intégré :
- une horloge (SCLK)
- une entrée « Master Data Out / Slave Data Input » (MOSI)
- une sortie « Master Data Input / Slave Data Output » (MISO)
- un « chip select » aussi appelé « slave select » (SS).
Organisation Maître / Esclave du bus SPI 1
Dans le cas général, les données arrivent dans le périphérique quand l’horloge est basse et
sortent quand l’horloge est haute. Un périphérique pour communiquer doit avoir le chip-select
bas. Dans le cas contraire, la plupart des périphériques ont leur sortie avec une haute
impédance (désactivée). Tout cela permet à de nombreux appareils de communiquer avec un
écouteur unique. La fréquence de l’horloge peut varier de quelques kHz à quelques MHz.
Quand il y a plusieurs périphériques esclaves, le périphérique maître possède plusieurs SS et
doit donc n’en activer qu’un seul à la fois.
Organisation Maître / Esclave du bus SPI 2
5
De nombreuses différences peuvent exister entre différents périphériques SPI. Certains
inversent les phases de l’horloge et reçoivent des données quand l’horloge est haute et
envoient quand l’horloge est basse. D’autres périphériques peuvent être sélectionné quand le
SS est haut. Cela cause de nombreuses incompatibilités entre les périphériques et l’on doit
s’assurer quand on couple des périphériques qu’ils utilisent bien tous la même version du bus
SPI.
Le bus SPI est un bus fait pour échanger des données brutes. Il n’y a pas de mécanisme de
communication standard ni de contrôle de flux. Le protocole de communication est laissé
libre au concepteur du périphérique. On pourrait voir que les périphériques esclaves ne sont
que de simples périphériques d’entrée / sortie.
Le bus SPI obtient les meilleures performances quand il n’y a qu’un seul esclave et un seul
maître du fait de sa capacité à faire du Full Duplex et de son taux de transfert pouvant
atteindre plusieurs mégabits par seconde.
2) Microwire
Microwire de National Semiconductor est un bus assez ancien dont le successeur est le bus
SPI. Ils fonctionnent de façon assez proche.
6
3) I²C
Présentation
Le bus I2C (Inter-IC Bus) est caractérisé par une liaison en mode série réalisée à l'aide de 2
Fils. C'est la société Philips qui en à créer le concept au début des années 80. Son succès est
lié à sa simplicité.
Voici l'architecture type d'un bus I2C, on remarque que plusieurs composants viennent se
"greffer" sur le même bus.
Les données transitent par les lignes :
- SDA : signal de donnée, généré par le Maître ou l'Esclave.
- SCL : signal d'horloge généré par le Maître.
La communication sur le bus est assez simple. Le Maître envoie sur le bus l'adresse sur 7 bits
du composant avec qui il souhaite communiquer, les esclaves ayant une adresse fixe, l'esclave
qui reconnaît son adresse répond à son tour par un signal de confirmation, puis le Maître
continue la procédure de communication écriture ou lecture. Dans tout les cas, les transactions
sont confirmées par un ACK
Protocole
La condition de repos : Condition dans la quel aucun composants ne communiquent, les
lignes de bus sont à l'état Haut
La condition de départ : Le Maître force la ligne SDA au niveau bas pour "réveiller" les
Esclaves quand SCL est au niveau haut
La condition d’arrêt : Les lignes SDA et SCL sont au niveau bas, puis quand SCL passe au
niveau haut, le Maître libère la ligne SDA au niveau haut. A cet instant le bus est considéré
comme disponible
L'acquittement : Une fois les données transmises, un acquittement est opéré par celui qui
reçoit les donnés. Cette procédure est réalisée en fin de trame de transmission, soit à la
neuvième impulsion. Le récepteur maintien la ligne SDA au niveau bas pendant le front
d'horloge
7
La communication par octet : Nous allons prendre comme exemples les cas suivants afin de
visualiser à quoi peut ressembler un échange complet sur le bus entre Maître et Esclave :
Driver
L’élaboration d’un driver pour I²C est assez simple. Le protocole ne nécessite que peu de code
pour être fonctionnel dans n’importe quelle architecture. Ci-joint en annexe, le code pour faire
fonctionner un périphérique I²C pour un processeur 6502, processeur très simple dont le code
assembleur peut être adapté facilement à tout autre processeur IA32, MIPS, PPC, Strong
ARM ou autres. Je n’ai pas inclus de code x86 car il est moins facilement portable et moins
clair que le code 6502. Le bus I²C est répandu dans tellement d’architectures qu’il est
dommage de se restreindre à l’IA32. Une documentation complète du processeur 6502 est
disponible à l’adresse http://www.obelisk.demon.co.uk/6502/index.html .
Les seuls changements importants pour l’architecture IA32 par exemple sont de prendre en
compte l’écriture dans le port de l’interface sur lequel est branché le bus. Par exemple « out
378h, octet » au lieu dans le code présent des « STA I2CPort ». De plus il faut
changer quelque peu les temporisations pour que le processeur n’aille pas plus vite que le bus
et que l’horloge générée soit ainsi à la bonne fréquence.
4) Comparaison
Les mémoires à accès série sont aujourd'hui accessibles par 3 bus séries :
1) le bus SPI de Motorola
2) le bus Microwire de National Semiconductor
3) le bus I²C de Philips
Il existe désormais à l'interface parallèle (Centronics) et à l'interface série (RS232), des
logiciels du domaine public permettant la constitution de programmateur venant écrire ces
mémoires. Aujourd'hui ces mémoires accès série sont placées sur les barrettes de SRAM ou
de DRAM pour contenir le pedigree de la barrette tel que sa capacité, le temps d'accès, le
fabricant...Autant d'informations nécessaires aux opérations de plug-and-play du PC. Ainsi
par 2 fils très particuliers du channel, le microprocesseur connaîtra l'horloge nécessaire pour
que les instructions se fassent sans overclockage.
8
Les interfaces synchrones sont caractérisées par la présence d'un signal de
transmission/réception destiné à l'horloge. Un procédé « maître » produit généralement un
signal d'horloge qui est reçu par tous les procédés « esclaves » qui reçoivent et transmettent
les données de façon synchrone. L'avantage est que chaque dispositif travaille en fonction du
signal de l'horloge émis par le « maître », indépendamment des variations d'oscillateur de
chaque procédé individuel. Ainsi ces interfaces sont très appropriées pour l'usage de puces
d'oscillateurs qui ont de grandes variations de fréquence.
Exemples d'interfaces synchrones : SPI (Serial Peripheral Interface) développé par Motorola,
Microwire développé par National Semiconductor, I²C (Inter Integrated Circuit) développé
par Philips mais aussi USART (Universal Synchronous & Asynchronous Receiver
Transmitter) qui comme son nom le suggère peut être soit en mode synchrone soit en mode
asynchrone.
Les interfaces synchrones ont été conçues pour relier des périphériques sur une même carte,
comme par exemple la EEPROMS externe ou les convertisseurs Analogique Numérique...
Elles sont seulement appropriées aux distances relativement courtes, moins d’un mètre.
Mais nous allons nous intéresser d'avantage aux interfaces SPI, Microwire et I²C et faire un
petit comparatif:
Ainsi SPI est un proche cousin du vieux Microwire. Les deux interfaces sont très simples et
fonctionnent principalement sur le principe d'un registre à décalage série de 8bits et pour les
dispositifs « maîtres », il s'agit d'une horloge programmable à décalage. Il n'y a aucun moyen
d'adresser les dispositifs, les applications typiques se composent d'un dispositif principal
« maître », habituellement un microcontrôleur, et d'un ou de multiples dispositifs «esclaves»,
comme par exemple des fonctions de périphérique comme le convertisseur A/N, EEPROM.
Cependant I²C est un petit peu plus complexe que SPI et Microwire, ceci demande donc un
plus grand secteur de silicium et entraîne des périphériques légèrement plus chers.
Concernant la connexion des périphériques externes, il y a trois raccordements au minimum
pour SPI et Microwire : l'horloge, l'entrée des données et la sortie des données. Par
conséquent, ces interfaces sont parfois désignées sous le nom d'interfaces à trois fils. Les
périphériques interconnectés ont besoin de se partager la borne Vcc et la masse et dans le cas
de périphériques connectés multiple, un chip select est nécessaire pour chaque périphérique
«esclave».
Si on veut connecter N périphériques à un microcontrôleur avec Microwire ou SPI, vous
devez sacrifier 3+N pins pour faire le travail. C'est un secteur où I²C a l'avantage, en effet il
comporte une adresse de 7bits et il peut donc adresser à 128 périphériques sur le bus sans
avoir besoin du signal du chip select.
Concernant la vitesse, I²C indiquait au début, une vitesse maximum de 100 KBits/sec, plus
tard celle-ci a grimpé à 400 KBits/sec et récemment quelques dispositifs sont montés jusqu'à
1Mbits/sec. Mais ceci est très peu par rapport aux vitesses que peuvent atteindre SPI et
Microwire. En effet une EEPROM série peut supporter aujourd'hui jusqu'à 3Mbits/sec pour
Microwire et plus de 10Mbits/sec avec SPI. Cette différence de vitesse s'explique par le fait
que SPI et Microwire ont des capacités full duplex c'est à dire qu'elles peuvent envoyer et
recevoir des données en même temps. Alors que I²C n'a que deux fils, un pour l'horloge et un
pour la donnée, il ne peut donc communiquer qu'en semi duplex.
La vitesse est très importante pour la consommation courante, tout d'abord, car la majeure
partie du temps, les applications du microcontrôleur sont en mode d'économie d'énergie et
seulement certaines périodes courtes sont en mode de fonctionnement normal. De plus, les
9
opérations de lecture et d'écriture vers un périphérique doivent être les plus rapides et le temps,
où le microcontrôleur est actif, doit être le plus court. Ceci est particulièrement vrai pour les
accès à des mémoires externes EEPROM.
Systèmes multi maîtres :
C'est I²C qui offre un meilleur support pour les systèmes multi-maîtres. L'interface est
construite sur le principe d'arbitrage pour détecter les périphériques multiples envoyant sur le
bus en même temps et en donnant la priorité à celui qui envoie le premier un « 0 ». SPI
supporte ce système grâce à un procédé de « logique par défaut », c'est à dire qu'il peut
détecter les requêtes des périphériques pour devenir «maître» via un pin SS (Slave Select).
Un inconvénient possible d'I²C est une sensibilité plus forte pour le bruit et avec ceci une
intégrité des données inférieure. I²C utilise un bit d'écriture et de lecture qui suit les 7bits
d'adresse initiaux pour demander à un périphérique si la donnée doit être lue ou écrite. I²C
échantillonne la donnée durant la phase élevée ou basse d'un bit et ce bruit peut altérer le bit
d'écriture/lecture. Ainsi si on veut lire une donnée d'une EEPROM externe mais que le bruit
transforme ce bit de lecture en bit d'écriture, la mémoire sera corrompue. D'autre part, les
périphériques de Microwire et de SPI implémentent les opérations de lecture et d'écriture via
des commandes explicites envoyés sur le bus.
En conclusion, si on a plusieurs périphériques connectés et plusieurs microcontrôleurs dans le
système qui peuvent agir en tant que maître alors l'interface à choisir serait plutôt I²C. Cette
interface est très populaire pour les applications vidéo et audio. Si par contre on recherche
plutôt des prix réduits, une grande vitesse et une immunité du bruit alors Microwire et SPI
sont préférables.
Conclusion
Il existe donc de nombreuses alternatives face au si répandu bus USB. Elles n’ont pas la
même vocation mais permettent d’accomplir des tâches pour lequel il serait trop important.
Chaque bus a ses avantages et ses inconvénients et il est donc difficile de faire un choix. La
simplicité et de faibles coûts ou une plus grande vitesse mais plus de fils ? Le choix dépend
donc de l’application. Mais tous ici peuvent facilement être reliés à des mémoires Flash.
Chaque bus est très lié à son constructeur et à ses partisans, mais tout le monde est d’accord
sur l’importance des mémoires Flash. Et pour les mémoires Flash, il y a plusieurs
constructeurs mais peu de variantes. Elle a su s’imposer rapidement et est devenue notre
quotidien.
10
Annexe
Driver I²C pour 6502
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
Devices are accessed using the following four subroutines.
SendAddr
This routine sends the slave address to the I2C bus.
It can also send any required register address bytes
by setting them up as you would data to be sent.
No stop is sent so you can either read or write after
calling this routine.
SendData
Send data byte(s) to an addressed device. Set the count
in I2cCountL/H and point to the data with TxBuffL/H
No stop is sent after calling this routine.
ReadData
StopI2c
Read data byte(s) from an addressed device. Set the count
in I2cCountL/H and point to the buffer with RxBuffL/H
No stop is sent after calling this routine.
generates a stop condition on the i2c bus
; Each device has an 8 bit address, the lowest bit of which is a read/write
; bit.
I2CPort
inputs
RxBuffL
TxBuffL
RxBuffH
TxBuffH
ByteBuff =
I2cAddr
I2cCountL
I2cCountH
JMP
JMP
JMP
JMP
;
;
;
;
;
;
;
=
$F121
=
=
=
=
$F3
=
=
=
; bit 0 is data [SDA]
; bit 1 is clock [SLC]
; bits 2 to 7 are unused
$F1
; receive buffer pointer low byte
RxBuffL
; the same (can't do both at once!)
$F2
; receive buffer pointer high byte
RxBuffH
; the same (can't do both at once!)
; byte buffer for Tx/Rx routines
$F4
; Tx/Rx address
$F5
; Tx/Rx byte count low byte
$F6
; Tx/Rx byte count high byte
*=
$2000
SendData
ReadData
SendAddr
StopI2c
; i2c bus port, o.c. outputs, tristate
; test vector to send
; test vector to read
; test vector to send
; test vector
data
data
slave address
to send stop
send the slave address for an i2c device
if I2cCountL is non zero then that number of bytes will be
sent after the address (to allow register addressing, required
on some devices)
RxBuff is a pointer, in page zero, to the transmit buffer
exits with the clock low and Cb=0 if all ok
routine entered with the i2c bus in a stopped state [SDA=SCL=1]
SendAddr
LDA
ORA
STA
LDA
STA
LDA
I2CPort
#$01
I2CPort
#$03
I2CPort
#$01
;
;
;
;
;
;
get i2c port state
release data
out to i2c port
release clock
out to i2c port
set for data test
WaitAD
11
BIT
BEQ
LDA
I2CPort
WaitAD
#$02
BIT
BEQ
JSR
LDA
JSR
BCS
LDA
BNE
RTS
I2CPort
WaitAC
StartI2c
I2cAddr
ByteOut
StopI2c
I2cCountL
SendData
; test the clock line
; wait for the data to rise
; set for clock test
WaitAC
;
;
;
;
;
;
; test the clock line
; wait for the clock to rise
; generate start condition
; get address (including read/write bit)
; send address byte
; branch if no ack
; get byte count
; go send if not zero
; else exit
send data to an already addressed i2c
I2cCountL/H is the number of bytes to
RxBuff is a pointer, in page zero, to
exits with Cb=0 if all ok
it is assumed at least one byte is to
routine entered with the i2c bus in a
device
send
the transmit buffer
be sent
held state [SCL=0]
SendData
INC
LDY
WriteLoop
LDA
JSR
BCS
INY
BNE
INC
NoHiWrInc
DEC
BNE
DEC
BNE
RET
;
;
;
;
;
;
I2cCountH
#$00
; increment count high byte
; set index to zero
(RxBuffL),Y
ByteOut
StopI2c
NoHiWrInc
RxBuffH
;
;
;
;
;
;
get byte from buffer
send byte to device
branch if no ack
increment index
branch if no rollover
else increment pointer high byte
I2cCountL
WriteLoop
I2cCountH
WriteLoop
;
;
;
;
decrement count
loop if not all
increment count
loop if not all
low byte
done
high byte
done
get data from already addressed i2c device
I2cCountL/H is the number of bytes to get
RxBuff is a pointer, in page zero, to the receive buffer
exits with Cb=0 if all ok
it is assumed at least one byte is to be received
routine entered with the i2c bus in a held state [SCL=0]
ReadData
INC
LDY
I2cCountH
#$00
; increment count high byte
; set index to zero
ReadLoop
JSR
CLC
JSR
LDA
STA
INY
BNE
INC
NoHiRdInc
DEC
BNE
DEC
BNE
RTS
ByteIn
NoHiRdInc
TxBuffH
; get byte from device
; clear for zero ack
; send ack bit
; get byte from byte buffer
; save in device buffer
; increment index
; branch if no rollover
; else increment pointer high byte
I2cCountL
ReadLoop
I2cCountH
ReadLoop
;
; loop if
;
; loop if
DoAck
ByteBuff
(TxBuffL),Y
decrement count low byte
not all done
decrement count high byte
not all done
; generate stop condition on i2c bus. it is assumed only that
; the clock is low on entry to this routine.
StopI2c
12
;
;
LDA
STA
NOP
LDA
STA
NOP
LDA
STA
RTS
#$00
I2CPort
#$02
I2CPort
#$03
I2CPort
;
;
;
;
;
;
;
;
now hold the data down
out to i2c port
need this if running >1.9MHz
release the clock
out to i2c port
need this if running >1.9MHz
now release the data (stop)
out to i2c port
; generate start condition on i2c bus. it is assumed that both
; clock and data are high on entry to this routine.
; note, another condition is A=$02 on entry
StartI2c
;
STA
NOP
LDA
STA
RTS
I2CPort
#$00
I2CPort
;
;
;
;
out to i2c port
need this if running >1.9MHz
clock low, data low
out to i2c port
; output byte to 12c bus, byte is in A. returns Cb=0 if ok
; clock should be low after generating a start or a previously
; sent byte
; exits with clock held low
ByteOut
OutLoop
;
STA
LDX
ByteBuff
#$08
; save byte for transmit
; 8 bits to do
LDA
ROL
ROL
STA
NOP
ORA
STA
LDA
#$00
ByteBuff
A
I2CPort
; unshifted clock low
; bit into carry
; get data from carry
; out to i2c port
; need this if running >1.9MHz
; clock line high
; out to i2c port
; set for clock test
BIT
BEQ
LDA
AND
STA
DEX
BNE
I2CPort
WaitT1
I2CPort
#$01
I2CPort
#$02
I2CPort
#$02
WaitT1
OutLoop
;
;
;
;
;
;
;
test the clock line
wait for the clock to rise
get data bit
set clock low
out to i2c port
decrement count
branch if not all done
; clock is low, data needs to be released, then the
; clock needs to be released then we need to wait for
; the clock to rise and get the ack bit.
GetAck
LDA
STA
LDA
STA
LDA
#$01
I2CPort
#$03
I2CPort
#$02
;
;
;
;
;
float data
out to i2c port
float clock, float data
out to i2c port
set for clock test
BIT
BEQ
LDA
LSR
LDA
STA
RTS
I2CPort
WaitGA
I2CPort
A
#$01
I2CPort
;
;
;
;
;
;
test the clock line
wait for the clock to rise
get data
data bit to Cb
clock low, data released
out to i2c port
WaitGA
13
; input byte from 12c bus, byte is returned in A. entry should
; be with clock low after generating a start or a previously
; sent byte
; exits with clock held low
ByteIn
LDX
LDA
STA
#$08
#$01
I2CPort
; 8 bits to do
; release data
; out to i2c port
LDA
STA
LDA
#$03
I2CPort
#$02
; release clock
; out to i2c port
; set for clock test
BIT
BEQ
LDA
ROR
ROL
LDA
STA
DEX
BNE
RTS
I2CPort
WaitR1
I2CPort
A
ByteBuff
#$01
I2CPort
; test the clock line
; wait for the clock to rise
; get data
; bit into carry
; bit into buffer
; set clock low
; out to i2c port
; decrement count
; branch if not all done
InLoop
WaitR1
InLoop
; clock is low, ack needs to be set then the clock released
; then we wait for the clock to rise before pulling it low
; and finishing. Ack bit is in Cb
DoAck
;
LDA
ROL
STA
NOP
ORA
STA
LDA
#$00
A
I2CPort
#$02
I2CPort
#$02
;
;
;
;
;
;
;
unshifted clock low
get ack from carry
out to i2c port
need this if running >1.9MHz
release clock
out to i2c port
set for clock test
BIT
BEQ
LDA
AND
STA
RTS
I2CPort
WaitTA
I2CPort
#$01
I2CPort
;
;
;
;
;
test the clock line
wait for the clock to rise
get ack back
hold clock
out to i2c port
WaitTA
14
Téléchargement