Step 6Using I2C Memory
To get ready for these experiments, we need to modify hardware slightly and build a couple of new circuits on the breadboard. Keep the Port Expander circuit since we'll use it to display some memory values. Remove the DIP switches from the PCA8574A and put blinkenlights on those pins. If you don't have enough blinkenlights, move the ones on P4 thru P7 over to P0 thru P3. (Values to be displayed are small enough.)
Now look at the schematic I2C Ram.pdf and hook up the PCF8570 on the breadboard. Have a look at the picture also. Be sure to tie pin 7 to Vcc. Run wires for SDA and SCL from the PCA8574A. No additional pull-up resistors are required.
If you're also interested in the EEPROM, build that circuit also using I2C EEPROM.pdf for the 24C16, but be warned that the example uses the ATmega168. This circuit is really simple. As discussed above, the address bits should be ignored. Just hook up power and ground. Don't connect SDA and SCL just yet since we haven't finished experimenting with the Ram.
We'll start our memory experiments with the ATtiny2313 connected to the PCA8574A Port Expander and to the PCF8570 Ram. The program will write some numbers to the Ram, then read them back and display them on the Port Expander.
Change your working directory to RAM under USI I2C. Use the make file to compile and download USI_I2C_RAM.c. Note that the I2C driver files are identical to those we used earlier. Hook up the power and you should see a single blink on LED 1 (PD6). Data will be written to the first 4 bytes of memory. Press the button and two bytes will be read back and displayed. You should see one LED light on the Port Expander (P0), a two second pause, then two LEDs light (P0 and P1). Another two second pause and the LEDs should turn off. Press the button again to start the sequence over. Debugging is similar to the method described above.
Let's take a look at the code. Open USI_I2C_RAM.c. It should look pretty similar to the previous code. The main differences are the details of reading and writing memory. Look at the way the message buffer is loaded before the call that actually does the write. The first byte is the slave address with the read/write bit set appropriately. But the next byte is the memory address at which to start writing data. Then comes the actual data bytes which will be sequentially loaded into memory starting at the address we specified. We specify the message size as 6. So we start writing at address 00 and write the values 01, 03, 02 and 06 into the memory locations 00 to 03.
To read the data back from the memory we must use the USI_TWI_Start_Random_Read function. The message buffer gets the slave address in the first byte and the starting address in the second byte. Then call the function with the message size set to the number of bytes to read plus 2. Note that the read/write bit doesn't matter since a read will be done regardless. The data returned will start in the second location in the message buffer. Once the data is read in, it's inverted for display on the Port Expander and written one byte at a time to it with a pause between the values. Finally, the Port Expander LEDs are turned off. The writes to the Port Expander are identical to what was done in the previous examples. For fun, you can uncomment the #define DEBUG statement as above and see lots of blinking LEDs.
Flushed with excitement after another successful experiment, let's move to the ATmega168 and an EEPROM. Change your working directory to EEPROM under TWI I2C. Use the make file to compile and download TWI_I2C_EEPROM.c. Note that the I2C driver files are identical to those we used earlier for the PCA8574A. To test the program, disconnect the ATtiny2313 and connect the ATmega168. Leave the I2C bus hooked to the Ram and power up. The results are different since we're now writing and reading more data. LED 1 on PD7 should blink at initialization. Press the button and data will be read back from the memory and displayed. The LEDs on the PCA8574 should blink the following sequence: P1, P0 & P2, (all off), P0 & P1, P1 & P2. Finally the Port LEDs should all go off. Press the button again to repeat this.
Oh, but wait, you say. Isn't this program for the EEPROM? Since we're accessing a memory device at the same I2C address, the same program works for both the Ram and the EEPROM. Power down and move SDA and SCL from the Ram to the EEPROM and run the program again. It should work exactly the same. Note that the EEPROM and the Ram can't be connected to the I2C bus at the same time since they share the same address. (The clever ones among you may consider changing the programmable address bits on the Ram, but that still won't work. The 24C16 uses the entire block of addresses that can be programmed for the Ram.)
OK, let's look at this last program. Open TWI_I2C_EEPROM.c. The first thing to notice is that I've indicated how to address the complete 24C16 EEPROM. It can be accessed in 256 byte chunks at 8 different I2C slave addresses. See how MEMORY_ADDR is defined as the starting address at 50 hexadecimal; that's why the Ram worked. If you want to access other blocks of the 24C16, then use the other addresses as I've indicated. Have a look at how I set up to write to the memory. First the slave address with the read/write bit set is put in the buffer, then the starting address of 00, then 16 bytes of data. The function TWI_Start_Read_Write is called to write the data (as before) with the message size set to 18. When the button is pressed, we use TWI_Start_Random_Read and TWI_Read_Data_From_Buffer to read the data back. Every third byte is displayed on the Port Expander LEDs. Finally, the LEDs are turned off to await the next button press.
You might wonder why I chose to write 16 bytes. If you read the data sheet carefully, you'll see that the 24C16 does a write cycle whenever it receives 16 bytes even if more bytes are being sent. So that seemed like a nice number to use. If you choose to increase this, you'll have to change the size of MESSAGEBUF_SIZE. You'll also have to change the value TWI_BUFFER_SIZE in TWI_Master.h. This is because the driver copies the data from the message buffer for use by the interrupt service routine.
Congratulations! You're now ready to use the I2C bus in your own projects!
| « Previous Step | Download PDFView All Steps | Next Step » |
![]() |
Add Comment
|











































