Hello again... I hope this time I can keep focus in my goal and get some good help!
My main goal is to understand Peter Fleury's code for the TWI.
I've been reading a little bit about the registers used in Peter Fleury's code! I'll call Peter Fleury's code "PF code" from now on to make things easier!
First of all, I'll state what I'm using, regarding hardware and software, my semi-goals and after that I'll ask my questions!
I'm using AtMega328P-PU, 28 pins as my uC.
I'm using Microchip 24LC08B and/or 24LC10B external memory ICs to save and read data into and from it!
I have 4k7 ohm pull-up resistors at SDA and SDL pins!
I'm using 16MHz crystal and 22pF capacitors at AtMega328P-PU pins 9 and 10.
I'm using a pressure switch to make the reset to the AtMega328P-PU uC when uploading firmware to it!
I'm using 1uF and 10uF decoupling capacitors between + and - lines (don't hane any other caps atm)!
All the remaining AtMega328P-PU pins are floating!
I'm using an USB-to-Serial converter to make the connection between the AtMega328P-PU and the laptop.
Hope I have not forgot anything!
About the software:
I'm a Debian Jessie 64bit user!
I'm using Atmel AVR 8-bit Toolchain 3.5.4 - Linux 64-bit which includes avr-gcc-4.8.1.
I'm using avrdude-6.3.
I'm using this AtMega328P-PU datasheet
I'm using this Microchip 24LC08B datasheet
I have downloaded PF libraries and example codes.
My focus will be each function in his code to ask some questions about some of the lines of code!
Hope I haven't forgot anything!
I'll start from the beginning of PF code:
From the AtMega328P-PU datasheet I can read the sequence of commands to initiate the TWI interface, page 268.
The first step is to issue a Start Condition. This is accomplished by:
TWCR0 = (1<<TWINT) | (1<<TWSTA)|(1<<TWEN);
From PF code:
Function: unsigned char i2c_start(unsigned char address)
TWCR = (1<<TWINT) | (1<<TWSTA) | (1<<TWEN);
Why the datasheet uses TWCR0 and PF code uses TWCR... One is addressing a single bit of the register the other uses the whole byte of the register! Is there any specific reason?
The same question applies to the other lines of code where TWCR is used rather than TWCR0.
Now, I wanted to understand the following step... It is described in the datasheet of AtMega328P-PU as:
3. The application software should now examine the value of TWSRn, to make sure that the START condition was successfully transmitted. If TWSRn indicates otherwise, the application software might take some special action, like calling an error routine. Assuming that the status code is as expected, the application must load SLA+W into TWDR. Remember that TWDRn is used both for address and data. After TWDRn has been loaded with the desired SLA+W, a specific value must be written to TWCRn, instructing the TWI n hardware to transmit the SLA+W present in TWDRn. Which value to write is described later on. However, it is important that the TWINT bit is set in the value written. Writing a one to TWINT clears the flag. The TWI will not start any operation as long as the TWINT bit in TWCRn is set. Immediately after the application has cleared TWINT, the TWI will initiate transmission of the address packet.
The suggested code to do this is described in the datasheet as:
if ((TWSR0 & 0xF8) != START) ERROR(); TWDR0 = SLA_W; TWCR0 = (1<<TWINT) | (1<<TWEN);
PF's code is the following:
// check value of TWI Status Register. Mask prescaler bits. twst = TW_STATUS & 0xF8; if ( (twst != TW_START) && (twst != TW_REP_START)) return 1; // send device address TWDR = address; TWCR = (1<<TWINT) | (1<<TWEN);
Why and how is the datasheet "START" compared to the PF's code "TW_REP_START"??? Isn't this "TW_REP_START" a repeated start? And how is the TWINT flag being checked?