Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Помогите советом. I2C
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > AVR
SasaVitebsk
У меня есть в устр-ве шина I2C. На ней сидит мастер - atmega640(I2C софтовый) пару микрух памяти 24с512 и atmega48(I2C аппаратный слэйв). Всё это подпёрто резисторами 3.9кОм. Общая протяжённость шины составляет ~30см.

Изначально работал побайтно с 24с512 и блоком с mega48. Всё работало суперустойчиво. Сутками. Ни единого сбоя. С какого-то момента я попытался значительно повысить скорость на чтение (а заодно на запись) с 24с512. Для этого я ввёл буфер на 32 байта и начал писать/читать блоками по 32 байта. В принципе всё работает, но периодически возникают сбои. Я выяснил. Сбои возникают как при чтении, так и при записи. Их характер - случайный и хаотический. Создаётся ощущение, что сбои - результат помех. Увеличение задержек - не дало результата.

Может кто сталкивался с чем-нибудь подобным и может подсказать? Пока не знаю куда рыть.
singlskv
Цитата(SasaVitebsk @ Jun 17 2007, 17:20) *
...удалено....

А какая частота шины i2c ? 3,9K может быть многовато при большом количестве
устройств(емкость шины). Попробуйте уменьшить до 2,7 или даже до 1,5.

У меня при pullup 4,7 отказывалось работать при 400KHz с FRAM, а при 1,5K
завелось на 1,4MHz (не с Atmega).
zltigo
То:singlskv - насточтельная просьба избегать совершенно не нужных цитирований.

24xxx совершенно беспроблемно работают в блочных режимах с аппаратными мастерами I2C.
К подтягивающему резистору скорее всего не очень критичны мне попалась в свое время отладочная борда от Olimex, где болгарские друзья вообще не развели один из подтягивающих резисторов (кажется SDA) к Микрочиповской EEPROM. Каким чудом на утечках хоть на пониженной частоте со сташными сбоями, но работало непонятно! У меня обычно стоят 2.2K.
singlskv
Цитата(zltigo @ Jun 17 2007, 18:04) *
То:singlskv - насточтельная просьба избегать совершенно не нужных цитирований.

Эээ... привычка, когда отвечаешь в длинной ветке нужно обозначить кому отвечаешь.
В данном случае это конечно было не нужно smile.gif
Цитата
мне попалась в свое время отладочная борда от Olimex, где болгарские друзья вообще не развели один из подтягивающих резисторов (кажется SDA) к Микрочиповской EEPROM. Каким чудом на утечках хоть на пониженной частоте со сташными сбоями, но работало непонятно!

Ну все-таки наверное работало на внутреннем пулапе ?
Вроде как i2c по стандарту умеет тянуть только вниз, и если вобще нет пулапа
то там должен быть всегда 0.
Хотя конечно реализации на разных контроллерах могут достаточно
сильно отличатся от стандарта biggrin.gif
SasaVitebsk
Экспериментировал от 1МГц до 100кГц. На высоких скоростях колличество сбоев увеличивается, но до определённого порядка. Начиная примерно с 360кГц количество сбоев от тактовой частоты не зависит.

Понятно что в пакетном режиме должно работать. У самого всё работало в других проектах. Только запись пакетную делал один раз. Но задержки ставил большие. А сейчас впритык. Сам уже не знаю где рыть. Пока ни одной ошибки не нашёл. Создаётся ощущение что проблема с вызывом прерываний в определённых местах. Так как ошибки проявляются только при значительных объёмах (практически непрерывной работе) передаваемой от I2C инфы. Возможно из-за софтового I2C.

Всем спасибо. Буду искать.
singlskv
Цитата(SasaVitebsk @ Jun 17 2007, 20:15) *
Экспериментировал от 1МГц до 100кГц. На высоких скоростях колличество сбоев увеличивается, но до определённого порядка. Начиная примерно с 360кГц количество сбоев от тактовой частоты не зависит.

пулап все-таки попробуйте поменьше, хотя бы просто для эксперимента
Цитата
Только запись пакетную делал один раз. Но задержки ставил большие. А сейчас впритык. Сам уже не знаю где рыть. Пока ни одной ошибки не нашёл. Создаётся ощущение что проблема с вызывом прерываний в определённых местах. Так как ошибки проявляются только при значительных объёмах (практически непрерывной работе) передаваемой от I2C инфы. Возможно из-за софтового I2C.

Задержки между каждым пакетом или между обращениями к разным устройствам ?
Ошибки только с 24с512 или с mega48 тоже ?
На mega48 обработка через прерывания ?
Ошибки с 24xx случайно происходят не после общения с мегой без паузы ?
Какая частота ошибок (примерно) ?

Ну и код общения через i2c(на мегах) лучше конечно покажите...
Для редко возникающих ошибок знаю одну багу/фичу...
zltigo
Цитата(singlskv @ Jun 17 2007, 17:18) *
Ну все-таки наверное работало на внутреннем пулапе ?

У LPC2000 на выводах, которые могут работать для I2C pullup нет. Совсем нет sad.gif, даже если они используется не для I2C.
singlskv
Цитата(zltigo @ Jun 17 2007, 20:40) *
У LPC2000 на выводах, которые могут работать для I2C pullup нет. Совсем нет sad.gif, даже если они используется не для I2C.

