Академический Документы
Профессиональный Документы
Культура Документы
Encode a clock with data so that clock be extracted or data has guaranteed transition density with receiver clock via Phase-Locked-Loop (PLL)
IEEE Firewire (clock encoded in data) USB (data has guaranteed transition density)
V 0.1
V 0.1
Multi-Receiver
Each peripheral must have a SELECT line that is asserted that indicates this serial communication is for them.
SCL
A2 A1
SDA
From: The Quintessential PIC Microcontroller, Sid Katzen
A0
4
V 0.1
V 0.1
I2C Features
Multiple receivers do not require separate select lines as in SPI
At start of each I2C transaction a 7-bit device address is sent Each device listens if device address matches internal address, then device responds
SDA (data line) is bidirectional, communication is half duplex SDA, SCLK are open-drain, require external pullups
Allows multiple bus masters (will discuss this more later).
V 0.1
I2C Transmission
V 0.1
Acknowledgement
ACK sent by slave after every 8-bits received. Master releases line (stops driving), samples line on next clock. Slave MUST pull line low. If Master does not detect ACK, then sets error bit. If Slave does not pull line low, the pullup resistors will pull the line low. Most common cause of ACK error incorrect device address.
Speed Comparison
Assume a 400 Khz I2C bus, 2.5 us clock period (2.5 e-6) Random write:
9 bit transmission = 2.5 us * 9 = 22.5 us 5 ms + 22.5 us* 4 (control,addhi,addlo,data) =5.09 ms For 64 bytes = 325 ms approximately, not counting software overhead.
Page Write
67 bytes total (control, addhi, addlo, data) 5 ms + 67 * 22.5 us = 6.5 ms!!! Address must be on a page boundary. For page size = 64 = 0x40, starting address must be a multiple of 64.
V 0.1 11 V 0.1 12
V 0.1
13
V 0.1
Sequential Read
Like a current address read, but after Slave sends data byte, Master sends ACK instead of STOP
Slave then sends next byte Can do this from 0x0000h to 0x7FFF (lower 32K block). When 0x7FFF is reached, address rolls over to 0x0000 Upper block goes from 0x8000 to 0xFFFF; at 0xFFFF address rolls over to 0x8000 Internal address counter is only 15 bits wide.
To set I2C clock rate, write 8-bit value to the SPADD register
Clock rate = Fosc/(4 *(SSPADD+1))
I2C standard defines 100 KHz and 400 KHz but in reality just about any clock rate from DC to 400 KHz wors
V 0.1
18
i2cmsu.c Subroutines
i2c_idle() wait for idle condition on I2C bus i2c_Start() send a START and wait for START end i2c_Stop() send a STOP and wait for STOP end i2c_doAck() do an ACK cycle i2c_doNak() do a NACK cycle i2c_WriteTo(address) do a i2c_Start(), then send address to I2C bus. i2c_PutByte(byte) write byte to I2C, wait for finish, then get an ACK i2c_GetByte() get a byte from I2C bus
The file memblk.c tests uses the subroutines to read/write data to the serial EEPROM.
V 0.1
19
V 0.1
20
memread(cmd,addr)
/* random read */ unsigned char mem_read(unsigned char cmd,int addr) { unsigned char hbyte, lbyte, val;
cmd is unsigned char that has EEprom i2c device address addr is unsigned char is memory address within EEprom Set internal address counter. Read byte from current address
if (addr & 0x8000) { // if MSB set , set block select bit cmd = cmd | 0x08; } hbyte = (addr >> 8) & 0x7F; // high address byte lbyte = (addr) & 0xFF; // low address byte i2c_WriteTo(cmd); // send write cmd, do this to set address counter i2c_PutByte(hbyte); // send high address byte i2c_PutByte(lbyte); // send low address byte i2c_Stop(); // send stop cmd = cmd | 0x1; // set read bit i2c_WriteTo(cmd); // send read cmd, address set by previous cmd val = i2c_GetByte(); // read data i2c_Stop(); // send stop return(val); }
V 0.1 22
i2c_Writeto (write_cmd) i2c_PutByte (address_hibyte) i2c_PutByte (address_lobyte) i = 0; i2c_PutByte (); i++ i = 64?
Page Write
set starting address.
Send 64 bytes.
hbyte = (addr >> 8) & 0x7F; // high address byte lbyte = (addr) & 0xFF; // low address byte i2c_WriteTo(cmd); // send write cmd i2c_PutByte(hbyte); // send high address byte i2c_PutByte(lbyte); // send low address byte for (k=0;k<64;k++) { Uncomment if //i2c_PutByte(buf[k]); // send data i2c_FastPutByte(buf[k]); // send data subroutine called } more often than 5 i2c_Stop(); //DelayMs(5); }
ms.
i2c_Stop()
V 0.1 23
FastPutByte does not check for idle condition before sending data.
V 0.1 24
Block Read
set starting address. Send read command Use sequential read to get 64 bytes. Sequential read can read up to 32K, block size of 64 bytes was arbitrary 25
i2c_doAck();
i2c_Stop()
V 0.1
/* block read */ void block_mem_read(unsigned char cmd,int addr,char *buf) { unsigned char hbyte; unsigned char lbyte; unsigned char k; if (addr & 0x8000) { // if MSB set , set block select bit cmd = cmd | 0x08; } hbyte = (addr >> 8) & 0x7F; // high address byte lbyte = (addr) & 0xFF; // low address byte i2c_WriteTo(cmd); // send write cmd, do this to set address counter i2c_PutByte(hbyte); // send high address byte i2c_PutByte(lbyte); // send low address byte i2c_Stop(); // send stop cmd = cmd | 0x1; // set read bit i2c_WriteTo(cmd); for (k=0;k<64;k++){ buf[k] = i2c_GetByte(); // read data if (k== 63) i2c_Stop(); // last byte, so send stop else i2c_doAck(); // do ack if not at end } }
V 0.1 26
Block Read in C
written!
V 0.1
28
i2c_idle()
i2c_idle() { unsigned char byte1; unsigned char byte2; do { byte1 = SSPSTAT & 0x04; byte2 = SSPCON2 & 0x1F; }while (byte1 | byte2); return; } // gte R/W bit.
i2c_Start()/i2c_Stop()
i2c_Start(){ i2c_idle(); /* initiate start, SEN=1 */ bitset(SSPCON2,0); /* wait until start finished */ while (bittst(SSPCON2,0)); } i2c_Stop() { i2c_idle(); /* initiate stop, PEN=1 */ bitset(SSPCON2,2); /* wait until stop finished */ while (bittst(SSPCON2,2)); }
V 0.1
Check if lower 5 bits are all 0 indicating that Start, Stop, Acknowledge sequences are all idle.
V 0.1 29
i2c_PutByte()
i2c_PutByte(unsigned char byte) { i2c_idle();
i2c_WriteTo
i2c_WriteTo(unsigned char addr) { /* first, send start */ i2c_Start(); SSPBUF = addr; /* write data */ /* wait until finished */
i2c_FastPutByte deletes this call. SSPBUF holds outgoing data Cleared when transmit finished. Cleared when ACK received.
V 0.1 31
/* write data */ SSPBUF = byte; /* wait until finished */ while(bittst(SSPSTAT,2)); /* wait for acknowledge */ while(bittst(SSPCON2,6)); }
V 0.1
32
i2c_GetByte()
unsigned char i2c_GetByte() { unsigned char byte; i2c_idle(); /* initiate read event */ bitset(SSPCON2,3); /* wait until finished */ while(bittst(SSPCON2,3)); while (!(bittst(SSPSTAT,0))); byte = SSPBUF; return(byte); } /* read data */
Enable receive Will be cleared when finished. Receive buffer should be full
Interrupt service routine stores bytes in a buffer. Problem: While writing bytes to serial EEPROM, more bytes are arriving!!! Solution: Use two buffers! Second buffer captures data while first buffer data written to EEPROM.
V 0.1 34
Get data
V 0.1 33
Two Buffers
Interrupt Service Subroutine
While writing data to EEPROM from one buffer, use other buffer to receive incoming data. ISR sets write_flag to indicate to main() that 64 bytes has been received, and that block_mem_write() should be called. active_buffer flag set by main() to indicate what buffer the ISR uses for byte storage.
35
At least one of the 64 byte buffers MUST be in bank1, not enough room for both in bank0. V 0.1
Serial EEPROM
Sequential, Random Read operations Random, Block Write operations
V 0.1
37