I2C and a Serial EEPROM

advertisement
Synchronous Serial IO
Serial Peripheral Interface (SPI)
Three wire interface: SCK (clock), SDO (serial data out),
SDI (Serial Data Out)
• Send a separate clock line with data
– SPI (serial peripheral interface) protocol
– I2C (or I2C) protocol
SDO, SDI is uni-directional, but communication can occur in
both directions at same time (full-duplex).
• 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)
From: The Quintessential PIC Microcontroller, Sid Katzen
V 0.1
1
V 0.1
2
I2C (Inter-Integrated-Circuit) Bus
Multi-Receiver
I2C is a two wire serial interface.
Each peripheral must have a SELECT line that
is asserted that indicates this serial
communication is for them.
16F873
Vdd
10K
Microchip 24LC515
SCL
SCL
A2
Vdd
A1
10K
SDA
SDA
SCL
SCL – clock line
SDA – data
(bidirectional)
V 0.1
3
I2C Features
A0
V 0.1
4
Example: I2C Serial EEPROM
• Multiple receivers do not require separate select
lines as in SPI
Will use the Microchip 24LC515 Serial EEPROM to discuss I2C
operation.
– 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
The 24LC515 is a 64K x 8 memory. This would require 16
address lines, and 8 data lines if a parallel interface was
used, which would exceed the number of available IO pins
our PIC16873!!!
• SDA (data line) is bidirectional, communication is
half duplex
• SDA, SCLK are open-drain, require external
pullups
Putting a serial interface on a memory device lowers the
required pin count.
Reduces speed since data has to be sent serially, but now
possible to add significant external storage to a low pincount micro controller.
– Allows multiple bus masters (will discuss this more
later).
V 0.1
A2
A1
SDA
From: The Quintessential PIC Microcontroller, Sid Katzen
A0
5
V 0.1
6
1
IDLE: SCL,
SDA high.
I2C Device Addressing
Each I2C device has either a 7-bit or 10-bit device address.
I2C Transmission
We will use an I2C EEPROM and an I2C DAC (Digital-toAnalog Converter, MAX517) in lab. Both of these devices
have a 7-bit address.
Upper four bits are assigned by device manufacturer and are
hardcoded in the device. Lower three bits are used in
different ways by manufacturer.
LC515 control byte (contains slave address):
Microchip 24LC515
R/W = 1
SCL A2
7654 3 2 1 0
for read, 0
1 0 1 0 B0 A1 A0 R/W for write.
A1
‘B0’ is block select (upper/lower 32K). A1, A0
SDA A0
are chip selects, four devices on one bus.
V 0.1
7
START: high
to low
transition on
SDA while
SCL high.
Acknowledgement
Valid data:
While clock is
high, data
valid and
stable.
V 0.1
Data
changes
while
clock is
low.
STOP: low to
high transition
on SDA while
SCL high.
8
Byte Write Operation
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.
• Byte Write: used to write one byte
– Send Control Byte, High address byte, low address
byte, data.
– After data is sent, takes 5 ms for write to complete
– SLOOOOOWWWWWW....
Most common cause of ACK error – incorrect device address.
‘0’ indicates write mode.
V 0.1
9
V 0.1
Page Write Operation
‘X’ because block select bit
chooses high or low 32K. 10
Speed Comparison
• Send a block of 64 bytes, then perform write
• Assume a 400 Khz I2C bus, 2.5 us clock period
(2.5 e-6)
• Random write:
– Send starting address, followed by 64 bytes
– After 64 bytes sent, wait 5 ms for write to complete
– Much faster than individual writes
– 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
2
Checking for end-ofwrite
Read Operation: Current Address
• An internal counter is used to keep track of last
address used
• A current address read uses this address, only
sends the command byte
Timing on write is
guaranteed to finish after 5
ms. But can end sooner; to
determine if write finished
use polling method.
– Internal counter incremented after read operation
‘1’ indicates read
operation
No ACK means device is
still busy with last write.
V 0.1
13
Random Read Operation
• 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.
Current address read
V 0.1
15
PIC 16 I2C Registers
V 0.1
16
I2C on the PIC16
• Synchronous Serial Port on PIC implements I2C
• Registers are:
• Will always use master mode on the PIC16
– SSPCON – control register - we will always set this to
0x28 which enables I2C MASTER mode.
– SSPCON1 – control register - used to initiate a
START/STOP conditions, indicates if ACK has been
received
– SSPSTAT – status register – check this to see if byte
finished transmitting, or byte has been received
– SSPBUF – read/write to this register for data transfer
– SSPADD – used to control clock rate
V 0.1
14
Sequential Read
• Must first set the internal address counter by
starting a write operation, but aborting by not
sending data byte
Aborted random write (address only,
no data)
V 0.1
‘no ack’ because slave is
driving data back to
master.
17
– This means that the PIC will always initiate all I2C bus
activity
• 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
3
i2cmsu.c Subroutines
Lab #8: Read/Write to Serial EEPROM
• 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
• Lab #8 has you read/write to a Serial EEPROM
via the I2C bus
• The files i2cmsu.h, i2cmsu.c define interface
subroutines for the I2C bus
– This file also has subroutines for random read/write,
block read/write for the serial eeprom
• The file memblk.c tests uses the subroutines to
read/write data to the serial EEPROM.
V 0.1
19
V 0.1
Random Read: memread(cmd,addr)
memread(cmd,addr)
cmd is unsigned char
that has EEprom i2c
device address
i2c_Writeto (write_cmd)
i2c_PutByte (address_hibyte)
Does a random read of EEPROM
/* random read */
unsigned char mem_read(unsigned char cmd,int addr) {
unsigned char hbyte, lbyte, val;
addr is unsigned char is
memory address within
EEprom
i2c_PutByte (address_lobyte)
i2c_Stop()
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);
Set internal address
counter.
i2c_Writeto (read_cmd)
Read byte from
current address
i2c_GetByte ()
20
}
i2c_Stop()
V 0.1
i2c_Writeto (write_cmd)
21
V 0.1
Page (Block) Write
Page Write
i2c_PutByte (address_hibyte)
/* block write */
void block_mem_write(unsigned char cmd,int addr, char *buf)
unsigned char hbyte, lbyte, val;
set starting
address.
i2c_PutByte (address_lobyte)
Send 64 bytes.
i = 64?
//DelayMs(5);
}
i2c_Stop()
V 0.1
{
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();
i = 0;
i2c_PutByte (); i++
22
23
ms.
// no need to delay, will not be back here for 5 ms
FastPutByte does not check for idle condition before
sending data.
V 0.1
24
4
i2c_Writeto (write_cmd)
Block Read in C
Block Read
i2c_PutByte (address_hibyte)
set starting
address.
i2c_PutByte (address_lobyte)
i2c_Stop()
Send read
command
i2c_Writeto (read_cmd)
Use sequential
read to get 64
bytes.
i2c_GetByte (); i++
i = 64?
no
i2c_doAck();
Sequential read can read up
to 32K, block size of 64
bytes was arbitrary 25
yes
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
EEPROM Test: memblk.c
EEPROM Test: memblk.c
memblk.c tests serial EEPROM by doing block read/write
to EEPROM.
printf("Enter 'w'(write), or 'r' (read): ");
pcrlf ();
inchar=getch();
Read 64 bytes from
if (inchar == 'w') {
address 0, store in buffer.
// see previous slide
}else if (inchar == 'r') {
printf("###Reading first 64 memory locations, via a block read");
pcrlf ();
block_mem_read(ROM,0,buf);
for (i=0;i<64;i++) {
printf("Read %d, val: %x (%c) \n",i,buf[i], buf[i]);
pcrlf ();
}
pcrlf ();
Print the 64 bytes read
printf("###Mem Read complete");
from EEPROM, hopefully
pcrlf ();
}
they will match what was
printf("Enter 'w'(write), or 'r' (read): ");
pcrlf ();
From main(), ask user for
inchar=getch();
if (inchar == 'w') {
write or read test.
pcrlf ();
printf("Capturing next 64 bytes for write to memory");
pcrlf ();
Get 64 bytes from serial
for (i=0;i<64;i++) {
buf[i] = getch();
port, save in buffer.
}
printf("Block write to memory");
Print
bytes before write to
pcrlf ();
EEPROM.
for (i=0;i<64;i++) {
printf("Write at %d, val: %x (%c) \n",i,buf[i], buf[i]);
pcrlf ();
}
Write bytes to EEPROM
block_mem_write(ROM,0,buf);
at address 0.
printf("Mem Write complete");
pcrlf ();
} elsif...
V 0.1
written!
27
V 0.1
i2c_idle()
unsigned char byte1;
unsigned char byte2;
28
i2c_Start()/i2c_Stop()
i2c_Start(){
i2c_idle();
/* initiate start, SEN=1 */
bitset(SSPCON2,0);
/* wait until start finished */
while (bittst(SSPCON2,0));
R/W bit, when ‘0’
then transmit is not
in progress
i2c_idle()
{
26
begin START
wait for end
}
do {
byte1 = SSPSTAT & 0x04;
byte2 = SSPCON2 & 0x1F;
}while (byte1 | byte2);
return;
}
// gte R/W bit.
Check if lower 5 bits are all ‘0’ indicating
that Start, Stop, Acknowledge sequences
are all idle.
V 0.1
29
i2c_Stop() {
i2c_idle();
/* initiate stop, PEN=1 */
bitset(SSPCON2,2);
/* wait until stop finished */
while (bittst(SSPCON2,2));
}
V 0.1
begin STOP
wait for end
30
5
i2c_PutByte()
i2c_WriteTo
i2c_PutByte(unsigned char byte) {
i2c_FastPutByte deletes this call.
i2c_idle();
i2c_WriteTo(unsigned char addr) {
/* first, send start */
i2c_Start();
SSPBUF = addr; /* write data */
SSPBUF holds
outgoing data
/* write data */
SSPBUF = byte;
/* wait until finished */
while(bittst(SSPSTAT,2));
/* wait until finished */
Cleared when
transmit finished.
/* wait for acknowledge */
while(bittst(SSPCON2,6));
while(bittst(SSPCON2,6));
Cleared when
ACK received.
V 0.1
31
Enable receive
bitset(SSPCON2,3);
/* wait until finished */
while(bittst(SSPCON2,3));
while (!(bittst(SSPSTAT,0)));
Will be cleared when
finished.
Receive buffer
should be full
Interrupt Service
Subroutine
1
Active buffer?
64 bytes?
Save char in buff1
no
64 bytes?
yes
yes
Write_flag = 1
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.
33
Two Buffers
Char arrival
triggers interrupt
no
Interrupt service routine
stores bytes in a buffer.
Get data
V 0.1
Save char in buff0
Capture 64
bytes from
serial port to
buffer
Page Write of 64
bytes
/* read data */
}
Write_flag = 1
exit interrupt service
At least one of the 64 byte buffers
MUST be in bank1, not enough
room for both in bank0.
V 0.1
32
Lab 9: I2C & Serial EEPROM
unsigned char byte;
0
V 0.1
Goal: Capture streaming data from serial port, store to serial
EEPROM
unsigned char i2c_GetByte() {
return(byte);
Cleared when
ACK received.
}
i2c_GetByte()
byte = SSPBUF;
Cleared when
transmit finished.
while(bittst(SSPSTAT,2));
/* wait for acknowledge */
}
i2c_idle();
/* initiate read event */
SSPBUF holds
outgoing data
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
V 0.1
34
Streaming Write Loop: main()
Streaming Write Loop
0
Write_flag?
Wait for interrupt service
routine to fill a buffer.
1
0
Active buffer?
1
Active buffer = 1
Active buffer = 0
Page write buff0
Page write buff1
Write_flag = 0
addr = addr + 64
V 0.1
36
6
What do you have know?
• Serial Peripheral Interface (SPI) – how is this
different from I2C?
• I2C Protocol
– What is start, stop, ack conditions, purpose of each
– How is data sent, received
– Device addressing
• Serial EEPROM
– Sequential, Random Read operations
– Random, Block Write operations
V 0.1
37
7
Download