Страница 1 из 1

Софтовый I2C

Добавлено: Ср июн 10, 2009 13:35:49
KVorb
Понадобился мне софтовый I2C. Взял пример из апноты avr300.asm
Отправка данных мастером работает, чтение одного байта тоже работает.
А вот при попытке прочитать два байта, в первом есть данные, а второй всегда равен 0x00 :( Во втором байте точно должен быть не 0, проверял с аппаратным I2C на Mega8.

Вот сам код:

Код: Выделить всё

;Адрес I2C + write и 	Старт	
ldi  	i2cadr,0b10011110+i2cwr	
rcall	i2c_start					
	
;Адрес ячейки и Отправка
ldi  	i2cdata,$A2			 
rcall	i2c_do_transfer				

;Адрес I2C + read и Повторный старт
ldi  	i2cadr,0b10011110+i2crd	
rcall	i2c_rep_start				

;Чтение
;Этот байт читается, после него ACK 
rcall	i2c_do_transfer				
mov  	r18,i2cdata	
	
sec							 
;Чтение
;В этом байте всегда 0x00 ( почему? ), после него NACK	
rcall	i2c_do_transfer				
mov  	r19,i2cdata

;STOP
rcall	i2c_stop					
Проверял и на макетке и в протеусе, везде одинаково.

Добавлено: Ср июн 10, 2009 14:53:21
KVorb
Разобрался :))

Оказывается в апноте есть ошибка. Она приводит к тому, что при чтении все байты, кроме первого (после адреса слейва) читаются как 0x00. Это связано с тем, что при выдачи мастером ACK в ответ на чтение 1-го байта линия SDA засаживается контроллером на "0" и остается в этом состоянии на протяжении всех последующих чтений.

Оригинальный код:

Код: Выделить всё

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
	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
Поменять на:

Код: Выделить всё

i2c_read:
	rol	i2cstat			; store acknowledge
						; (used by i2c_put_ack)
	ldi	i2cdata,0x01		; data = 0x01
i2c_read_bit:				; do
	sbi	DDRC,SCLP		; 	force SCL low
;******** Добавлено******************************
    nop; даем время опуститься SCL (300ns)
    nop
    nop
    nop
    nop
    cbi    DDRC,SDAP; отпускаем SDA
;******** ***************************************
	rcall	i2c_hp_delay		;	half period delay

	cbi	DDRC,SCLP		;	release SCL
	rcall	i2c_hp_delay		;	half period delay

	clc				;	clear carry flag
	sbic	PINC,SDAP		;	if SDA is high
	sec				;		set carry flag

	rol	i2cdata			; 	store data bit
	brcc	i2c_read_bit		; while receive register not full
Спасибо тем кто очень хотел, но не успел помочь :)))

Добавлено: Ср июн 10, 2009 15:02:43
ploop
KVorb, это вам спасибо, следил за темой. Реально скоро пригодится.