Ну тогда это точно какой-то фокус учитывая что LPC это Philips 07.gif
zltigo
Цитата(singlskv @ Jun 17 2007, 19:46) *
Ну тогда это точно какой-то фокус учитывая что LPC это Philips 07.gif

Никаких фокусов - сигнал при рассмотрении осциллографом был жутчайший, но как-то иногда понимался взаимодействующими сторонами. Ну а иметь хорошие I2C контроллеры Филипса положение обязывает smile.gif.
bodja74
А софтовый I2C следит за SCL при растяжке ACK слейвом?
singlskv
Цитата(zltigo @ Jun 17 2007, 21:00) *
Никаких фокусов - сигнал при рассмотрении осциллографом был жутчайший, но как-то иногда понимался взаимодействующими сторонами. Ну а иметь хорошие I2C контроллеры Филипса положение обязывает smile.gif.

Положение то обязывает,
но вот попробуйте объяснить мне, откуда там в сигнале могли единички
появлятся при полном отсутствии пулапов.
То что на i2c сигналы тянутся только к 0, принципиально, т.к. иначе
сложно реализовать мультимастер.
zltigo
Цитата(singlskv @ Jun 17 2007, 20:24) *
но вот попробуйте объяснить мне, откуда там в сигнале могли единички
появлятся при полном отсутствии пулапов.

Нормального сигнала не было, но наводки с соседнего клока были по этим фронтам оно все как-то жило.
Цитата
То что на i2c сигналы тянутся только к 0....

Я не запрашивал курс ликбеза и объяснений почему не могло работать, то, что хоть хреново, но работало на моих глазах.
singlskv
Цитата(zltigo @ Jun 17 2007, 22:13) *
Нормального сигнала не было, но наводки с соседнего клока были по этим фронтам оно все как-то жило.
Я не запрашивал курс ликбеза и объяснений почему не могло работать, то, что хоть хреново, но работало на моих глазах.

Ну я вобще-то и не собирался устраивать ликбез, только вот для меня осталось странным,
что получив подобный результат Вы не разобрались в чем была фишка...
Ну не должно было там быть единички, а Вы говорите что была и все было "Ok"...

P.S. Раскажите откуда все-таки 1ки появились...
zltigo
Цитата(singlskv @ Jun 17 2007, 21:44) *
... только вот для меня осталось странным,
что получив подобный результат Вы не разобрались в чем была фишка...

А чего странного? Мне эта 'фишка' без надобности - угробил несколько часов (начинал дома копаться и боролся с нежеланием искать сетевой шнур от осциллографа), потом увидел кашу, выяснил, что и резистор и место для него отсутствуют, как класс, грязно выругался по-болгарски smile.gif, запаял прямо на корпус AT24 первый попавшийся выводной резистор и все.
Цитата
P.S. Раскажите откуда все-таки 1ки появились...

Читайте предыдущий пост.
SasaVitebsk
Цитата(bodja74 @ Jun 17 2007, 20:04) *
А софтовый I2C следит за SCL при растяжке ACK слейвом?


У меня один мастер. Я не сталкивался с таким. Уточните откуда может быть растяжка.

И 24c512 и mega48 - аппаратно формируют сигналы.

Насчёт ошибок у м48 информации нет. Я пока это проконтролировать не могу. Необходимо на ней писать специальную отладочную программу чтобы это увидеть. Так, на вскидку, на ней ошибок нет.

Ночь длинная. Проведу сейчас дополнительные исследования, тогда доложу о результатах. По поводу уменьшения резисторов - что-то нет веры: должно и так работать, по-моему.

Средний примерный объём ошибокЖ 1-2 на 3к инфы
singlskv
Цитата(zltigo @ Jun 17 2007, 22:13) *
Нормального сигнала не было, но наводки с соседнего клока были по этим фронтам оно все как-то жило.

наводки по фронтам 07.gif
если это ловля кода по радиоканалу я бы еще поверил...
zltigo
Цитата(singlskv @ Jun 17 2007, 21:58) *
если это ловля кода по радиоканалу я бы еще поверил...

Радиоканал? С каких частот у нас радио начинается знаете? Ну а даже заваленые 20ns фронты LPX2000 великолетно наводятся на идущую параллельно висящую дорожку.
singlskv
Цитата(zltigo @ Jun 17 2007, 22:53) *
А чего странного? Мне эта 'фишка' без надобности - угробил несколько часов (начинал дома копаться и боролся с нежеланием искать сетевой шнур от осциллографа), потом увидел кашу, выяснил, что и резистор и место для него отсутствуют, как класс, грязно выругался по-болгарски smile.gif, запаял прямо на корпус AT24 первый попавшийся выводной резистор и все.

Читайте предыдущий пост.

Дык а фишка заключается в том, что Вы неразобравшись в Вашем конкретном случае
начинаете советовать остальным (неразобравшись в чем у Вас была проблемма)
как нужно организовывать обмен по i2c другим...
вот это и странно...
Цитата
Радиоканал? С каких частот у нас радио начинается знаете? Ну а даже заваленые 10ns фронты LPX2000 великолетно наводятся на идущую параллельно висящую дорожку.

Знаю, но к приему сигнала по i2c без пулапов это не имеет никакого значения.
Ладно, если Вы не против довайте попробуем отвлечся smile.gif и ответить на вопрос автора.

Цитата(SasaVitebsk @ Jun 17 2007, 22:54) *
И 24c512 и mega48 - аппаратно формируют сигналы.

