Администрация форума не несёт ответственности за достоверность информации и оставляет за собой право редактировать или в особых случаях даже удалять посты без предупреждения. Спасибо за понимание.

Программирование ATMEL в BASCOM.

Информация о пользователе

Привет, Гость! Войдите или зарегистрируйтесь.


Вы здесь » Программирование ATMEL в BASCOM. » Связь проводная и бесп-ная, интерфейсы, протоколы » проблемка с хардварным I2С (проблемка "зависания" аппаратного TWI)


проблемка с хардварным I2С (проблемка "зависания" аппаратного TWI)

Сообщений 1 страница 13 из 13

1

Вот у меня  возникла небольшая (боольшая) проблемка с хардварным 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)

0

2

Может потому, что после конфигурации нет строки I2cinit ?

0

3

Penumbra написал(а):

Подтвержение_записи:

И ещё. Зачем такие сложности с проверкой.
Записали, прочитали записанный регистр стандартными средствами и сравнили две переменных.
Совпало, значит всё ок.
Не стал разбираться в программе, но на первый взгляд там не всё корректно.

0

4

sva-don написал(а):

Может потому, что после конфигурации нет строки I2cinit ?

Стоит, просто забыл скопировать,.

sva-don написал(а):

Penumbra написал(а):

    Подтвержение_записи:

И ещё. Зачем такие сложности с проверкой.
Записали, прочитали записанный регистр стандартными средствами и сравнили две переменных.
Совпало, значит всё ок.
Не стал разбираться в программе, но на первый взгляд там не всё корректно.

Это я уже пытался искать ошибку ... где вылезет

Отредактировано Penumbra (2025-04-06 13:05:46)

0

5

А вот это (выделено) обязательно ?

Penumbra написал(а):

$lib "I2C_TWI.LBX"
Config Scl = Portd.0                                        ' I2c Scl
Config Sda = Portd.1                                        ' I2c Sda
Config Twi = 100000

0

6

Nord написал(а):

А вот это (выделено) обязательно ?
Penumbra написал(а):

    $lib "I2C_TWI.LBX"
    Config Scl = Portd.0                                        ' I2c Scl
    Config Sda = Portd.1                                        ' I2c Sda
    Config Twi = 100000

Ну, я же хочу аппаратный I2C, а не программный.. (порты для atmega2560)

Я же безоговорочно верю мануалу  BASCOM :

Код:
$lib"i2c_twi.lbx"' we do not use software emulated I2C but the TWI
 
Config Scl =Portc.5 ' we need to provide the SCL pin name
Config Sda =Portc.4 ' we need to provide the SDA pin name
Config Twi = 100000 ' wanted clock frequency

Все как завещал разработчик..

0

7

Penumbra написал(а):

Ну, я же хочу аппаратный I2C, а не программный.. (порты для atmega2560)
Я же безоговорочно верю мануалу  BASCOM:
$lib"i2c_twi.lbx"' we do not use software emulated I2C but the TWI

Config Scl =Portc.5 ' we need to provide the SCL pin name
Config Sda =Portc.4 ' we need to provide the SDA pin name
Config Twi = 100000 ' wanted clock frequency

Все как завещал разработчик..

Ну, не все "завещания" ведут к истине... ;)
Всегда использую аппаратный I2C и ни разу (!) не устанавливал скорость...
Ну, разве в ходе экспериментов...

Потом вот еще...
У вас количество отправленных байтов соответствует требуемым ?
А то Slave (возможно) ждет еще, а "тиграм мяса не докладывают"... ;)
После I2cstop принудительно:
TWCR.TWEN = 1
TWCR.TWIE = 1
TWCR.TWINT = 1
TWCR.TWSTO = 1
... гарантированно остановит Мастера.
По сути это - дополнительный I2cstop, но уже без библиотеки.

0

8

Nord написал(а):

После I2cstop принудительно:
TWCR.TWEN = 1
TWCR.TWIE = 1
TWCR.TWINT = 1
TWCR.TWSTO = 1
... гарантированно остановит Мастера.
По сути это - дополнительный I2cstop, но уже без библиотеки.

