protocolo i2c

12
Ming Hsieh Department of Electrical Engineering EE 459Lx - Embedded Systems Design Laboratory Using the I 2 C Interface on the ATmega328P and MC908JL16 by Allan G. Weber 1 Introduction The I 2 C or I2C (Inter-Integrated Circuit ) interface is a serial bus intended for communication between two or more integrated circuits on the same PC or prototyping board. Also known as a “two-wire bus”, this bus is for communication with many different types of IC’s such as EEPROMs, real-time clock, temperature sensors, etc. The I 2 C interface is not particularly fast so it is typically used for connecting to IC’s that do not require large amounts of data to be transferred rapidly. Some of the microcontrollers used in EE459Lx such as the Atmel ATmega328P and the Freescale MC908JL16 implement this interface in hardware. The Atmel documentation calls the I 2 C interface the “Two Wire Interface” while the Freescale documentation refers to it as “MMIIC” (Multi-Master IIC) but it’s the same thing. The hardware on these microcontrollers perform many of the lower level tasks required for transferring data on the I 2 C bus. For example, to write data to a I 2 C device, the program sets up the transfer, starts it, keeps a data buffer full with the next byte to be sent and finally terminates the transfer at the end. The signaling required for sending each bit is handled by the hardware. Reading is done in a similar manner. Software-only implementations of the I 2 C protocol can also be used to provide this interface on micro- controllers that do not have I 2 C hardware. The Agilent and Tektronix oscilloscopes in the OHE 240 lab have special triggering capabilities that make it possible to analyze I 2 C data transfers. Individual data transfers can be captured and viewed so that the transfer can be examined in detail to see if the correct information is being sent or received. This capability of these scopes is an extremely useful tool for students trying to debug any I 2 C aspects of their projects. 1.1 Device Addresses In order to use the I 2 C interface you need to know the address of the device on the I 2 C bus. The address is a seven bit number but is often written as an eight-bit number where the upper seven bits are the address and the least significant bit indicates whether a read or write is occurring. Most manufacturer’s datasheets provide the eight bit number with the least significant bit set to zero. Table 1 shows the 8-bit value (7-bit address + R/W flag) for some common devices used in EE459 projects. Some I 2 C devices allow you to specify one or more of the least significant bits of the seven-bit address by connecting pins on the chip to a logical zero or one. This make it possible to have more than one device of the same type on the bus or to avoid address conflicts with other devices. The number of extra address bits available is indicated in Table 1. 1.2 Reading Data Many I 2 C devices require reading operations to be done in two steps. The first part of the reading operation consists of writing the address of the first location to be read into an internal buffer. The write operation is EE 459Lx, Rev. 12/24/14 1

Post on 11-Sep-2015

286 views

Category:

Documents


1 download

DESCRIPTION

Protocolo i2c

