![](templates/subSilver/images/CCSLogo.jpg) |
![CCS C Software and Maintenance Offers](templates/subSilver/images/forumAd6.jpg) |
View previous topic :: View next topic |
Author |
Message |
nina
Joined: 20 Apr 2007 Posts: 111
|
register x address |
Posted: Thu Mar 12, 2009 1:57 pm |
|
|
I have studied ds1307 and also i2c. All documents and articles about it talk about registers and address.
Someone could explain what are registers and address? What they work for?
I have realized some programs with i2c like below:
Code: | i2c_start();
i2c_write(0xd0); ????? why and for what???
i2c_wirte(address); ?????
i2c_write(data); ????? why i have to write data instead of read data????
i2c_stop() ????
i2c_start(); ???? why start again |
tks |
|
![](templates/subSilver/images/spacer.gif) |
rnielsen
Joined: 23 Sep 2003 Posts: 852 Location: Utah
|
|
Posted: Thu Mar 12, 2009 3:23 pm |
|
|
In I2C there are certain sequences that need to happen in order for the devices to communicate properly. Each device, such as a eeprom, requires certain commands in order to be written to or to be read from. I'll try to explain your example a little.
i2c_start();
This is the command that the Master, or PIC, uses to tell everybody on the I2C bus that it is taking control of the bus and that they need to pay attention.
i2c_write(0xd0);
After an i2c_start() the Master sends out the address of the device it wants to talk to. In this example the device is at 0xd0. All other devices on the bus will then ignore further commands that are sent on the bus.
i2c_write(address);
This is most likely an eeprom being talked to. This command, issued after the device's address, tells the eeprom what address, inside the eeprom, it wants to access.
i2c_write(data);
This is the actual data that is going to be written to the 'address' inside of the eeprom.
i2c_stop();
The Master issues this command saying that it's either finished talking and realeasing the bus from it's command OR, depending on the device, it's going to take control again to issue further commands to the device, which is does in many eeproms.
i2c_start();
This stop-start sequence can be a requirement for devices, at least with most eeproms that I've used, in order to write data to them.
The sequence that you've entered doesn't appear to be exactly in the correct order but hopefully this explaination helps a bit. Looking at the spec. sheet you will see the exact sequence that needs to be used in order to write data to or read data from the device.
Clear as mud?
Ronald |
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah Guest
|
|
Posted: Thu Mar 12, 2009 4:04 pm |
|
|
Start with the DS1307 data sheet.
On i2c, each device on the bus, has to have an address. Addresses of 0 to 127, are available, with then certain ones being 'reserved' for special stuff (ignore the bottom 16, and the top one). Manufacturers make their chips either with fixed addresses, or in some cases with addresses that can be changed through a number of values, by altering external pins, or sometimes with a range of values available as 'mask' options from the manufacturer.
For the 1307, you will find in the paragraph at the top of page 7, the line:
"The address byte is the first byte received after the start condition is generated by the master. The address byte contains the 7 bit DS1307 address, which is 1101000, followed by the *direction bit (R/W ) which, for a write, is a 0."
On I2C, each initial transaction carries a direction 'bit'. 0 for a write, and 1 for a read.
So the 1307, requires the first 'address' byte, to be:
1101 0000 for a write
1101 0001 for a read
In Hex, these are 0xD0, and 0xD1
Now, the next part of the I2C transaction.
Basically, with I2C, the byte(s) (more than one for a device that has more than 256 internal 'registers'), following a 'write' address, is the 'register number' to be talked to.
The sequence is:
Send a start.
Send the device address, for write (bottom bit = 0).
Send the register number.
Now, the chip is all set to _write_to specific location.
All you do at this point to _write_, is start sending the data.
However to _read_, you then use what is called a 'repeated start'
Send another start.
Send the device address, with the bottom bit set to _read_.
Start reading the data.
After either the read or write, you send a 'stop' to say you have finished.
Key is this idea, that you can select the 'register number', with a 'write' command, and then turn the bus around, by using the repeated start.
Figure 2, on the data sheet, gives the 'register numbers' used by the chip. 8 bytes for the clock, then 56bytes useable for storage.
The 'minutes' for example, are location 1. So the sequence to read the minutes, becomes:
Code: |
i2c_start();
i2c_write(0xd0); //Chip address from the data sheet - write selected
i2c_write(1); //Select register 1
i2c_start(); //Send a restart
i2c_write(0xd1); Chip address - read selected
mins=i2c_read(); //read the minutes
i2c-stop(); //finish the transaction
|
Now, before you can read the minutes, the clock itself has to be enabled. This is done by clearing the top bit of register number 0. So the code to 'start' the chip, becomes:
Code: |
i2c_start();
i2c_write(0xd0); //Chip address from the data sheet - write selected
i2c_write(0); //Select register 0
i2c_write(0); //clear the seconds, to start the clock
i2c-stop(); //finish the transaction
|
Now, in general, when you read or write to a register, the register number automatically advances to the next register. If you stop a transaction, and start again, the register number selected is retained. So if you combine the two jobs into one, and send a '0' to register 0, then stop, and start selecting 'read', you will get the contents of register 1. This appears to be what your example is doing.
Best Wishes |
|
![](templates/subSilver/images/spacer.gif) |
nina
Joined: 20 Apr 2007 Posts: 111
|
i2c |
Posted: Thu Mar 12, 2009 7:39 pm |
|
|
Ttelmah/nielsen...
Thank you very much for all information...it is like that information I have looking for. Great. You explained in a simple way everything I wanted know. I'll read one more time the datasheet ds1307 and pay attention to all the information you gave me.
Just one more question..
Instead of using:
Code: |
i2c_start();
i2c_write(0xd0); //Chip address from the data sheet - write selected
i2c_write(1); //Select register 1
i2c_start(); //Send a restart
i2c_write(0xd1); Chip address - read selected
mins=i2c_read(); //read the minutes
i2c-stop(); //finish the transaction
|
Could I use the code below???
Code: | i2c_start();
i2c_write(0xd1); Chip address - read selected
i2c_write(1); //Select register 1
mins=i2c_read(); //read the minutes
i2c-stop(); //finish the transaction |
Thank you very much again.
nina |
|
![](templates/subSilver/images/spacer.gif) |
rnielsen
Joined: 23 Sep 2003 Posts: 852 Location: Utah
|
|
Posted: Thu Mar 12, 2009 8:59 pm |
|
|
You need to do it just as Ttelmah describes with one exception. The statement:
needs to have the master send a NACK to notify the DS1307 that the master is finished reading data. So, the command needs to be:
Code: | mins=i2c_read(0);// insert a zero here to send a NACK |
You can't make any short cuts. You have to do it exactly as the data sheet describes.
Ronald |
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah Guest
|
|
Posted: Fri Mar 13, 2009 3:23 am |
|
|
Aargh.
Typing from memory, rather than following the data sheet. Slap slap... naughty boy!....
Rnielsen makes the point, which applies all the way here, data sheet, line by line.
As you see from my post, the data sheet does contain the address details, and the numbers needed to select the registers (and when ACK/NACK is needed...). It is 'just' a matter of following this to the letter. The problem is that the actual 'layout', of what is involved, is not terribly 'obvious', unless you are experienced in I2C.
Best Wishes |
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah Guest
|
|
Posted: Fri Mar 13, 2009 3:40 am |
|
|
Ongoing, on the question about shortening the sequence, _no_.
The direction byte controls the whole transaction, after the initial address byte. You need to _write_the address, so the 'write' direction needs to be selected. Only after you have written this, can you turn the bus round, and read the bytes at the address. This is why you can't select 'read', and then write the address needed in one go...
Best Wishes |
|
![](templates/subSilver/images/spacer.gif) |
nina
Joined: 20 Apr 2007 Posts: 111
|
ds1307 |
Posted: Fri Mar 13, 2009 3:53 am |
|
|
telmah
I did not find why I have write (i2c_write(0xd0); //Chip address from the data sheet - write selected)
instead of (i2c_write(0xd1); Chip address - read selected )instead of read
could you show me where datasheet say it, please?
The address byte is the first byte received after the start condition is generated by the master. The address byte contains the 7-bit DS1307 address, which is 1101000, followed by the *direction bit (R/W ) which, for a read, is a 1. After receiving and decoding the address byte the
device inputs an acknowledge on the SDA line. The DS1307 then begins to transmit data starting with the register address pointed to by the register pointer. If the register pointer is not written to before the initiation of a read mode the first address that is read is the last one stored in the register pointer. The DS1307 must receive a “not acknowledge” to end a read.
many tks again |
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah Guest
|
|
Posted: Fri Mar 13, 2009 8:47 am |
|
|
In the DS1307 sheet, look at the example 'slave receiver mode' transaction (Fig 6). Note that the register address is transferred. Then look at the next paragraph 'slave transmitter mode'. Note that no address is sent. Read the paragraph itself. "After receiving and decoding the address byte the device inputs an acknowledge on the SDA line. The DS1307 then begins to transmit data starting with the register address pointed to by the register pointer. If the register pointer is not written to before the initiation of a read mode the first address that is read is the last one stored in the register pointer.".
Note the words _before the initiation of a read mode_.
The point is that to _write_ the register number pointer, you have to have 'write mode' selected. If you want to read from a particular register, you have to select write mode, and write the register number, then switch to read mode, to read from it. The bus is 'half duplex' (only talks in one direction at a time), so you have to turn it round to read, after writing an address. If you have selected 'read' (0xd1), you can't then write the address (the bus is setup to read from the device).
In the I2C specs, this is covered in the 'combined format' spec.
Best Wishes |
|
![](templates/subSilver/images/spacer.gif) |
rnielsen
Joined: 23 Sep 2003 Posts: 852 Location: Utah
|
|
Posted: Fri Mar 13, 2009 10:50 am |
|
|
In I2C the master needs to send a start() to tell everybody that it's going to start talking. The next thing is to send the address of the device that will be talked to. Now, this address is an 8-bit address with the last bit determining if a Write or a Read is going to happen.
In the sequence that is needed, the address 0xD0 is first sent out on the bus telling the device, at 0xD0, that it needs to pay attention and that data is going to be written to it. 0xD0 is 11010000 in binary. Notice the last bit is a zero(0). This is the 'direction' bit. It tells the device which direction data is going to go. When 0xD1 is sent (11010001) this tells the device that data is going to be read from it.
So, the sequence that the DS1307 requires is:
Code: | i2c_start();// OK, the master is going to talk so pay attention!
i2c_write(0xD0);// hey, whoever is at address 0xD0, i'm talking to you
i2c_write(1);// okay, mr. device, I want to access whatever is inside you at address 1
i2c_start();// i'm sending another restart so i can change the direction of the bus
i2c_write(0xD1)// okay mr. device, i'm still talking to you and i want to READ data from you now
mins = i2c_read(0);// i'm reading whatever data is at internal address 1 from the device PLUS sending a NOACK
i2c_stop();// the master is now finished talking, you can all go back to sleep |
Hopefully that might help clear things up a little. According to the spec. sheet, this is the sequence _required_ to read something from the device.
Now, if you wanted to read the Hours you would have sent a 2 instead of a 1 on the second i2c_write(). If you wanted the seconds you would have sent a 0.
Ronald |
|
![](templates/subSilver/images/spacer.gif) |
nina
Joined: 20 Apr 2007 Posts: 111
|
ds1307 |
Posted: Fri Mar 13, 2009 12:55 pm |
|
|
nielsen / Ttelmah
Thank you very much for all information. Now it very clear what happen with ds1307. That's what I needed to start understand datasheets.
thanks again
nina |
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah Guest
|
|
Posted: Fri Mar 13, 2009 3:56 pm |
|
|
and of course, if you want to read, the minutes, then the hours, use:
Code: |
i2c_start();// OK, the master is going to talk so pay attention!
i2c_write(0xD0);// hey, whoever is at address 0xD0, i'm talking to you
i2c_write(1);// okay, mr. device, I want to access whatever is inside you at address 1
i2c_start();// i'm sending another restart so i can change the direction of the bus
i2c_write(0xD1)// okay mr. device, i'm still talking to you and i want to READ data from you now
mins = i2c_read(); //Don't NACK
hours = i2c_read(0); //Now send the NACK
i2c_stop();// the master is now finished talking, you can all go back to sleep
|
Having started a read sequence, you can potentially read _all_ the registers in sequence, till you NACK/stop.
Best Wishes |
|
![](templates/subSilver/images/spacer.gif) |
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|