EEVblog Electronics Community Forum
Electronics => Microcontrollers => Topic started by: eneuro on July 01, 2015, 11:24:51 am
-
After using software master I2C on ATTiny85 succesfully before, now trying use USI I2C and this what I've noticed in this sample I2C master library described there:
ATTiny USI I2C Introduction - A powerful, fast, and convenient communication interface for your ATTiny projects! (http://www.instructables.com/id/ATTiny-USI-I2C-The-detailed-in-depth-and-infor/?ALLSTEPS)
it looks there is no timeout support etc :/
Additionally, I've no idea .. how I2C frequency is defined, since it looks like they use something like this for timing in usi_i2c_master.c:
#define USICR_CLOCK_STROBE_MASK 0b00101011
#define USI_CLOCK_STROBE() { USICR = USICR_CLOCK_STROBE_MASK; }
I've no external clock in many ATTiny projects since I do not need fast I2C and what I've noticed is
USI USICR register mask defined in this file
I've downloaded this example USI I2C ATTiny library from this linked mentioned in above instructables:
https://github.com/CalcProgrammer1/Stepper-Motor-Controller/tree/master/UnipolarStepperDriver (https://github.com/CalcProgrammer1/Stepper-Motor-Controller/tree/master/UnipolarStepperDriver)
Added definitions for ATTiny85 port and SCL/SDA pin definitions like this:
#if defined (__AVR_ATtiny25__) | \
defined (__AVR_ATtiny45__) | \
defined (__AVR_ATtiny85__)
#define DDR_USI DDRB
#define PORT_USI PORTB
#define PIN_USI PINB
#define PORT_USI_SDA PB0
#define PORT_USI_SCL PB2
#define PIN_USI_SDA PINB0
#define PIN_USI_SCL PINB2
#endif
It compiles now, but while trying to talk to RTC (PCF8563) to set its output clock out to 1 Hz in my hand watch project, for the moment probably waits forever in one of those: USI_I2C_WAIT_HIGH() / USI_I2C_WAIT_LOW() routines since for the moment I didn't have timeout support-just tried to use this library and see how it works on ATTiny85 :palm:
Maybe external crystal clock was used in this project, so USICR_CLOCK_STROBE_MASK bits 00101011
In ATTiny85 datsheet I found something like this:
The clock can be selected from three different sources: The USCK pin, Timer/Counter0 Compare Match or from software.
...
The clock is generated by the Master device software by toggling the USCK pin via the PORTB register or by writing a one to bit USITC bit in USICR.
ATTiny85 USICR register below:
(http://s14.postimg.org/4zzlakcip/USICR_USI_Control_register.png)
Such bits are set in clock strobe routines in USICR: 00101011 -there is no F_CPU or something like I2C frequency settings in this linked USI I2C library...
Last page of ATTiny85 USI documentation shows how clock is selected and it looks like bits USICR[3:1] (101) in this I2C master library selects clock source as "External, positive edge" with "Software clock strobe USITC" .
(http://s17.postimg.org/dys9x8haj/USICR_USICS_and_USICLK_setting.jpg) (http://postimg.org/image/dys9x8haj/)
Does it mean this I2C master library uses external clock connected to SCL pin? Doesn't setting USITC toggle this SDA line?
According to this page they only mention that to be able see SCL changes DDR output pin must be set (1) to allow "easy" clock generation when implementing master devices :-//
What exactly this "External, positive edge" clock source means? Which clock?-I haven't got external crystal clock.
I could create timer and drive this SCL pin, since I do not want any external clocks in low speed I2C setups.
I'm lost for the moment with USI I2C setup, but have ready Attiny85 programmed so will try hard today talk to this RTC as I2C master >:D
Support for I2C master arrbitration could be additional advantage and challenge, since in a few projects I might want use this more advanced I2C master mode.
Could someone give some hints (maybe I'm missing something) USI I2C master ATTiny85 library (without any external crystal clocks), please?
Reading again this ATTiny USI datasheet (pages from 108 in linked below PDF):
http://www.atmel.com/Images/Atmel-2586-AVR-8-bit-Microcontroller-ATtiny25-ATtiny45-ATtiny85_Datasheet.pdf (http://www.atmel.com/Images/Atmel-2586-AVR-8-bit-Microcontroller-ATtiny25-ATtiny45-ATtiny85_Datasheet.pdf)
NOTE: I've F_CPU set to 8MHz, but no fuses set for this-I switch to 8MHz at the beginning in software, than wait 1s and try to talk via I2C to RTC using routines described above... so my ATTiny85 runs at 8MHz now , but it will be much lower frequency in hand watch project to save battery life .
#define F_CPU 8000000UL
-
OK. I've found where SCL timings [us] are defined in usi_i2c_master.* files:
//I2C Bus Specification v2.1 FAST mode timing limits
#ifdef I2C_FAST_MODE
#define I2C_TLOW 1.3
#define I2C_THIGH 0.6
//I2C Bus Specification v2.1 STANDARD mode timing limits
#else
#define I2C_TLOW 4.7
#define I2C_THIGH 4.0
#endif
Than those [us] delays are used in code to wait for bus wheen needed to slowdown things:
#define USI_I2C_WAIT_HIGH() { _delay_us(I2C_THIGH); }
#define USI_I2C_WAIT_LOW() { _delay_us(I2C_TLOW); }
Update: Yep they takem those delays from I2C specification ver 2.1 (2000) (http://i2c2p.twibright.com/spec/i2c.pdf)
(http://s24.postimg.org/ppah20aox/i2c_spec_2_1_bus_fast_vs_standard.jpg) (http://postimg.org/image/ppah20aox/)
Adding 10kHz slow (~10 times slower than I2C Standard maximum 100kHz) mode could be good idea on 8MHz MPU and (slower) since we are still below limits of _delay_us(double) used in this I2C master library, which is:
The maximal possible delay is 768 us / F_CPU in MHz
and even slow optoisolated I2C buses should work since cut off frequency of very slow cheap PC817/EL817 is 80kHz, etc 8)
So, probbaly will add much slower mode . eg. I2C_SLOW_MODE or I2C_TEST_MODE to modify those timings to slow things even more for I2C protocol testing purposes with not perfectly choosen I2C pullup resistors ;)
This library comes with I2C standard speed ~100kHz max and those SCL timings gives us such frequency, which might be too fast in some I2C setups...
-
Mystery of I2C master MPU hang up resolved -I've forgot solder pull up resistors on test prototype, so I2C lines had no chance to go high :-DD
Anyway, it was intersting experiment and watchdog or I2C timeout support needed, to avoid this.
Now it is time implement I2C multi-master (http://www.i2c-bus.org/multimaster/) arbitration logic into USI I2C library ;)
Monster Attiny85 MPU
(http://s4.postimg.org/rfjoicw71/ATTINY85_SO_8_forum.jpg)
and RTC
(http://s28.postimg.org/t3trousel/PCF8563_SO_8_forum.jpg)
ready to run forever powered by... sun/artificial light in hand watch clock project :popcorn:
No bloody AC mains chargers, no wires... no buttons-wireless power transfer and synchronization with pc/tablet/smartphone/cell phone :)
-
afaik this is working code
Master is in the main thread in the below url
slave is linked to in this post
http://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&p=332173#332173 (http://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&p=332173#332173)
This is also based on Don's code
https://code.google.com/p/codalyze/wiki/I2COnATtiny45 (https://code.google.com/p/codalyze/wiki/I2COnATtiny45)
/Bingo
-
afaik this is working code
Yep, but I do not like error handling in this USI I2C master module and this software I2C (single) master by Peter Fleury http://homepage.hispeed.ch/peterfleury/ (http://homepage.hispeed.ch/peterfleury/) is much more compact and provides pure TWI implementation as well as software version written in assembler.
I've removed in assembler module i2c_delay_T2 and implemented it using _delay_us(double) in custom I2C header:
void i2c_delay_T2();
void i2c_delay_T2() {
_delay_us(I2C_DELAY_T2);
}
which allows me easy define I2C bus speed, while added to my I2C header files definitions like this:
// Delays in [us]/2
#ifdef I2C_STANDARD_MODE
// 100kHz
#define I2C_DELAY_T2 (5.0)
#else
#ifdef I2C_SLOW_MODE
// 10kHz
#define I2C_DELAY_T2 (5.0*10)
#else
#ifdef I2C_TEST_MODE
// 1kHz
#define I2C_DELAY_T2 (5.0*100)
#else
// I2C_DEBUG_MODE
// 100Hz
#define I2C_DELAY_T2 (5.0*1000)
#endif // I2C_TEST_MODE
#endif // I2C_SLOW_MODE
#endif // I2C_STANDARD_MODE
So, default I2C speed in this software implementation of I2C (single) master library is as low as 100Hz, set for debug mode ;)
Hopefully, I've found this Atmel AVR310: Using the USI Module as a I2C Master (http://www.atmel.com/images/atmel-2561-using-the-usi-module-as-a-i2c-master_ap-note_avr310.pdf) so I should have now better understanding what happends on hardware USI registers level in this USI I2C (single) master implementation from first post in this thread, having in mind those typical I2C timing diagrams:
(http://s30.postimg.org/z4z9fa3pt/i2c_timing.png)
(http://s3.postimg.org/ont8rw5hb/i2c_timing_diagrams.jpg) (http://postimg.org/image/ont8rw5hb/)
So, need to review this code again and make another tests, but probably software I2C master might better option, however USI I2C might be good for slave, so this way I will have I2C slave implemented in USI hardware and on other two MPU pins software I2C, to be able gather information from another I2C internal MPU network and provide this information as I2C slave device with assigned slave address to external I2C masters 8)
-
I've found this Atmel AVR310: Using the USI Module as a I2C Master (http://www.atmel.com/images/atmel-2561-using-the-usi-module-as-a-i2c-master_ap-note_avr310.pdf)
This was what I was looking for and now USI TWI/I2C (single) master works as expected with I2C error codes like those below- I was able to detect easy that there were no RTC device on bus or missed his address, since I've got error code 0x1
USI_TWI_NO_ACK_ON_ADDRESS 8)
#define USI_TWI_NO_ERROR 0x00// NO error
#define USI_TWI_NO_DATA 0x08 // Transmission buffer is empty
#define USI_TWI_DATA_OUT_OF_BOUND 0x09 // Transmission buffer is outside SRAM space
#define USI_TWI_UE_START_CON 0x07 // Unexpected Start Condition
#define USI_TWI_UE_STOP_CON 0x06 // Unexpected Stop Condition
#define USI_TWI_UE_DATA_COL 0x05 // Unexpected Data Collision (arbitration)
#define USI_TWI_NO_ACK_ON_DATA 0x02 // The slave did not acknowledge all data
#define USI_TWI_NO_ACK_ON_ADDRESS 0x01 // The slave did not acknowledge the address
#define USI_TWI_MISSING_START_CON 0x03 // Generated Start Condition not detected on bus
#define USI_TWI_MISSING_STOP_CON 0x04 // Generated Stop Condition not detected on bus
#define USI_TWI_BAD_MEM_READ 0x0A // Error during external memory read
I2C device detection and error handling is now as simply as it is ;)
// Try to set 1 Hz RTC clock out
if( rtc_set_clock_out_1hz() ) {
isclock= 1;
} else {
isclock= 0;
}
// Output result as morse byte code
err= i2c_master_error_code();
if(err ) {
morse_byte(PWMPIN, err );
// #define USI_TWI_NO_ACK_ON_ADDRESS 0x01
// The slave did not acknowledge the address
addr= i2c_master_error_addr();
morse_byte(PWMPIN, addr );
morse_delay();
morse_delay();
isclock= 0;
}
No scope needed to find typical I2C errors, since in the case of bus error in debug mode error code with I2C 7bit device address is displayed on one MPU pin using... Morse byte codes (blinking led at ~1Hz bit legths to be able read those bytes bits by humans) >:D
Master arbitration is another thing I'd like to support optionally in this USI I2C master library.
For the moment some hints comes from oryginal NXP I2C manuals, but implementing this might be a little bit challenge, since master clock synchronization need to be performed, etc.
(http://s10.postimg.org/t9k0zydg5/i2_C_arbitration_procedure.jpg) (http://postimg.org/image/t9k0zydg5/)