Вы понимаете что аппаратно формируемые сигналы от 24xx и от ATmegaxx имеют
по крайней мере разную форму ?
Все зависит от софта на Атмега...
zltigo
Цитата(singlskv @ Jun 17 2007, 22:24) *
...что Вы неразобравшись
...
начинаете советовать остальным (неразобравшись в чем у Вас была проблемма)
как нужно организовывать обмен по i2c другим...

Я разобрался в том, что:
1. AT24 очень НЕ КРИТИЧНА к качеству сигналов и шаманство с уменьшению pullup-ов маловероятно приведет к результату.
2. AT24 не имеет проблем с блочным режимом, по крайней мере при работе с железным I2C контроллером.
Кроме того, я разобрался в чем была конкретная проблема с конкретной платой.
О чем и написал - перечитайте пост №3.
Если Вам привиделись какие-то "советы" - это Ваши проблемы.
SasaVitebsk
Я, к примеру, совершенно не удивился сообщению zltigo. И совершенно не понимаю что вас в нём удивляет? I2C - статическая шина. Следовательно поступающие сигналы не должны быть привязаны ко времени. Если подтяжки нет, то наводки на этих ножках рано или поздно но уложатся в нужный сигнал, как ни крути. Один раз я столкнулся со случаем работы контроллера дисковода (ВГ93) при обрезанном сигнале управления (то ли RD то ли WR уже не помню, но помню что совершенно необходимый). Тот милый человек, который смотрел эту плату до меня зачем-то перерезал его с помощью лезвия. Наверное потом хотел соплю кинуть, да подзабыл. Когда я нашёл настоящую неисправность и запустил злополучный синклер, то выяснил что дисковод работает, но только длинные файлы не читает. Причина выяснилась достаточно быстро. Анализирую ноги ВГ93 было обнаружено, что одна просто болтается в воздухе. Как я писал выше дисковод полностью работал и короткие файлы читал исправно.

zltigo спасибо за информацию Ваш пост я понял.

2 singlskv. Также спасибо. Я правда не совсем понял фразу
Цитата
Вы понимаете что аппаратно формируемые сигналы от 24xx и от ATmegaxx имеют
по крайней мере разную форму ?
Все зависит от софта на Атмега...


Софт на м48 писал, естественно я сам. Наверное Вы имели ввиду не "разную форму", а "работают по разному". Это, безусловно, я понимаю. Ещё раз повторяю. Если работа с at24 идёт побайтно, то никаких проблем не возникает. Два изделия работают круглосуточно больше месяца.

2 zltigo. При блочной записи. Записываю 32 байта. Границы верны. То есть принципиально всё пишется правильно. Вопрос достаточно ли одной задержки 10мс после записи страницы? Точнее части страницы. Помню в какой-то мне приходилось задержку на запись делать = Twr * число записываемых байт. Правда это в какой-то младшенькой памяти было.
zltigo
Цитата(SasaVitebsk @ Jun 17 2007, 23:23) *
Вопрос...

Увы, я софтовой эмуляцией не занимался - работает железный контроллер все на прерываниях, т.е. никакие задержки не формируются - достаточно ACK.
Dog Pawlowa
Цитата(SasaVitebsk @ Jun 17 2007, 21:54) *
Средний примерный объём ошибокЖ 1-2 на 3к инфы

А попробовать исключить возможное влияние прерываний? - Может, что-то банально портится во время прерывания. У Вас, насколько я помню, система прерываний достаточно требовательная. Может там что накосячили 07.gif Во всяком случае у меня при софтовом мастере и работе с EEPROM сбоев не бывает.
И еще - есть такая особенность, что время записи некоторых микросхем существенно возрастает. Если бит готовности не обрабатывается, а используется банальная задержка "с запасом", может оказаться так, что по мере старения микросхемы этого запаса может не хватать.
Спокойной ночи biggrin.gif
SasaVitebsk
Цитата(zltigo @ Jun 17 2007, 23:38) *
Увы, я софтовой эмуляцией не занимался - работает железный контроллер все на прерываниях, т.е. никакие задержки не формируются - достаточно ACK.


Это-то я понимаю. Я спрашиваю про задержку после записи. Она же по-любому аппаратно не формируется.

2 Dog Pawlowa. Простите о каком бите готовности вы говорите? Я работаю с 24с512.
zltigo
Цитата(SasaVitebsk @ Jun 17 2007, 23:46) *
Это-то я понимаю. Я спрашиваю про задержку после записи. Она же по-любому аппаратно не формируется.

Можно узнать. Cмотрите раздел ACKNOWLEDGE POLLING в мануале - щупается наличие реакции на START+DEVICE ADDRESS.
Практически все очень просто - запрашиваете запись следующего блока без всяких задержек и повторяете запросы пока на запрос не получите ACK. В любом случае с предварительной задержкой или без, получение ACK на START означает завершение цикла записи блока.
SasaVitebsk
Цитата(zltigo @ Jun 18 2007, 00:19) *
Можно узнать. Cмотрите раздел ACKNOWLEDGE POLLING в мануале - щупается наличие реакции на START+DEVICE ADDRESS.
Практически все очень просто - запрашиваете запись следующего блока без всяких задержек и повторяете запросы пока на запрос не получите ACK. В любом случае с предварительной задержкой или без, получение ACK на START означает завершение цикла записи блока.