После I2cstop принудительно уже не получается.. Так как  контроллер "зацикливается" на операторе I2cstop, тоесть внутри оператора, где он ждет аппаратного сброса TWSTO, а этого не происходит изза того что  TWI  поймал глюк на шине и у нас начался вечный цикл
LDS R20,$00BC
SBRC R20,$04
RJMP $-0006
Но.. я тоже подумал про I2cstop, но уже без библиотеки
После танцев с бубном, курения мануалов  :smoke:  и окуривания помещения ладаном (что, кстати, дало свои результаты), я решил написать  :writing:  что-то вроде своего 'оператора' I2cStop — подпрограммку I2cStopSafe. Уже 4 часа мучаю как Proteus, так и макетную плату, издеваюсь над шиной I2C: убираю резисторы, запускаю помехи, устраиваю конфликты на шине... Зависаний пока не было, так что теперь WDT не нужен  8-)

Код:
'===============================================================================
 I2cStopSafe:

' Проверка на BUS ERROR (TWSR = &H00)
   If TWSR = &H00 Then
      Print "Error:I2C BUS ERROR (TWSR = &H00)!"   'Только на время отладки
   End If

   'Twcr = (1 << TWINT) | (1 << TWSTO) | (1 << TWEN)
   Twcr = &B10010100                               ' Отправляем команду STOP + Сброс флага прерывания + Включение TWI

   ' Ждем, пока АППАРАТНЫЙ модуль сбросит бит TWSTO (бит 4)
   Timeout_stp = 0
_Wait_TWSTO_Loop:


   Twcr_val = Twcr                                 ' Читаем текущее значение TWCR
   If Twcr_val.4 = 0 Then Goto _Stop_OK            ' Бит TWSTO сброшен, выходим нафиг

   ' Бит еще установлен, ждем немного
   Waitus 10                                       ' !! Короткая задержка в МИКРОсекундах !!
   Incr Timeout_stp

   If Timeout_stp > 200 Then Goto _Stop_Timeout    ' Таймаут примерно 200 * 10 мкс = 2 мс (должно быть более чем достаточно)
   Goto _Wait_TWSTO_Loop

_Stop_Timeout:  ' Если завис — перезапускаем TWI  Бит TWSTO не сбросился аппаратно - ЯВНАЯ ПРОБЛЕМА!
   Print "Error: I2C STOP Timeout (TWSTO stuck)!"   'Только на время отладки
   ' Пытаемся принудительно сбросить TWI
   Twcr = 0                                         ' Выключить TWI
   Waitus 10
   TWCR = &B00000100                                ' Включить TWI заново


_Stop_OK:
   ' Бит TWSTO сброшен аппаратно, все прошло штатно.
   ' Можно добавить небольшую паузу для стабилизации шины, если нужно.. надо в железе посмотреть..
    Waitus 5

Return
'===============================================================================

Надо будет ещё потестировать шину. Если где-то вылезут 'зависания', то придётся добавить что-то вроде фонового мониторинга состояния TWI из прерывания таймера и выполнять принудительный сброс.

Отредактировано Penumbra (2025-04-07 01:37:17)

0

9

А если после окончания передачи пакета просто сделать Waitus 200, а потом стандартно скомандовать I2CStop ?
С длительностью паузы можно "поиграться"...

Это, конечно, костыль, но иногда и они работают... ;)

0

10

Я пробовал, но если в момент  приема/передачи на шине происходит глюк то пауза уже не играет никакой роли .

0

11

Фишка в том, что оператором I2CStop мы устанавливаем TWSTO в 1, и контроллер отправляет команду STOP. После успешной отправки он сам, аппаратно, сбрасывает TWSTO в 0, а оператор I2CStop ожидает этот 0... но его нет. В результате получаем вечный цикл

Отредактировано Penumbra (2025-04-07 14:57:43)

0

12

А Slave не косячит на шине ?

С кем, кстати, МК общается ?

0

13

Ответа не дождался... ;)

Судя по комментам в листинге, вы опять "воюете" с м/с памяти ?
Но у вас уже была "схватка" - проблема с записью в ЕЕПРОМ 24LC64
Тогда таких проблем с I2C не возникало ?

0


Вы здесь » Программирование ATMEL в BASCOM. » Связь проводная и бесп-ная, интерфейсы, протоколы » проблемка с хардварным I2С (проблемка "зависания" аппаратного TWI)