Задача простая:
есть пик12, он мастер, к нему подключен расширитель. В разрез соединения подключен I2C Debugger.
Необходимо используя протокол i2c снять данные с расширителя портов и записать их в регистр пика. Дебагер в данном случае будет гарантом того, что мы общаемся по протоколу i2c.
Выглядит схема вот так:

Я прочитал про сам протокол, понял что мне надо выводить тактовую частоту на SCL и используя её как несущую передавать данные по SDA. Прочёл про то как происходит обмен данными, про стартовый и стоповый биты, про подтверждение/непотверждение, про чтение и запись.
В общем к делу я подошёл немного по-тупому. Что я сделал? Написал собственно следующие подпрограммы:
- отправления стартового бита
- отправления данных (адрес слейва или саму дату)
- считывания с порта сигналов и сохранения её в регистре (сохранение даты с канала SDA)
- отправления подтверждения
- отправления стопового бита
Короче, я запустил всё это и попытался сделать запрос данных с PCF8574 и ничего в ответ не получил. Кроме того даже I2C Debugger не дал ничего кроме вопросов:

Ну а вот сами сигналы:

Вот они же ближе:

В общем я пока пинаю на то, что у меня есть какой-то рассинхрон по тактовой частоте. Но чёрт возьми: почему стартовый бит-то не читается? я сделал прямо как в доках от филипса.
Вот стартовый бит из книжки по микрочипу:

Вот мой стартовый бит:

Они похожи.
Справа от линии я настраивал порты МК, слева от линии уже работали подпрограммы и вроде как по спаду должно было прийти "S" - стартовый сигнал на дебаггер, но его там нет.
В общем: что вы думаете? куда мне идти? я уже думаю блин начать просто компоновать пакет и запускать таймер который выдаёт импульсы такта на SCL, и там как-нить по тактам таймера выпихивать пакет на линию SDA (но едрён батон, как я вот читать буду - я пока хрен знаю).
Ну а код у меня написан из расчёта машинных тактов - может в этом и косяк?
Сам код:
Код:
;==============
; Main.asm file generated by New Project wizard
;
; Created: Чт янв 14 2016
; Processor: PIC12F675
; Compiler: MPASM (Proteus)
;==============
;==============
; DEFINITIONS
;==============
#include p12f675.inc ; Include register definition file
__CONFIG _INTRC_OSC_CLKOUT & _MCLRE_OFF
;_INTRC_OSC_CLKOUT - INTOSC oscillator: CLKOUT function on GP4/OSC2/CLKOUT pin, I/O function on GP5/OSC1/CLKIN
;_WDT_OFF - WDT disabled
;_MCLRE_OFF - GP3/MCLR pin function is digital I/O, MCLR internally tied to VDD
;настройки для I2C
#define slave1 b'01001111'
#define scl GPIO,1 ;Clock I2C line
#define sda GPIO,2 ;Data I2C line
;Регистры для шины I2C
cblock 020h ;БАНК памяти 0
SLAVE_ADDR
MASTER_input_DATA
MASTER_output_DATA
temp ;Счётчик битов
endc
;==============
; RESET and INTERRUPT VECTORS
;==============
; Reset Vector
RST code 0x0
goto Start
;==============
; CODE INTERRUPT
;==============
;INT code 0x0004
; goto interrupt
; retfie
;==============
; CODE SEGMENT
;==============
PGM code
Start
;гп0 - вход/выход семисегментника
;гп1 - вход/выход семисегментника
;гп2 - вход/выход I2C / sda
;гп3 - вход прерывания клавиатуры
;гп4 - выход такта I2C / scl
;гп5 - выход светодиода
;------ настройка портов GPIO
; перешли в банк памяти 0
bcf STATUS, RP0 ;установить бит RP0 в регистре STATUS в ноль
;(непосредственная адресация в банке памяти 00 = банк 0 000h-07Fh)
; обнуление портов и/о
clrf GPIO ;установка в ноль регистра GPIO начиная с 7 бита:
;хх/000000
; отключение выходов компаратора на ногах пика
movlw B'00000111'
movwf CMCON ;из аккумулятора переслать содержимое (???) в CMCON
;видимо тут переданы нули - хх/000(хз чё)/000(компораторы выключены)
;перешли в банк памяти 1
bsf STATUS, RP0 ;установить бит RP0 в регистре STATUS в единицу
;(непосредственная адресация в банке памяти 01 = банк 0 80h-FFh)
; DONT USE ANY PINS AS ANALOGUE, ONLY DIGITAL
MOVLW 0
MOVWF ANSEL
; настройка ввода/вывода портов
movlw B'00001000' ;записать в аккумулятор 00001000
movwf TRISIO ;из аккумулятора переслать содержимое (00001000) в TRISIO
;конфигурируем 6ти разрядный порт GPIО отдельно на каждый GP0,...,GP5
;0 - канал работает на выход, 1 - на вход
;'хх001000' - GP5-вsх/GP4-вых/GP3-вх(всегда только вход)/GP2-вых/GP1-вых/GP0-вsх
;GP4 настраивается как вывод тактового сигнала командой __CONFIG
;------ настройка прерываний
; разрешить прерывание на входе GP3
;movlw B'00001000' ;маска для допуска прерывания на GP3
;movwf IOCB ;установили маску в регистр - разрешили прерывание на GP3
; разрешение прерываний на GPIO и вообще
;movlw B'10001000' ;маска для допуска глобальных прерываний и прерываний по изменению сигнала на GPIO
;movwf INTCON ;становили маску в регистр
movlw 0
movwf slave1
movwf MASTER_input_DATA
movwf MASTER_output_DATA
Loop
bsf sda
bsf scl
goto interrupt_gpie
;==============
; обработка прерываний
;==============
;interrupt
; btfsc INTCON, GPIF
; goto interrupt_gpie
; return
interrupt_gpie
;прерывание по гп3 - ввели цифру на клавиатуре, надо её получить и сохранить
movlw slave1 ;в аккумулятор записать 8=00001000
movwf SLAVE_ADDR
call Read_I2C
return
;==============
; библиотека I2C
;==============
Read_I2C
movlw 8 ;в аккумулятор записать счётчик до семи
movwf temp
call Send_Start_Bit_I2C ;1. Послать стартовую последовательность
call Choose_Slave_I2C ;2. Послать адрес устройства к которому обращаемся с нулевым битом чтения/записи (четный адрес)
call Wait_ack_I2C ;3
call Read_data_I2C
call Send_NACK_Bit_I2C
call Send_Stop_Bit_I2C
return
Choose_Slave_I2C
metka btfsc SLAVE_ADDR,7
bsf sda
nop
bsf scl
rlf SLAVE_ADDR,1
nop
nop
nop
bcf scl
bcf sda
decfsz temp,1
goto metka
return
Wait_ack_I2C
bsf scl
nop
movlw 7 ;в аккумулятор записать счётчик до семи
movwf temp
nop
bcf scl
bcf sda
return
Read_data_I2C
metka2 btfsc sda
bsf MASTER_input_DATA,1
nop
bsf scl
rrf MASTER_input_DATA,1
nop
nop
nop
bcf scl
bcf sda
decfsz temp,1
goto metka2
nop
return
Send_NACK_Bit_I2C
nop
nop
nop
bsf sda;
bsf scl
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
bcf scl
bcf sda
return
Send_Stop_Bit_I2C
bsf scl;
bsf sda
nop
nop
return
Send_Start_Bit_I2C
bsf sda
bsf scl
nop
bcf scl
bcf sda
return
;==============
END
Может есть какой-то путь по-проще?