;**** A P P L I C A T I O N   N O T E   A V R 3 0 0 ************************;*;* Title		: I2C (Single) Master Implementation;* Version		: 1.0 (BETA);* Last updated		: 97.08.27;* Target		: AT90Sxxxx (any AVR device);*;* Support email	: avr@atmel.com;*;* DESCRIPTION;* 	Basic routines for communicating with I2C slave devices. This;*	"single" master implementation is limited to one bus master on the;*	I2C bus. Most applications do not need the multimaster ability;*	the I2C bus provides. A single master implementation uses, by far,;*	less resources and is less XTAL frequency dependent.;*;*	Some features :;*	* All interrupts are free, and can be used for other activities.;*	* Supports normal and fast mode.;*	* Supports both 7-bit and 10-bit addressing.;*	* Supports the entire AVR microcontroller family.;*;*	Main I2C functions :;*	'i2c_start' -		Issues a start condition and sends address;*				and transfer direction.;*	'i2c_rep_start' -	Issues a repeated start condition and sends;*				address and transfer direction.;*	'i2c_do_transfer' -	Sends or receives data depending on;*				direction given in address/dir byte.;*	'i2c_stop' -		Terminates the data transfer by issue a;*				stop condition.;*;* USAGE;*	Transfer formats is described in the AVR300 documentation.;*	(An example is shown in the 'main' code).	;*;* NOTES;*	The I2C routines can be called either from non-interrupt or;*	interrupt routines, not both.;*;* STATISTICS;*	Code Size	: 81 words (maximum);*	Register Usage	: 4 High, 0 Low;*	Interrupt Usage	: None;*	Other Usage	: Uses two I/O pins on port D;*	XTAL Range	: N/A;*;***************************************************************************;**** Includes ****.include "2313def.inc"			; change if an other device is used;**** Global I2C Constants ****.equ	SCLP	= 1			; SCL Pin number (port D).equ	SDAP	= 0			; SDA Pin number (port D).equ	b_dir	= 0			; transfer direction bit in i2cadr.equ	i2crd	= 1.equ	i2cwr	= 0;**** Global Register Variables ****.def	i2cdelay= r16			; Delay loop variable.def	i2cdata	= r17			; I2C data transfer register.def	i2cadr	= r18			; I2C address and direction register.def	i2cstat	= r19			; I2C bus status register;**** Interrupt Vectors ****	rjmp	RESET			; Reset handle;	( rjmp	EXT_INT0 )		; ( IRQ0 handle );	( rjmp	TIM0_OVF )		; ( Timer 0 overflow handle );	( rjmp	ANA_COMP )		; ( Analog comparator handle );***************************************************************************;*;* FUNCTION;*	i2c_hp_delay;*	i2c_qp_delay;*;* DESCRIPTION;*	hp - half i2c clock period delay (normal: 5.0us / fast: 1.3us);*	qp - quarter i2c clock period delay (normal: 2.5us / fast: 0.6us);*;*	SEE DOCUMENTATION !!!;*;* USAGE;*	no parameters;*;* RETURN;*	none;*;***************************************************************************i2c_hp_delay:	ldi	i2cdelay,2i2c_hp_delay_loop:	dec	i2cdelay	brne	i2c_hp_delay_loop	reti2c_qp_delay:	ldi	i2cdelay,1	i2c_qp_delay_loop:	dec	i2cdelay	brne	i2c_qp_delay_loop	ret;***************************************************************************;*;* FUNCTION;*	i2c_rep_start;*;* DESCRIPTION;*	Assert repeated start condition and sends slave address.;*;* USAGE;*	i2cadr - Contains the slave address and transfer direction.;*;* RETURN;*	Carry flag - Cleared if a slave responds to the address.;*;* NOTE;*	IMPORTANT! : This funtion must be directly followed by i2c_start.;*;***************************************************************************i2c_rep_start:	sbi	DDRD,SCLP		; force SCL low	cbi	DDRD,SDAP		; release SDA	rcall	i2c_hp_delay		; half period delay	cbi	DDRD,SCLP		; release SCL	rcall	i2c_qp_delay		; quarter period delay;***************************************************************************;*;* FUNCTION;*	i2c_start;*;* DESCRIPTION;*	Generates start condition and sends slave address.;*;* USAGE;*	i2cadr - Contains the slave address and transfer direction.;*;* RETURN;*	Carry flag - Cleared if a slave responds to the address.;*;* NOTE;*	IMPORTANT! : This funtion must be directly followed by i2c_write.;*;***************************************************************************i2c_start:					mov	i2cdata,i2cadr		; copy address to transmitt register	sbi	DDRD,SDAP		; force SDA low	rcall	i2c_qp_delay		; quarter period delay;***************************************************************************;*;* FUNCTION;*	i2c_write;*;* DESCRIPTION;*	Writes data (one byte) to the I2C bus. Also used for sending;*	the address.;*;* USAGE;*	i2cdata - Contains data to be transmitted.;*;* RETURN;*	Carry flag - Set if the slave respond transfer.;*;* NOTE;*	IMPORTANT! : This funtion must be directly followed by i2c_get_ack.;*;***************************************************************************i2c_write:	sec				; set carry flag	rol	i2cdata			; shift in carry and out bit one	rjmp	i2c_write_firsti2c_write_bit:	lsl	i2cdata			; if transmit register emptyi2c_write_first:	breq	i2c_get_ack		;	goto get acknowledge	sbi	DDRD,SCLP		; force SCL low	brcc	i2c_write_low		; if bit high	nop				;	(equalize number of cycles)	cbi	DDRD,SDAP		;	release SDA	rjmp	i2c_write_highi2c_write_low:				; else	sbi	DDRD,SDAP		;	force SDA low	rjmp	i2c_write_high		;	(equalize number of cycles)i2c_write_high:	rcall	i2c_hp_delay		; half period delay	cbi	DDRD,SCLP		; release SCL	rcall	i2c_hp_delay		; half period delay	rjmp	i2c_write_bit;***************************************************************************;*;* FUNCTION;*	i2c_get_ack;*;* DESCRIPTION;*	Get slave acknowledge response.;*;* USAGE;*	(used only by i2c_write in this version);*;* RETURN;*	Carry flag - Cleared if a slave responds to a request.;*;***************************************************************************i2c_get_ack:	sbi	DDRD,SCLP		; force SCL low	cbi	DDRD,SDAP		; release SDA	rcall	i2c_hp_delay		; half period delay	cbi	DDRD,SCLP		; release SCLi2c_get_ack_wait:	sbis	PIND,SCLP		; wait SCL high 					;(In case wait states are inserted)	rjmp	i2c_get_ack_wait	clc				; clear carry flag	sbic	PIND,SDAP		; if SDA is high	sec				;	set carry flag	rcall	i2c_hp_delay		; half period delay	ret;***************************************************************************;*;* FUNCTION;*	i2c_do_transfer;*;* DESCRIPTION;*	Executes a transfer on bus. This is only a combination of i2c_read;*	and i2c_write for convenience.;*;* USAGE;*	i2cadr - Must have the same direction as when i2c_start was called.;*	see i2c_read and i2c_write for more information.;*;* RETURN;*	(depends on type of transfer, read or write);*;* NOTE;*	IMPORTANT! : This funtion must be directly followed by i2c_read.;*;***************************************************************************i2c_do_transfer:	sbrs	i2cadr,b_dir		; if dir = write	rjmp	i2c_write		;	goto write data;***************************************************************************;*;* FUNCTION;*	i2c_read;*;* DESCRIPTION;*	Reads data (one byte) from the I2C bus.;*;* USAGE;*	Carry flag - 	If set no acknowledge is given to the slave;*			indicating last read operation before a STOP.;*			If cleared acknowledge is given to the slave;*			indicating more data.;*;* RETURN;*	i2cdata - Contains received data.;*;* NOTE;*	IMPORTANT! : This funtion must be directly followed by i2c_put_ack.;*;***************************************************************************i2c_read:	rol	i2cstat			; store acknowledge					; (used by i2c_put_ack)	ldi	i2cdata,0x01		; data = 0x01i2c_read_bit:				; do	sbi	DDRD,SCLP		; 	force SCL low;******** Добавлено******************************    nop; даем время опуститься SCL (300ns)    nop    cbi    DDRD,SDAP; отпускаем SDA;******** ***************************************	rcall	i2c_hp_delay		;	half period delay	cbi	DDRD,SCLP		;	release SCL	rcall	i2c_hp_delay		;	half period delay	clc				;	clear carry flag	sbic	PIND,SDAP		;	if SDA is high	sec				;		set carry flag	rol	i2cdata			; 	store data bit	brcc	i2c_read_bit		; while receive register not full;***************************************************************************;*;* FUNCTION;*	i2c_put_ack;*;* DESCRIPTION;*	Put acknowledge.;*;* USAGE;*	(used only by i2c_read in this version);*;* RETURN;*	none;*;***************************************************************************i2c_put_ack:	sbi	DDRD,SCLP		; force SCL low	ror	i2cstat			; get status bit	brcc	i2c_put_ack_low		; if bit low goto assert low	cbi	DDRD,SDAP		;	release SDA	rjmp	i2c_put_ack_highi2c_put_ack_low:			; else	sbi	DDRD,SDAP		;	force SDA lowi2c_put_ack_high:	rcall	i2c_hp_delay		; half period delay	cbi	DDRD,SCLP		; release SCLi2c_put_ack_wait:	sbis	PIND,SCLP		; wait SCL high	rjmp	i2c_put_ack_wait	rcall	i2c_hp_delay		; half period delay	ret;***************************************************************************;*;* FUNCTION;*	i2c_stop;*;* DESCRIPTION;*	Assert stop condition.;*;* USAGE;*	No parameters.;*;* RETURN;*	None.;*;***************************************************************************i2c_stop:	sbi	DDRD,SCLP		; force SCL low	sbi	DDRD,SDAP		; force SDA low	rcall	i2c_hp_delay		; half period delay	cbi	DDRD,SCLP		; release SCL	rcall	i2c_qp_delay		; quarter period delay	cbi	DDRD,SDAP		; release SDA	rcall	i2c_hp_delay		; half period delay	ret;***************************************************************************;*;* FUNCTION;*	i2c_init;*;* DESCRIPTION;*	Initialization of the I2C bus interface.;*;* USAGE;*	Call this function once to initialize the I2C bus. No parameters;*	are required.;*;* RETURN;*	None;*;* NOTE;*	PORTD and DDRD pins not used by the I2C bus interface will be;*	set to Hi-Z (!).;*;* COMMENT;*	This function can be combined with other PORTD initializations.;*;***************************************************************************i2c_init:	clr	i2cstat			; clear I2C status register (used					; as a temporary register)	out	PORTD,i2cstat		; set I2C pins to open colector	out	DDRD,i2cstat	ret;***************************************************************************;*;* PROGRAM;*	main - Test of I2C master implementation;*;* DESCRIPTION;*	Initializes I2C interface and shows an example of using it.;*;***************************************************************************RESET:main:	rcall	i2c_init		; initialize I2C interface;**** Write data => Adr(00) = 0x55 ****	ldi	i2cadr,$A0+i2cwr	; Set device address and write	rcall	i2c_start		; Send start condition and address	ldi	i2cdata,$00		; Write word address (0x00)	rcall	i2c_do_transfer		; Execute transfer	ldi	i2cdata,$55		; Set write data to 01010101b	rcall	i2c_do_transfer		; Execute transfer	rcall	i2c_stop		; Send stop condition;**** Read data => i2cdata = Adr(00) ****	ldi	i2cadr,$A0+i2cwr	; Set device address and write	rcall	i2c_start		; Send start condition and address	ldi	i2cdata,$00		; Write word address	rcall	i2c_do_transfer		; Execute transfer	ldi	i2cadr,$A0+i2crd	; Set device address and read	rcall	i2c_rep_start		; Send repeated start condition and address	sec				; Set no acknowledge (read is followed by a stop condition)	rcall	i2c_do_transfer		; Execute transfer (read)	rcall	i2c_stop		; Send stop condition - releases bus	rjmp	main			; Loop forewer;**** End of File ****