Вот у меня возникла небольшая (боольшая) проблемка с хардварным I2С...
Контроллер иногда "зависает" наглухо, не часто, но бывает при работе с шиной I2С . Причём "зависает" на операторе I2cstop (возможно, но не точно) в коде:
$lib "I2C_TWI.LBX"
Config Scl = Portd.0 ' I2c Scl
Config Sda = Portd.1 ' I2c Sda
Config Twi = 100000
....
....
I2cstart ' Стартуем
I2cwbyte wr_adress ' Адресное обращение к микросхеме
I2cwbyte mem_adr_high ' Отправляем старший байт адреса ячейки памяти
I2cwbyte mem_adr_low ' Отправляем младший байт адреса ячейки памяти
I2cwbyte byte_high (1) ' Записываемый байт
I2cwbyte byte_low (1) ' Записываемый байт
I2cwbyte byte_high (2) ' Записываемый байт
I2cwbyte byte_low (2) ' Записываемый байт
I2cwbyte byte_high (3) ' Записываемый байт
I2cwbyte byte_low (4) ' Записываемый байт
.....
I2cstop ' Освобождаем шину I2c
Gosub Подтвержение_записи
.....
Подтвержение_записи: ' Подпрограмма для подтверждения записи данных
'-------------------------------------------------------------------------------
Timeout_cnt = 0
Waitus 100 ' Начальная пауза перед первой проверкой
_Loop_Confirm_Write:
I2cstart ' Стартуем
I2cwbyte wr_adress ' Адресное обращение к микросхеме
If Err = 0 Then Goto _Confirm_Write_OK ' Ответила (ACK)! Запись завершена.
' не ответила (NACK), значит занята или ошибка
I2cstop ' !!! Важно: Отправить STOP после неудачной попытки !!!
Waitus 200 ' Небольшая пауза между попытками опроса
Incr Timeout_cnt
If Timeout_cnt > 150 Then Goto _Confirm_Write_Error ' Таймаут (~30мс с учетом пауз..возможно но не точно)
Goto _Loop_Confirm_Write ' Повторяю попытку
_Confirm_Write_Error:
' Индикация ошибки таймаута
Print "Error: TWI Write Confirm Timeout!"
Goto _Confirm_Write_Exit ' Выходим
_Confirm_Write_OK:
' После успешного ACK нужно ее освободить
I2cstop ' !!! ДОБАВЛЕНО 04.04.25: Освобождаем шину !!!
'-------------------------------------------------------------------------------
_Confirm_Write_Exit:
Return . Если верить Протеусу, он даже не зависает, а уходит в вечный цикл. На вкладке дизассемблера он "вечно" выполняет код:
509E 9140 00BC LDS R20,$00BC 50A4 FD44 SBRC R20,$04 50A6 CFFC RJMP $-0006(509E)
Если я правильно понял, то это:
509E 9140 00BC LDS R20,$00BC: Прочитать регистр управления TWI (TWCR) в R20.
50A4 FD44 SBRC R20,$04: Пропустить следующую инструкцию (RJMP), если бит 4 в R20 (т.е. в TWCR) равен 0. Смотрю в даташит: бит 4 в TWCR - это TWSTO (TWI STOP Condition).
50A6 CFFC RJMP $-0006(509E): Перейти назад к 509E, если SBRC не пропустил, т.е. если бит TWSTO был равен 1.
То есть - бесконечный цикл ожидания завершения генерации STOP-условия на шине I2C. Бит TWSTO (Stop Condition) устанавливается для завершения передачи на шине, но он аппаратно сбрасывается только после успешного выполнения STOP. А STOPа нет... глюк на шине, помеха и т.д., транзакция была прервана.
Я так понял, это лаг с библиотекой i2c_twi.lbx.
Вот и вопрос: как решить проблему зависания аппаратного TWI?
Отредактировано Penumbra (2025-04-06 03:41:25)

и окуривания помещения ладаном (что, кстати, дало свои результаты), я решил написать
что-то вроде своего 'оператора' I2cStop — подпрограммку I2cStopSafe. Уже 4 часа мучаю как Proteus, так и макетную плату, издеваюсь над шиной I2C: убираю резисторы, запускаю помехи, устраиваю конфликты на шине... Зависаний пока не было, так что теперь WDT не нужен