I2C and the Analog-to-Digital Converter What you need to know for the Self-test project Start by recalling the brief introduction given in the project lecture slides. There was a diagram of the entire computer and I/O architecture: In this diagram, there is an I2C Controller block. You can think of it as a link between the 16-bit I/O bus of the Simple Computer (used to “talk” to a variety of I/O devices, as we know), and ANOTHER I/O bus, the I2C bus. The I2C bus is a serial bus: essentially a 1-bit data bus instead of the 16-bit I/O bus. The I2C Controller does all the hard work of accepting commands from SCOMP on the 16-bit I/O bus and handling the sequence of operations needed to send or receive data from any of several possible devices. This is shown in the picture below. SCOMP DATA[0..15] Audio Codec (used for tone generation) I2C Controller Enable signals, Clocking, Reset, IO_CYCLE, IO_WRITE Serial Clock, Serial Data TV Decoder (not used, currently) Note the “normal” IO bus that you have seen in Lab 8 on the left side of the figure above. The I2C Controller is just another IO device, addressed at a specific I/O location, just as the switches are at address 0x00, the LEDs are at address 0x01, and so on. But when the I2C Controller is given a command, it is a request that includes a target address ON THE I2C BUS, as well as a desired function to perform. In the example above, it might be a request to send a command like “volume adjust” to the Audio Codec chip, which has a different address than the TV Decoder chip. The same SCOMP I/O address (i.e. the I/O address of the I2C controller) would be used to address the TV Decoder, but a different address/function command would be sent. Now, let’s clarify an oversimplification in the very first figure (the one on the previous page). It shows a single I2C Controller in the SCOMP architecture. Actually, you were given TWO I2C Controllers in the files that you used in the first week of the project. An accurate depiction is shown below. Enable signals, Clocking, Reset, IO_CYCLE, IO_WRITE SCOMP DATA[0..15] I2C Controller Reset, Clocking ONESHOT_I2C (A simple I2C controller) Serial Clock, Serial Data A/D Converter I2C bus between DE2 and Robot Audio Codec (used for tone generation) Serial Clock, Serial Data I2C bus on DE2 TV Decoder (not used, currently) There are actually two I2C busses. One is entirely on the DE2 board, and the other one goes through the DE2 daughterboard down to the inside of the robot, where the A/D converter is located. The I2C Controller for the Robot I2C bus is addressable by SCOMP. The I2C controller for the DE2 I2C bus, called ONESHOT_I2C, simply does an automatic configuration of the Audio Codec so that you can later use it to generate tones. (Specifically, it enables the analog audio output, sets the volume, and does a few other things that you would almost certainly not want to do any differently yourself.) So, you cannot “talk” to the ONESHOT_I2C from SCOMP, and that is just less work for you, anyway. But you CAN talk to the other I2C Controller, and will need to do so to read the robot battery voltage. The I2C Controller, appropriately called I2C_CONTROLLER, has three internal registers at three different addresses in the SCOMP I/O space. You can figure out those addresses (or change them, for that matter), by looking at the IO_DECODER device that was part of the Week 1 exercises. But, here’s the answer. The important addresses are: I2C_CMD (used to tell the I2C Controller what to do): address 0x90 I2C_DATA (the data to send the target device or receive from the target device): address 0x91 I2C_BUSY (an indication that the activity on the I2C bus is in progress): address 0x92 I2C allows devices to send and receive bytes of data, but every single different device in the world with an I2C interface has its own way of interpreting that data. This is deliberately a generic controller that you have been given. What is always true is that you first send a word to I2C_CMD that describes what device you want to talk to, whether you are reading from it or writing to it (or both), and how many bytes you are sending or receiving. The specifics are given in the comments of the code provided: ----- I2C_CONTROLLER.vhd An SCOMP peripheral to interface with I2C devices. Capable of sending up to two bytes and reading up to two bytes at a time. Created by Kevin Johnson. Last modified 2013-03-07 -- SCOMP interface: -- Three IO addresses are used: I2C_CMD, I2C_DATA, and I2C_BUSY. --I2C_CMD contains the bits [00WW 00RR AAAAAAAA] where: -WW is the number of bytes to write (0, 1, or 2) -RR is the number of bytes to read (0, 1, or 2) -AAAAAAAA is the 8-bit I2C address of the device --I2C_DATA is a read/write register. Write to it the data you wish to send, -and read from it any data received. Writing to this register starts the -I2C transaction, so: -I2C_CMD must be set BEFORE writing to I2C_DATA. -Even if no data is to be sent, something must still be written to I2C_DATA --I2C_BUSY is a read-only register that allows for polling the progess -of the I2C transaction. A non-zero value indicates that this device -is busy and will not accept additional commands or data. -Zero indicates that this device is ready to accept commands or data. -- Example of typical usage: -- Write 0x2134 to I2C_CMD ; command to write two bytes then read one byte, I2C address 0x34 -- Write 0xAA55 to I2C_DATA ; send the bytes 0xAA and 0x55 over I2C, then read one byte from I2C -- Read I2C_BUSY until it returns 0 -- Read I2C_DATA to retrieve the byte that was read from the I2C device. Since there is only a single I2C device (the analog-to-digital converter, or ADC) actually connected to this controller, all that remains is for you to understand what it expects in terms of an address and data. It is actually a simple device. Its datasheet will be posted on the project page, but you may find it confusing. The summary of how to access the ADC is as follows: The address of the ADC on the I2C bus is 0x90, and you use this address both to write to it and to read from it. When it first powers up, you need to write a specific byte to it once to set it up. The datasheet refers to this as the “Control Byte,” and for this application it must be 0x00. (Specifically, this disables the unused analog output, configures the analog inputs as “single-ended,” and selects analog input channel 0, which is the one connected to the battery.) Once it has been configured, you only need to read a single byte from it whenever you want the ADC value, but note the comments in I2C_CONTROLLER.VHD that say that you always write to I2C_DATA to begin ANY operation (including reads). The first value returned by the ADC (after power-up and configuration) is always 0x80, and is not valid data (other than possibly as a test that you are correctly accessing the ADC). All subsequent values (numbers between 0 and 255) are proportional to a voltage on a scale of 0 to 5 V where 256=5V. For example, a value of 128 is: 128/256*5V, or 2.5V. The actual battery voltage is larger than this by a factor of (118+487)/118. See the lecture slide called “How do I test the battery” for an explanation. It is a complete coincidence (and perhaps unfortunately confusing) that one of the three SCOMP I/O addresses of the I2C controller is 0x90 and the address of the ADC on the I2C bus is also 0x90. Don’t lose sight of the fact that the SCOMP I/O address is something decoded in IO_DECODER to produce a “chip select” for I2C_CONTROLLER, while the ADC decodes its address internally when it sees a message on the serial I2C bus. You could change the address of the I2C_CONTROLLER device, but the address if the ADC chip itself is built into the chip.