Так японский городовой, - я ж этого не делаю. Я просто делаю задержку такую же как на байт. 10мс. smile.gif

Похоже в этом и ошибка кроется. А то что при чтении сбои возникают, так похоже просто некоторые ячейки записываются неустойчиво. Сейчас попробовал запись побайтно, а чтение блоками. Вроде полностью работает.

А если нет ответа, то повторяется старт условие без всяких яких? Или надо запрос стопом завершить?
zltigo
Цитата(SasaVitebsk @ Jun 18 2007, 00:55) *
А если нет ответа, то повторяется старт условие без всяких яких?

Да, поскольку девайс в этот момент банально отключен от линии, то наличие/отсутствие стопа ему безразлично.
SasaVitebsk
Цитата(zltigo @ Jun 18 2007, 01:21) *
Да, поскольку девайс в этот момент банально отключен от линии, то наличие/отсутствие стопа ему безразлично.


Какой-то брэд у меня. 05.gif У меня всегда 24с отвечает. Ошибки вроде нет. Буду разбираться завтра. Пока меня устроит запись побайтная. Время некритично, но неприятно. Так как массивы по 60к. Затягивается процесс. smile.gif Но мне пока достаточно работу предъявить. А там только чтение.

Скажи а страницу я обязан полностью записывать (там 128 байт). Насколько я помню там просто копируется вся страница в озу потом модифицируется и записывается. То есть по моим понятиям я могу сколько угодно записать. Работать должна. Или я не прав? Почему может 24с всегда отвечать?
defunct
Цитата(SasaVitebsk @ Jun 18 2007, 02:18) *
Скажи а страницу я обязан полностью записывать (там 128 байт). Насколько я помню там просто копируется вся страница в озу потом модифицируется и записывается. То есть по моим понятиям я могу сколько угодно записать. Работать должна. Или я не прав? Почему может 24с всегда отвечать?

После записи страницы надо ждать 5ms для чипов с маркировкой "A", и 10ms без "A"..

Код
U8 AT24_AttemptWrite( U16 Address, U8 *pData, U8 count)
{
    U8 retval = NACK;
    U8 repcount = 12; // (A package - write op timeout - 5ms, not (A) package - 10ms)

    while (repcount-- && (retval != ACK))
    {
        i2c_MemTransfer(AT24_DevAddress + SLA_W, Address, count, pData);
        retval = i2c_WaitCompleteOperation();
        if (retval) // operation NACK'ed
            Kernel_WaitMS( 1 );
    }
    return retval;
}


Цитата
Сбои возникают как при чтении, так и при записи. Их характер - случайный и хаотический.

Возможно сбои связаны с тем, что у вас не обрабатывается либо неправильно обрабатывается какое-то из состояний шины.
Например, при блочном чтении, очень важно устанавливать NACK перед приемом последнего байта данных.


Цитата
Для этого я ввёл буфер на 32 байта и начал писать/читать блоками по 32 байта.

На меге640 лучше не скупиться на буфер и сделать его размером байт в 200 (про запас) чтобы можно было размещать страницы целиком.
Dog Pawlowa
Цитата(SasaVitebsk @ Jun 18 2007, 02:18) *
...Пока меня устроит запись побайтная. Время некритично, но неприятно...

А драматическое уменьшение ресурса не смущает?
Про бит готовности - это у меня терминология выпала под вечер smile.gif ACK, конечно же.

Еще раз предупреждаю про задержку - дело в том, что для микросхем какого-то производителя очень критично, если повторная запись страницы начинается раньше, чем закончилась предыдущая. Во всяком случае это было лет 6 назад и у меня были серьезные проблемы. Микросхема выходила из строя в течение дня.
zltigo
Цитата(SasaVitebsk @ Jun 18 2007, 02:18) *
Скажи а страницу я обязан полностью записывать (там 128 байт).

Нет, любым кусочком. Я почти всегда пишу не страницами а по 32 байта, дабы не разбираться, какой чип стоит или в некоторых случаях кусками равными размеру записи а не страницы.


Цитата(defunct @ Jun 18 2007, 02:51) *
После записи страницы надо ждать 5ms для чипов с маркировкой "A", и 10ms без "A"..

Уже писал - я не разбираюсь с буковками на чипе и не жду. Банально повторяется посылка START до получения ACK.
Какой-либо задержки не используется в принципе.
Прокладок-задержек между циклами опроса, как в Вашем примере, тоже, поскольку работаю по прерываниям и там автомат самостоятельно непрерывно молотит.
Чипы производители оборудования точно ставят разные и разных производителей.
SasaVitebsk
Цитата(zltigo @ Jun 18 2007, 10:37) *
Нет, любым кусочком. Я почти всегда пишу не страницами а по 32 байта, дабы не разбираться, какой чип стоит или в некоторых случаях кусками равными размеру записи а не страницы.


И я том же. К тому же дальнейшее увеличение размера записываемой страницы практически не даст существенного выигрыша. А память - всегда дефицит. smile.gif

Всем спасибо за участие. Информации мне теперь достаточно. Пока беру таймаут. Выясню причину, - обязательно напишу.
defunct
Цитата(zltigo @ Jun 18 2007, 10:37) *
Какой-либо задержки не используется в принципе.
Прокладок-задержек между циклами опроса, как в Вашем примере, тоже, поскольку работаю по прерываниям и там автомат самостоятельно непрерывно молотит.