TRANSCRIPT

  • Ming Hsieh Department of Electrical Engineering

    EE 459Lx - Embedded Systems Design Laboratory

    Using the I2C Interface on theATmega328P and MC908JL16

    by

    Allan G. Weber

    1 Introduction

    The I2C or I2C (Inter-Integrated Circuit ) interface is a serial bus intended for communication between twoor more integrated circuits on the same PC or prototyping board. Also known as a two-wire bus, thisbus is for communication with many different types of ICs such as EEPROMs, real-time clock, temperaturesensors, etc. The I2C interface is not particularly fast so it is typically used for connecting to ICs that donot require large amounts of data to be transferred rapidly.

    Some of the microcontrollers used in EE459Lx such as the Atmel ATmega328P and the FreescaleMC908JL16 implement this interface in hardware. The Atmel documentation calls the I2C interface theTwo Wire Interface while the Freescale documentation refers to it as MMIIC (Multi-Master IIC) butits the same thing.

    The hardware on these microcontrollers perform many of the lower level tasks required for transferringdata on the I2C bus. For example, to write data to a I2C device, the program sets up the transfer, startsit, keeps a data buffer full with the next byte to be sent and finally terminates the transfer at the end. Thesignaling required for sending each bit is handled by the hardware. Reading is done in a similar manner.

    Software-only implementations of the I2C protocol can also be used to provide this interface on micro-controllers that do not have I2C hardware.

    The Agilent and Tektronix oscilloscopes in the OHE 240 lab have special triggering capabilities that makeit possible to analyze I2C data transfers. Individual data transfers can be captured and viewed so that thetransfer can be examined in detail to see if the correct information is being sent or received. This capabilityof these scopes is an extremely useful tool for students trying to debug any I2C aspects of their projects.

    1.1 Device Addresses

    In order to use the I2C interface you need to know the address of the device on the I2C bus. The address isa seven bit number but is often written as an eight-bit number where the upper seven bits are the addressand the least significant bit indicates whether a read or write is occurring. Most manufacturers datasheetsprovide the eight bit number with the least significant bit set to zero. Table 1 shows the 8-bit value (7-bitaddress + R/W flag) for some common devices used in EE459 projects.

    Some I2C devices allow you to specify one or more of the least significant bits of the seven-bit addressby connecting pins on the chip to a logical zero or one. This make it possible to have more than one deviceof the same type on the bus or to avoid address conflicts with other devices. The number of extra addressbits available is indicated in Table 1.

    1.2 Reading Data

    Many I2C devices require reading operations to be done in two steps. The first part of the reading operationconsists of writing the address of the first location to be read into an internal buffer. The write operation is

    EE 459Lx, Rev. 12/24/14 1

  • IIC Device Description 8-bit Base Number of ExtraAddress Address Bits

    24LC256 32KB EEPROM 0xA0 3DS1307 Real-time clock 0xD0 nonePCF8563 Real-time clock 0xA2 noneDS1621, DS1631 Temperature sensor 0x90 3MCP23008 8-bit port expander 0x40 3MCP23017 16-bit port expander 0x40 3MAX7311 16-bit port expander 0x40 3

    Table 1: I2C Device Addresses

    then terminated and a read command is sent. This causes the device to start sending data from the locationgiven by the data that was previously written to it. The number of bytes that must be written before theread can be done is dependent on the device.

    2 I2C on the ATmega328P

    The ATmega328P uses pins 27 and 28 for the I2C data and clock. When I2C is not used these pins can beused as general I/O ports PC4 and PC5.

    2.1 Initializing

    The internal I2C hardware needs to have the baud rate (I2C clock rate) set before any transfers can takeplace. The maximum rate that the I2C device can handle should be described in the devices datasheet,but most devices should be able to operate with a clock up to 100kHz. The clock is derived from themicrocontrollers clock by dividing it down according to this formula.

    I2C Baud Rate =CPU Clock Frequency

    16 + 2(TWBR) (prescalar value)The prescalar value is set by a two bit number in the TWSR register and can be either 1, 4, 16 or 64. The

    TWBR value is the eight-bit contents of the TWBR register. This value can be calculated if we rearrange theabove formula to solve for TWBR

    TWBR =

    (CPU Clock Frequency

    I2C Baud Rate

    ) 16)/(2 prescalar value)

    A suitable value for TWBR can be calculated in the program source code using compiler preprocessorstatements. For example, if we want a baud rate of 100kHz, we can set the prescalar to one and then usethe following to determine the value to go in the TWBR register.

    #define FOSC 9830400 // Clock frequency = Oscillator freq.

    #define BDIV (FOSC / 100000 - 16) / 2 + 1

    TWSR = 0; // Set prescalar for 1

    TWBR = BDIV; // Set bit rate register

    The +1 at the end of the statement calculating BDIV is needed since the integer calculations done bythe preprocessor could have truncation errors resulting in a value of BDIV that is too low and giving an I2Cfrequency over 100kHz. The +1 makes sure the frequency is below 100kHz.

    2.2 Writing

    The following is an example of a function that writes n bytes of data from array p to an I2C devicewith the 8-bit address device_addr. Most of code in this routine consists of slight variations of the same

    EE 459Lx, Rev. 12/24/14 2

  • thing: load the data register with data, set the control register to send it, wait for it to be sent, and checkthe status.

    /*

    i2c_write - write bytes to an I2C device

    */

    uint8_t i2c_write(uint8_t device_addr , char *p, uint16_t n)

    {

    uint8_t status;

    To start the transmission, the control register is set to signal a start condition on the bus.

    TWCR = (1

  • */

    uint8_t i2c_read2(uint8_t device_addr , char *p, uint16_t n, uint16_t a)

    {

    uint8_t status;

    // To read , first write the device address and two bytes

    // of the internal address

    TWCR = (1

  • to be read.

    // Read all but the last of n bytes from the slave device in this loop

    n--;

    while (n-- > 0) {

    TWCR = (1

  • 3.2 Writing

    The following is an example of a function that writes n bytes of data from array p to an I2C device withthe 8-bit address dev_addr.

    The program first checks to make sure the number of bytes being written is non-zero. The addressregister, MMADR, is loaded with the 8-bit I2C device address which is actually the 7-bit address with a zeroadded as the least significant bit. The data register is loaded with the first byte of the data to be written. Inthe control register, the MMRW bit is set for a write, and finally the MMAST bit is set to start the transmission.The byte count is decremented since the first byte has already been sent as part of the initial steps in theprocess.

    /*

    i2c_write - Write bytes to an I2C device.

    */

    unsigned char i2c_write(unsigned char dev_addr , unsigned char *p,

    unsigned int n)

    {

    unsigned char status;

    status = 0; // 0 = operation worked

    if (n == 0) // check for no data

    return(status );

    MMADR = dev_addr; // Device address -> address reg

    MMDTR = *p++; // 1st byte of data

    MIMCR_MMRW = 0; // Set for transmit

    MIMCR_MMAST = 1; // Start transmission

    n--; // First byte already being sent

    If there are more bytes to send the programs loops through the following steps. First, wait for thetransmit buffer to be empty. The I2C transmit hardware consists of two registers, one (MMDTR) for holdingthe next byte to be transmitted, and a shift register that contains the byte currently being transmited. Thecontents of the MMDTR will be moved into the shift register for output as soon as that register is empty andat that time the MMTXBE bit will be set. When MMTXBE goes to a one, the MMSR_MMRXAK bit can be checked tosee if the previously transmitted byte resulted in and ACK or NAK response from the slave. If a NAK wasreceived, set the status value and go send a STOP condition. Otherwise load the MMDTR with the next byte.In summary, wait for byte k to clear out of the transmit buffer, check the ACK/NAK status for byte k 1,move byte k + 1 into the transmit buffer, and loop.

    while (n-- > 0) {

    while (!( MMSR_MMTXBE )); // Wait for TX buffer empty

    if (MMSR_MMRXAK) { // Check for NAK

    status = 1; // Set status for failed operation

    goto nakstop; // Go set STOP condition

    }

    MMDTR = *p++; // Next data -> MMDTR

    }

    When the value of the byte count, n, reaches zero the last data byte has been moved into MMDTR. Theprogram waits for MMTXBE to show that this byte has moved to the output shift register and checks theACK/NAK status of the previous byte. Due to an oddity in the JL16 the output hardware will not generatea clock signal to receive the acknowledge for the last byte unless there is some data in the transmit register.The solution is to write some dummy data into MMDTR. This will cause the proper I2C clock signal to beproduced for the ACK to be received.

    The MMAST bit is set to zero to generate a STOP condition after the byte currenting being transmitted issent. This ends the write before any of the dummy data gets transferred.

    EE 459Lx, Rev. 12/24/14 6

  • while (!( MMSR_MMTXBE )); // Wait for TX buffer empty

    if (MMSR_MMRXAK) // Check for NAK

    status = 1; // Set status for failed operation

    else

    MMDTR = 0xff; // Dummy data to get ACK clock

    nakstop:

    MIMCR_MMAST = 0; // Generate STOP bit

    return(status );

    }

    3.3 Reading

    The following function reads n bytes of data from an I2C device with the 8-bit address dev_addr. The16-bit address of where the data is to be read from is passed in the argument a, and the location wherethe data that is read is to be stored is in pointer p. The first part of the program is similar to the writingfunction described above. It loads the device address into register MMADR, the upper part of the address datainto MMDRT, set the mode to a write and starts the transmission.

    /*

    i2c_read2 - read bytes from an I2C device (two byte address)

    */

    unsigned char i2c_read2(unsigned char dev_addr , unsigned char *p,

    unsigned int n, unsigned int a)

    {

    unsigned char status;

    status = 0; // 0 = operation worked

    if (n == 0) // check for no data

    return(status );

    MMADR = dev_addr; // Device address -> address reg.

    MMDTR = a >> 8; // High byte of data address

    MIMCR_MMRW = 0; // Set for transmit

    MIMCR_MMAST = 1; // Initiate transfer

    The code that follows is essentially the writing loop from the write function unrolled into sending thelower part of the address data, and then the dummy data to allow it to wait for the acknowledge to bereceived for the second address byte. If the device only requires a one byte data address, then that addressbyte should be sent in the part above, and the first five lines below can be removed.

    while (!( MMSR_MMTXBE )); // Wait for TX buffer empty

    if (MMSR_MMRXAK) { // Check for NAK

    status = 1; // Set status for failed operation

    goto nakstop; // Go set STOP condition

    }

    MMDTR = a & 0xff; // Low byte of data address

    while (!( MMSR_MMTXBE )); // Wait for TX buffer empty

    if (MMSR_MMRXAK) { // Check for NAK

    status = 1; // Set status for failed operation

    goto nakstop; // Go set STOP condition

    }

    MMDTR = 0xff; // Dummy data to get ACK clock

    Now the registers are set up for reading. The device address is loaded into MMADR, the mode is set for aread, the Repeated Start bit is enabled, and the transfer is started. The command byte containing the

    EE 459Lx, Rev. 12/24/14 7

  • device address has to be sent so dummy data has to be put in the data register so the JL16 can receive theACK for this byte.

    MMCR_MMTXAK = 0 // MCU will ACK received data

    MMADR = dev_addr; // device address -> address reg.

    MIMCR_MMRW = 1; // Set for receive

    MMCR_REPSEN = 1; // Enable repeated start

    MIMCR_MMAST = 1; // Initiate transfer

    while (!( MMSR_MMTXBE )); // Wait for TX buffer empty

    if (MMSR_MMRXAK) { // Check for NAK

    status = 1; // Set status for failed operation

    goto nakstop; // Go set STOP condition

    }

    MMDTR = 0xff; // Dummy data to get ACK clock

    The program now loops n 1 times waiting for the receive buffer to be full and then transferring thereceived data to the array in memory.

    n--; // Loop n-1 times

    while (n > 0) {

    while (!( MMSR_MMRXBF )); // Wait for RX buffer full

    *p++ = MMDRR; // Get data

    n--; // Decrement total count

    }

    For the last byte, a flag is set telling the hardware to not send an ACK. Once the last byte is received,the hardware is made to generate a STOP bit and the reading operation is finished.

    MMCR_MMTXAK = 1; // Don t send ACK for last byte

    while (!( MMSR_MMRXBF )); // Wait for RX buffer full

    *p++ = MMDRR; // Get data

    nakstop:

    MIMCR_MMAST = 0; // Generate STOP bit

    return(status );

    }

    4 Viewing I2C Transfers on the Agilent 54622A Scopes

    The two-channel Agilent 54622A oscilloscopes have I2C triggering built in to them. To make use of thisfollow the steps below.

    1. Turn on the scope and then turn on both input channels by pressing the 1 and 2 buttons in thevertical section of controls until they light up.

    2. Use the large knobs above the 1 and 2 buttons to adjust the input levels for both channels to 5Volts per division. The levels for the channels are shown in the top left corner of the screen.

    3. Use the large knob in the horizontal section of the controls to change the horizontal sweep speed to200sec/div. The sweep speed is shown in the top center portion of the screen.

    4. The small knob in the horizontal section changes the horizontal position of the displayed signal. Usethis knob to move one of the small triangles near the top of the screen over closer to the left side ofthe screen. When an I2C signal is captured, it will be displayed with the starting point of the signalat this position.

    5. In the trigger section of the controls (Fig. 1), press the Edge button.

    EE 459Lx, Rev. 12/24/14 8

  • Figure 1: Agilent triggering controls Figure 2: Agilent trigger Mode menu

    6. Press the softkey below the screen for channel 1, and then use the Level knob in the triggering sectionto adjust the trigger voltage to around 2.5 Volts. The trigger voltage level is indicated in the top rightcorner of the screen. Press the softkey for channel 2 and set the channel 2 trigger level to around 2.5Volts.

    7. In the trigger section of the controls, press the Mode/Coupling button.

    8. If the left softkey doesnt say Mode Normal, press it to bring up the mode menu and press it againuntil Normal is selected.

    9. Connect the two scope probes to scope and then connect the probe tips to the I2C clock and data lineson your project board. Either one can be attached to either signal but make note of which way theyare connected.

    10. In the triggering section of the scope controls, press the More button.

    11. If the label of the second softkey does not say Trigger I2C, press this button to bring up the triggermode menu (Fig. 2) and then continue pressing it until the check mark is by I2C.

    12. Press the left softkey that is labeled Settings to bring up the I2C Trigger Menu screen

    13. The labels on two left most softkeys indicate which channel is assigned to the I2C clock and which is forthe data (Fig. 3). If the channel assignment is opposite to how you connected the probes, press eitherof the two softkeys for the channel assignments. This will bring up a menu for the channel assignmentand you can press that key again until the setting is correct. You dont need to change both channelsmanually since changing one causes the other to also change.

    14. Check the label on the third softkey to make sure it says Trigger: Start. If it doesnt, press this keyto bring up the Trigger on: menu (Fig. 4) and then press the button enough times to select Startcondition.

    At this point the scope is configured to trigger on a I2C Start condition. Press the Single button abovethe triggering controls to put the scope in a state where it will wait for the next Start condition on the I2C

    EE 459Lx, Rev. 12/24/14 9

  • Figure 3: Agilent channel selection Figure 4: Agilent trigger conditions

    bus and then capture the data. Do whatever is needed on your project board to get it to generate the I2Ctransfer, and once the data has been captured it will be displayed on the screen. The captured data canbe expanded or shrunk horizontally using the large knob in the horizontal section of controls. To scroll thedata left or right, use the small knob in the horizontal section.

    5 Viewing I2C Transfers on the Tektronix Scopes

    The four-channel Tektronix DPO2014 and MSO2014 oscilloscopes have I2C triggering as part of the DPO2EMBDoption. To make use of this follow the steps below. If at any time during the setup you want to make amenu disappear from the screen, press the Menu Off button near the lower right corner of the screen.

    1. Turn on the scope and then turn on two of four input channels by pressing the buttons with numberson them in the vertical section of controls until the traces appear on the screen. In this example welluse channels 1 and 2. The wide rectangular box at the lower left of the screen (Fig. 5) shows thechannels that have been turned on.

    2. Use the large Scale knobs below the 1 and 2 buttons to adjust the input levels for both channelsto 5 Volts per division. The levels for the channels are shown in the lower left part of the screen.

    3. Use the small knobs above channel buttons to vertically position the two traces on the screen whereboth can be viewed.

    4. Use the large knob in the horizontal section of the controls to change the horizontal sweep speed to200s (time/division). The sweep speed is shown in the box in the lower center portion of the screen.

    5. The small Position knob in the horizontal section changes the horizontal position of the displayedsignal. Use this knob to move one of the small T markers near the top of the screen over closer tothe left side of the screen. When an I2C signal is captured, it will be displayed with the starting pointof the signal at this position.

    EE 459Lx, Rev. 12/24/14 10

  • Figure 5: Tek channel settings Figure 6: Tek bus configuration

    Figure 7: Tek channel selection Figure 8: Tek trigger conditions

    6. Connect two scope probes to channels 1 and 2 of the scope and then connect the probe tips to the I2Cclock and data lines on your project board. Either one can be attached to either signal but make noteof which way they are connected.

    7. The Tek scopes can have two configurations stored for working with buses. To setup a bus for I2C,press one of the B1 or B2 buttons just above the connector of channel 1. In this example well useBus 1. Pressing the B1 button brings up the bus configuration menu along the bottom of the screen.

    8. The label for the left softkey shows the current setting for the bus. If it doesnt say Bus B1 I2C,press the softkey below the label to bring up a vertical menu for selecting the bus type (Fig. 6). Usingthe Multipurpose a knob in the top left part of the controls, select the I2C setting for bus B1.

    9. Press the second softkey from the left labeled Define Inputs. This brings up the screen shown inFig. 7. The current settings for which channel is clock and which is data is shown at the right side ofthe screen. Use the a and b Multipurpose knobs to change these to match how you connected theprobes to the hardware under test.

    10. Press the Thresholds softkey to see the voltages threshold settings for each channel. The thresholdsneed to be set to something around the middle of the zero to 5 volt range. Use the two Multipurpose

    EE 459Lx, Rev. 12/24/14 11

  • controls to set each of the thresholds to 2.4 or 2.6 Volts

    11. Use the Include R/W in address softkey to change that setting to Yes. This will make thescope display the device addresses as a eight-bit number with the least significant bit representing theread/write flag.

    12. Use the Bus Display softkey to change that setting to Hex. This causes the bytes of data on thebus to be displayed in hexadecimal rather than as binary numbers.

    13. Press the Menu button in the Trigger section. If the Type softkey label doesnt say Bus, pressit and use the Multipurpose a knob to scroll down to Bus.

    14. The Trigger On softkey is used to select the I2C condition that will cause the scope to acquire data.For most purposes a Start condition works best. If the softkey doesnt say Start, press the softkeyto bring up the Trigger On menu (Fig. 8) and use the Multipurpose a knob to set it for triggeringon a I2C Start condition.

    15. If the right softkey along the bottom doesnt say Mode Normal . . . , press it and then press thesoftkey along the right side to set the trigger mode for Normal.

    16. If needed press Menu Off a few times to remove the menus from the screen.

    At this point the scope is configured to trigger on a I2C Start condition. Press the Single button abovethe triggering controls to put the scope in a state where it will wait for the next Start condition on the I2Cbus and then capture the data. Do whatever is needed on your project board to get it to generate the I2Ctransfer, and once the data has been captured it will be displayed on the screen. The captured data can beexpanded or shrunk horizontally using the smaller inner knob of the Wave Inspector control in the topmiddle portion of the front panel. To scroll the data left or right, use the larger outer part of this control.

    EE 459Lx, Rev. 12/24/14 12