в примере нет задержки для системы, там задержка операции записи.
Kernel_WaitMS(x) передает управление другим задачам, на время x.
i2c у меня тоже работает по прерыванию.

Цитата
Уже писал - я не разбираюсь с буковками на чипе и не жду. Банально повторяется посылка START до получения ACK.
Какой-либо задержки не используется в принципе.

Тем самым занимаете i2c шину на тупое ожидание At24.
У меня к примеру на шине несколько устройств, и пока AT24 выполняет запись, шина используется для обмена с другими устройствами.


Цитата
Нет, любым кусочком. Я почти всегда пишу не страницами а по 32 байта, дабы не разбираться, какой чип стоит или в некоторых случаях кусками равными размеру записи а не страницы.

Бесспорно любым кусочком можно писать. Но почему 32 байта? чтобы страница объемом в 128 байт записывалась в 4 раза дольше?
Время записи для AT24, что всей страници сразу, что одного байта - одинаково.
zltigo
Цитата(defunct @ Jun 18 2007, 14:04) *
в примере нет задержки для системы, там задержка операции записи.

Я вижу. Про задержку для системы я не говорил, а задержка для устройства есть.
Цитата
Тем самым занимаете i2c шину на тупое ожидание At24.

При нескольких устойствах, естественно, оптимальная организация может быть иной. Какой, надо думать в каждом конкретном случае.
Цитата
Бесспорно любым кусочком можно писать. Но почему 32 байта? чтобы страница объемом в 128 байт записывалась в 4 раза дольше?

Уже обьяснял - в наиболее частом варианте, дабы не разбираться со страничной организацией конкретного чипа поставленного производителем оборудования (а меньше 32 не встречал), или в зависимости от размера единичной записи, которую надо записать сразу не дожидаясь когда будет дополнение до размера страницы.
SasaVitebsk
Кое что прояснилось. Буду, конечно ещё дальше копать.

Мега48 работает в том числе в качестве часов реального времени. Когда я пытался минимизировать её потребление, то столкнулся с проблемой, что засыпает она не сразу и как бы некоторое время работает хотя питание уже отрублено. Чтобы уменьшить ёмкость кондёра, который позволил бы переключиться на батарейное питание, я практически всегда сплю. Просыпается она по часам, таймеру и I2C. Думаю с этим связаны некоторые сбои. Походу она иногда отвечает не на свой адрес. Почему так происходит я пока не знаю. Но это явно мешает работе 24с. При снижении частоты до 150кГц страничное чтение EEPROM начинает устойчиво работать. Хотя запись - ещё нет. Конечно можно попробовать и дальше снижать частоту шины, дабы добиться устойчивой работы и на записи и на чтении, но меня это не устраивает.

Попробую провести ряд экспериментов чтобы выяснить почему это происходит в принципе. Где собака порылась. Или попробую ввести значительную задержку после старта, чтобы она успела просыпаться и правильно реагировать на адрес. Пока короче не знаю. По описанию, она должна нормально работать с I2C во время сна. Пока я этого не наблюдаю.

Я, конечно несколько схалявил с обработкой I2C слэйва. Все состояния не обрабатывал. Посчитал не нужным. С точки зрения Меги640, - мега48 представляет собой микруху памяти типа 24с01 с левым адресом 0x16/0x17.

Обработчик могу привести - он не большой. Можно было бы посмотреть чужой. Может я что-то не верно сделал. Хотя вроде бы работает.

Да и ещё инфа для размышления. Во время чтения, - обращение к м48 происходит. Во время записи - нет, до завершения записи.
defunct
Цитата(zltigo @ Jun 18 2007, 15:21) *
(а меньше 32 не встречал),


FYI:

Код
    switch(aDevType)
    {
        case AT24C01:
        case AT24C02:
            AT24_PageSize = 8;
            break;
        case AT24C04:
        case AT24C08:
        case AT24C16:
            AT24_PageSize = 16;
            break;
        case AT24C32:
        case AT24C64:
            AT24_PageSize = 32;
            break;
        case AT24C128:
        case AT24C256:
            AT24_PageSize = 64;
            break;
        case AT24C512:
            AT24_PageSize = 128;
            break;
        default:
            retval = NACK;
            AT24_PageSize = 128;
            break;


Цитата
Обработчик могу привести - он не большой. Можно было бы посмотреть чужой. Может я что-то не верно сделал. Хотя вроде бы работает.

Приводите, может что-то заметим...

Цитата
Да и ещё инфа для размышления. Во время чтения, - обращение к м48 происходит. Во время записи - нет, до завершения записи.

Имеется в виду ложное обращение (всмысле ложное срабатывание m48)?
SasaVitebsk
Код

//Инициализация порта TWI
void TWI_Init(void)
{
  TWI_DDR &= ~(1<<SDA);                                    // SDA на ввод
  TWI_PORT |= (1<<SDA);                                    // подпереть
  TWI_DDR &= ~(1<<SCL);                                    // SCL на ввод
  TWI_PORT |= (1<<SCL);                                    // подпереть
  TWCR=TWI_OK;                                            // Режим Slave
}


Код
#pragma    vector=TWI_vect                                    // I2C
__interrupt    static void    i2c(void)
{
uint8_t    static  AdrStatus;                            // Смещение внутри структуры

switch(TWSR & 0xF8){
  case TWI_ADDR_W:                                        // Приняли свой адрес
    Flag.ErrIIC=0;
    Flag.AdrIIC=1;
    break;
  case TWI_DATA_W:                                        // Читаем Адрес структуры или саму структуру (Установка времени)
    if(Flag.AdrIIC){                                    // Читаем Адрес структуры
      Flag.AdrIIC=0;                                    // Сбросили признак
      AdrStatus=TWDR & 0x1f;                            // установить смещение
    }
    else{                                                // Читаем саму структуру (Установка времени)
      if(AdrStatus>13){
        AdrStatus=0;                                    // Игнорировать ошибки
        break;                                            // Недопустить запись в область ячеек памяти
      }
      *(&Status.Year+AdrStatus++)=TWDR;                    // Записать и перейти на следующий
      Flag.SetDay=1;                                    // Был установлен день
    }
    break;
  case TWI_WP:                                            // Стоп или повторный старт
  case TWI_STOP:                                        // Стоп
  case TWI_A_STOP:                                        // Стоп
    if(Flag.SetDay){                                    // Если было установлено время, то
       LastDay=LastDayOfMonth[Status.Month];            // Определим последний день месяца
       Flag.SetDay=0;                                    // Сбросить признак
    }
    break;
  case TWI_ADDR_R:                                        // Читаем
  case TWI_DATA_R:                                        // Читаем
    TWDR= *(&Status.Year+AdrStatus++);                    // Прочитать и перейти на следующий
    if(AdrStatus>13)AdrStatus=0;                        // Игнорировать ошибки
    break;
  default: Flag.ErrIIC=1;                                // Иначе ошибка
}
TWCR=TWI_OK;                                            // Подтвердить приём
}


Код
//==== I2C =====
  TWAR=0x16;                                            // Адрес Slave = 16/17


Код
#define FCLK            8000000                    // Частота контроллера
#define TCLK            125                        // Частота контроллера в нс

#define VERSIJA            0x18                    // Версия ПО 1.8

#define INT0            2                        // Нога INT0
#define INT0_PIN        PIND                    // Порт INT0

//========================================
//======== TWI ===========
#define TWI_ADDR_W        0x60                    // Передача "Адрес + W"
#define TWI_DATA_W        0x80                    // Передача "Записать данные"
#define TWI_WP            0xa0                    // Передача "Записать данные и стоп"

#define TWI_ADDR_R        0xa8                    // Передача "Адрес + R"
#define TWI_DATA_R        0xb8                    // Передача "Читать данные"
#define TWI_STOP        0xc0                    // Передача "Читать стоп"
#define TWI_A_STOP        0xc8                    // Передача "Читать стоп"

#define TWI_OK            0xc5                    // Подтверждение приёма

#define SDA                0x4                        // Линия порта SDA
#define SCL                0x5                        // Линия порта SCL
#define TWI_PORT        PORTC                    // Порт I2C
#define TWI_DDR            DDRC                    // Порт I2C

#define PWR_BAT            0x1                        // Включение батарейного питания
#define BAT_PORT        PORTC                    // Порт включения батарейного питания
#define    PWR_BAT_ON        BAT_PORT |=    (1<<PWR_BAT)// Подключить батарейку
#define    PWR_BAT_OFF        BAT_PORT &= ~(1<<PWR_BAT)// Выключить батарейку
defunct
Цитата(SasaVitebsk @ Jun 19 2007, 01:42) *
default: Flag.ErrIIC=1;

На первый взгляд никакого криминала нет.

По дефолту попробуйте сделать переинициализацию шины
TWCR = (1 << TWIE); // twen - 0
TWDR = 0;
TWAR = SLAVE_ADDRESS;
TWCR = (1 << TWEN) | (1 << TWIE) | (1 << TWINT) | (1 << TWEA);

(и конечно же под отладкой поставить точку останова на default case и посмотреть когда туда попадает)
singlskv
1. нужно обязательно добавить обработку состояния Bus Error ((TWSR & 0xF8)==0x00)
там обработка отличается
TWCR=(1<<TWINT)|(1<<TWSTO)|(1<<TWEA)|(1<<TWEN);

2. попробуйте вместо:
TWCR=TWI_OK; // Подтвердить приём

написать так:
TWCR;
TWCR=TWI_OK;

может быть поможет (это не шутка!)
mrcashe
Кстати говоря, на такой шине при поллинге надо обязательно выдавать стоп-условие вне зависимости от того, есть ACK или нет. Устройств-то несколько! И не нужно заморачивать себе голову всеми этими задержками, так как они плывут по температуре и от возраста, а использовать только поллинг и в побайтовом случае, и в блочном. По сути дела, побайтовая запись - это ни что иное, как запись блока размером 1 байт, которая всё равно приводит к перезаписи страницы целиком.
О пуллапах. На 1 МГц 10к вполне достаточно, всю жизнь ставлю и всё ОК (тьфу-тьфу...).
SasaVitebsk
Цитата(mrcashe @ Jun 19 2007, 07:54) *
Кстати говоря, на такой шине при поллинге надо обязательно выдавать стоп-условие вне зависимости от того, есть ACK или нет. Устройств-то несколько! И не нужно заморачивать себе голову всеми этими задержками, так как они плывут по температуре и от возраста, а использовать только поллинг и в побайтовом случае, и в блочном. По сути дела, побайтовая запись - это ни что иное, как запись блока размером 1 байт, которая всё равно приводит к перезаписи страницы целиком.
О пуллапах. На 1 МГц 10к вполне достаточно, всю жизнь ставлю и всё ОК (тьфу-тьфу...).

Я сразу поставил стоп-условие. Хотябы для того, чтобы линии возвращались в исходное.
Проблема в том, что я не вижу случаев "неответа" при записи. Она всегда отвечает ASK. Точнее кто-то отвечает. Сегодня буду рэзать и выяснят.

2 defunct спасибо попробую. Надо бы два компа и два JTAG ICE MK2. smile.gif

2 singlskv - первое попробую, а второе IAR выбросит. Напишет оператор не имеет смысла. При любой оптимизации. Да и я бы, по честному выбросил. Прости, но я в шаманство не верю. Предпочитаю причину найти.
singlskv
Цитата(SasaVitebsk @ Jun 19 2007, 12:19) *
2 singlskv - первое попробую, а второе IAR выбросит.

не выбросит, не имеет таких правов smile.gif
при описании регистров там везде понатыкано volatile
а это просто чтение регистра перед тем как его записать
Цитата
Прости, но я в шаманство не верю. Предпочитаю причину найти.

Я тоже долго не верил, пока в ходе длительных боев с i2c не убедился
в этом сам.
На самом деле это нужно делать только при одном состоянии на шине
и только при определенных условиях.

Да, кстати, пример работы с i2c по прерываниям есть в avrlib.
SasaVitebsk
Всем спасибо за участие. В любом случае я узнал новые для себя вещи (в плане 24с). И переработал программу. Работает намного быстрее, естественно.

Если кого интересует, то хомут найден. Хомут забавный. У меня подряд шли два буфера (IAR разместил). Приёмный буфер 485 и I2C. Буфер I2C общий на запись и чтение, так как данные операции не идут совместно. Буфер 485 достаточно сложный я делаю по привычке. Размер более двух размеров пакетов. Подкачка начинается задолго до полного опустошения буфера (так как надо успеть принять пакет целиком и сверить КС до полного опустошения буфера). Естественно он не инициализируется. Ну и указатели я тоже не инициализирую а выравниваю. Таким образом закачка продолжается с того места на котором остановилась предыдущая.
При написании я хомутнул и задействовал на 1 байт больше размера вх буфера (при переходе по кольцу). В результате пока я пишу побайтно (то есть буфер I2C не использую) то всё замечательно, а как только начинаю использовать, то происходят единичные сбои в момент перехода по кольцу и одновременной записи в EEPROM. В связи с описанными выше особенностями, сбои проявлялись достаточно хаотично. В разных местах и в разное время. smile.gif

Кстати раз уж зашёл разговор об этом. Подскажите спецы кто как работает в Си. Можно работать с массивами и указателями. Что эффективней?

А то у меня кое где массивы, а кое где указатели. Смотрю IAR достаточно эффективно компилит, но всё равно думается если индекс массива более 1 байта (в смысле менее разрядности процессора), то наверное всётаки лучше с указателями работать. Кто выскажется по данному вопросу?
defunct
Цитата(SasaVitebsk @ Jun 30 2007, 03:37) *
А то у меня кое где массивы, а кое где указатели. Смотрю IAR достаточно эффективно компилит, но всё равно думается если индекс массива более 1 байта (в смысле менее разрядности процессора), то наверное всётаки лучше с указателями работать. Кто выскажется по данному вопросу?

Что удобнее - то и используйте.
Как по мне, для кольцевых буферов с байтовым доступом удобнее работать с индексами. Код получается более естественный (при проходе через 0), текущий размер свободного места можно определить формулой (без доп переменных).
Для списковых, пакетных - с указателями.
Dog Pawlowa
Цитата(SasaVitebsk @ Jun 30 2007, 03:37) *
А то у меня кое где массивы, а кое где указатели. Смотрю IAR достаточно эффективно компилит, но всё равно думается если индекс массива более 1 байта (в смысле менее разрядности процессора), то наверное всётаки лучше с указателями работать. Кто выскажется по данному вопросу?

При разборе с указателями букав меньше smile.gif
Но использую и то, и другое.
Кстати или не кстати - при использовании протоколов запрос-ответ стараюсь использовать линейные буфера вместо циклических - так проще прописать автоматы приема-передачи.
sensor_ua
Цитата
Можно работать с массивами и указателями. Что эффективней?

Массив имеет длину и её можно узнать.
Указателю на начало масива (имени массива) нельзя присваивать значения (соответственно тяжело потерятьwink.gif), а по сути работа с ним идёт как с обычным указателем и смещением.
Т.е. эквивалентно a[i] и *(a+i) и i[a]
Хотя и бывают некоторые ограничения - так размер массива в ИАРе для АВР раньше (не смотрел что там сейчас), соответственно допустимый диапазон индексов, был ограничен длиной не более, чем __SIGNED_INT_MAX__ - вероятно дабы не загружать моск компилеру (что, ИМХО, вполне оправданно), но с указателем можно было работать арифметикой до __UNSIGNED_INT_MAX__, а может и больше (для __flash), но не проверял и не вчитывался в доку глубжеwink.gif
С указателем можно работать как с массивом
char array[]="Preved!";
char * ptr = &array[1];
char x;
x = ptr[4] ; //x = *(ptr+4); или x = 'd';
mrcashe
Цитата
Подскажите спецы кто как работает в Си. Можно работать с массивами и указателями. Что эффективней?

Я стараюсь работать только с указателями. При программировании для МК это несколько экономит ресурсы. Допустим, есть некая структура:
Код
typedef struct { int id; void * p; } some_struct_t;


и есть некая константа, задающая размер буфера (читай: массива):
Код
enum { some_buffer_size = 20 };


Разместим сам буфер:
Код
some_struct_t some_buffer[some_buffer_size];


Теперь вариант перебора с применением индекса:
Код
int i;
for (i = 0; i < some_buffer_size; ++i) {
        printf("%i %p\n", some_buffer[i].id, some_buffer[i].p);
}


Перебор с применением указателя:
Код
some_struct_t * p;
for (p = some_buffer; p < some_buffer+some_buffer_size; ++p) {
        printf("%i %p\n", p->id, p->p);
}


Как видим, в первом случае индексирование выполняется дважды за цикл, т.е. всего 40 раз! А что есть индексирование? Это умножение(!) индекса на размер элемента массива и суммирование его с указателем на массив. Конечно, в случае массива символов размер элемента массива == 1, так что можно просто прибавлять индекс к адресу массива, но в случае массивов с размером элементов в 5 байт придётся именно умножать.
Во втором же случае размер элемента массива просто прибавляется к текущему значению указателя, что может быть на порядок (а то и 2 порядка) эффективнее.
С другой стороны, если не требуется итерация по всему буферу, а нужен именно произвольный доступ к элементу с определённым индексом, то можно с одинаковым успехом воспользоваться обоими методами, как и показал sensor_ua.

Цитата
Массив имеет длину и её можно узнать.

Это что-то новое. Размер массива в Си, вообще говоря, невозможно узнать динамически. Соответственно, код, сгенерированный компилятором, не имеет возможности детектировать выход за пределы массива. Если Вы имеете ввиду sizeof() , то он возвращает размер объекта в байтах, что обычно не то, что нужно в повседневной жизни. Более того, полагаться на этот оператор просто опасно. В различных компиляторах он может выдавать различные значения благодаря различному выравниванию элементов. Если массив размещается статически, то всегда заводите константу, содержащую его размер и пользуйтесь только ею для задания и определения размера массива. Если массив размещается динамически, то определите переменную (а ещё лучше - функцию) для определения его размера. Для изменения размера определите соотвествующую функцию.
sensor_ua
Цитата
Это что-то новое. Размер массива в Си, вообще говоря, невозможно узнать динамически. Соответственно, код, сгенерированный компилятором, не имеет возможности детектировать выход за пределы массива. Если Вы имеете ввиду sizeof() , то он возвращает размер объекта в байтах, что обычно не то, что нужно в повседневной жизни. Более того, полагаться на этот оператор просто опасно. В различных компиляторах он может выдавать различные значения благодаря различному выравниванию элементов. Если массив размещается статически, то всегда заводите константу, содержащую его размер и пользуйтесь только ею для задания и определения размера массива. Если массив размещается динамически, то определите переменную (а ещё лучше - функцию) для определения его размера. Для изменения размера определите соотвествующую функцию.

Это относится к категории вредных советов. Действительно sizeof - оператор, вычисляемый во время компиляции. Действительно может давать значение с учётом утечек памяти при выравнивании. Нормальные компиляторы позволяют указывать явно что и как выравнивать. Во время компиляции он превращается в целую константу, значение которой равно размеру типа или объекта (в байтах). Ещё - в C89 и C++ действительно не поддерживаются массивы переменной длины, но в С99 всвязи с введением массивов переменной длины применение sizeof к таковым приводит в к тому, что значение sizeof получает во время выполнения. Что касается контроля выхода за пределы - тут без наличия этих величин пределов в Си нечего делать. Что касается "нужного в повседневной жизни", то, как понимаю имеется в виду sizeof(array)/sizeof(array[0]) - ничего сдесь нет сложного - классический пример.
defunct
Цитата(mrcashe @ Jul 1 2007, 11:35) *
В различных компиляторах он может выдавать различные значения благодаря различному выравниванию элементов. Если массив размещается статически, то всегда заводите константу, содержащую его размер и пользуйтесь только ею для задания и определения размера массива.


Как уже отметил sensor_ua, не надо заводить никаких констант.
Гораздо безопаснее применять макрос
#define COUNT( arr ) ( sizeof( arr ) / sizeof( (arr)[0] ) )


Цитата
Как видим, в первом случае индексирование выполняется дважды за цикл, т.е. всего 40 раз!

для процессоров таких как AVR, компилятор соптимизирует операции индексирования. (добавит неявный указатель на структуру)

Для процессоров с индексной адресацией, абсолютно не важно сколько раз происходит индексирование:

MOV eax, [ebx + esi * x + offset]
zltigo
Цитата(defunct @ Jul 1 2007, 16:09) *
Для процессоров с индексной адресацией, абсолютно не важно сколько раз происходит индексирование:
MOV eax, [ebx + esi * x + offset]

Справедливости ради smile.gif x может быть только степеню двойки sad.gif, ну и такты кушает такая адресация.
Ну а с оптимизацией, действительно дело обстоит в большинстве случаев действительно хорошо.
SasaVitebsk
Спасибо.
Доступно, внятно и чётко. Короче похоже это тот вопрос, по которому все уже определились. smile.gif
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.