|
|
  |
Помогите советом. I2C, Мож кто сталкивался. |
|
|
|
Jun 18 2007, 11:04
|

кекс
     
Группа: Свой
Сообщений: 3 825
Регистрация: 17-12-05
Из: Киев
Пользователь №: 12 326

|
Цитата(zltigo @ Jun 18 2007, 10:37)  Какой-либо задержки не используется в принципе. Прокладок-задержек между циклами опроса, как в Вашем примере, тоже, поскольку работаю по прерываниям и там автомат самостоятельно непрерывно молотит. в примере нет задержки для системы, там задержка операции записи. Kernel_WaitMS(x) передает управление другим задачам, на время x. i2c у меня тоже работает по прерыванию. Цитата Уже писал - я не разбираюсь с буковками на чипе и не жду. Банально повторяется посылка START до получения ACK. Какой-либо задержки не используется в принципе. Тем самым занимаете i2c шину на тупое ожидание At24. У меня к примеру на шине несколько устройств, и пока AT24 выполняет запись, шина используется для обмена с другими устройствами. Цитата Нет, любым кусочком. Я почти всегда пишу не страницами а по 32 байта, дабы не разбираться, какой чип стоит или в некоторых случаях кусками равными размеру записи а не страницы. Бесспорно любым кусочком можно писать. Но почему 32 байта? чтобы страница объемом в 128 байт записывалась в 4 раза дольше? Время записи для AT24, что всей страници сразу, что одного байта - одинаково.
|
|
|
|
|
Jun 18 2007, 12:21
|

Гуру
     
Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244

|
Цитата(defunct @ Jun 18 2007, 14:04)  в примере нет задержки для системы, там задержка операции записи. Я вижу. Про задержку для системы я не говорил, а задержка для устройства есть. Цитата Тем самым занимаете i2c шину на тупое ожидание At24. При нескольких устойствах, естественно, оптимальная организация может быть иной. Какой, надо думать в каждом конкретном случае. Цитата Бесспорно любым кусочком можно писать. Но почему 32 байта? чтобы страница объемом в 128 байт записывалась в 4 раза дольше? Уже обьяснял - в наиболее частом варианте, дабы не разбираться со страничной организацией конкретного чипа поставленного производителем оборудования (а меньше 32 не встречал), или в зависимости от размера единичной записи, которую надо записать сразу не дожидаясь когда будет дополнение до размера страницы.
--------------------
Feci, quod potui, faciant meliora potentes
|
|
|
|
|
Jun 18 2007, 21:35
|
Гуру
     
Группа: Свой
Сообщений: 2 712
Регистрация: 28-11-05
Из: Беларусь, Витебск, Строителей 18-4-220
Пользователь №: 11 521

|
Кое что прояснилось. Буду, конечно ещё дальше копать.
Мега48 работает в том числе в качестве часов реального времени. Когда я пытался минимизировать её потребление, то столкнулся с проблемой, что засыпает она не сразу и как бы некоторое время работает хотя питание уже отрублено. Чтобы уменьшить ёмкость кондёра, который позволил бы переключиться на батарейное питание, я практически всегда сплю. Просыпается она по часам, таймеру и I2C. Думаю с этим связаны некоторые сбои. Походу она иногда отвечает не на свой адрес. Почему так происходит я пока не знаю. Но это явно мешает работе 24с. При снижении частоты до 150кГц страничное чтение EEPROM начинает устойчиво работать. Хотя запись - ещё нет. Конечно можно попробовать и дальше снижать частоту шины, дабы добиться устойчивой работы и на записи и на чтении, но меня это не устраивает.
Попробую провести ряд экспериментов чтобы выяснить почему это происходит в принципе. Где собака порылась. Или попробую ввести значительную задержку после старта, чтобы она успела просыпаться и правильно реагировать на адрес. Пока короче не знаю. По описанию, она должна нормально работать с I2C во время сна. Пока я этого не наблюдаю.
Я, конечно несколько схалявил с обработкой I2C слэйва. Все состояния не обрабатывал. Посчитал не нужным. С точки зрения Меги640, - мега48 представляет собой микруху памяти типа 24с01 с левым адресом 0x16/0x17.
Обработчик могу привести - он не большой. Можно было бы посмотреть чужой. Может я что-то не верно сделал. Хотя вроде бы работает.
Да и ещё инфа для размышления. Во время чтения, - обращение к м48 происходит. Во время записи - нет, до завершения записи.
|
|
|
|
|
Jun 18 2007, 22:06
|

кекс
     
Группа: Свой
Сообщений: 3 825
Регистрация: 17-12-05
Из: Киев
Пользователь №: 12 326

|
Цитата(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)?
|
|
|
|
|
Jun 18 2007, 22:42
|
Гуру
     
Группа: Свой
Сообщений: 2 712
Регистрация: 28-11-05
Из: Беларусь, Витебск, Строителей 18-4-220
Пользователь №: 11 521

|
Код //Инициализация порта 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)// Выключить батарейку
|
|
|
|
|
Jun 18 2007, 23:37
|

кекс
     
Группа: Свой
Сообщений: 3 825
Регистрация: 17-12-05
Из: Киев
Пользователь №: 12 326

|
Цитата(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 и посмотреть когда туда попадает)
|
|
|
|
|
Jun 19 2007, 04:54
|
Участник

Группа: Участник
Сообщений: 17
Регистрация: 21-07-06
Из: Владивосток
Пользователь №: 18 987

|
Кстати говоря, на такой шине при поллинге надо обязательно выдавать стоп-условие вне зависимости от того, есть ACK или нет. Устройств-то несколько! И не нужно заморачивать себе голову всеми этими задержками, так как они плывут по температуре и от возраста, а использовать только поллинг и в побайтовом случае, и в блочном. По сути дела, побайтовая запись - это ни что иное, как запись блока размером 1 байт, которая всё равно приводит к перезаписи страницы целиком. О пуллапах. На 1 МГц 10к вполне достаточно, всю жизнь ставлю и всё ОК (тьфу-тьфу...).
|
|
|
|
|
Jun 19 2007, 08:19
|
Гуру
     
Группа: Свой
Сообщений: 2 712
Регистрация: 28-11-05
Из: Беларусь, Витебск, Строителей 18-4-220
Пользователь №: 11 521

|
Цитата(mrcashe @ Jun 19 2007, 07:54)  Кстати говоря, на такой шине при поллинге надо обязательно выдавать стоп-условие вне зависимости от того, есть ACK или нет. Устройств-то несколько! И не нужно заморачивать себе голову всеми этими задержками, так как они плывут по температуре и от возраста, а использовать только поллинг и в побайтовом случае, и в блочном. По сути дела, побайтовая запись - это ни что иное, как запись блока размером 1 байт, которая всё равно приводит к перезаписи страницы целиком. О пуллапах. На 1 МГц 10к вполне достаточно, всю жизнь ставлю и всё ОК (тьфу-тьфу...). Я сразу поставил стоп-условие. Хотябы для того, чтобы линии возвращались в исходное. Проблема в том, что я не вижу случаев "неответа" при записи. Она всегда отвечает ASK. Точнее кто-то отвечает. Сегодня буду рэзать и выяснят. 2 defunct спасибо попробую. Надо бы два компа и два JTAG ICE MK2.  2 singlskv - первое попробую, а второе IAR выбросит. Напишет оператор не имеет смысла. При любой оптимизации. Да и я бы, по честному выбросил. Прости, но я в шаманство не верю. Предпочитаю причину найти.
|
|
|
|
|
Jun 19 2007, 08:41
|
дятел
    
Группа: Свой
Сообщений: 1 681
Регистрация: 13-05-06
Из: Питер
Пользователь №: 17 065

|
Цитата(SasaVitebsk @ Jun 19 2007, 12:19)  2 singlskv - первое попробую, а второе IAR выбросит. не выбросит, не имеет таких правов  при описании регистров там везде понатыкано volatile а это просто чтение регистра перед тем как его записать Цитата Прости, но я в шаманство не верю. Предпочитаю причину найти. Я тоже долго не верил, пока в ходе длительных боев с i2c не убедился в этом сам. На самом деле это нужно делать только при одном состоянии на шине и только при определенных условиях. Да, кстати, пример работы с i2c по прерываниям есть в avrlib.
|
|
|
|
|
Jun 30 2007, 00:37
|
Гуру
     
Группа: Свой
Сообщений: 2 712
Регистрация: 28-11-05
Из: Беларусь, Витебск, Строителей 18-4-220
Пользователь №: 11 521

|
Всем спасибо за участие. В любом случае я узнал новые для себя вещи (в плане 24с). И переработал программу. Работает намного быстрее, естественно. Если кого интересует, то хомут найден. Хомут забавный. У меня подряд шли два буфера (IAR разместил). Приёмный буфер 485 и I2C. Буфер I2C общий на запись и чтение, так как данные операции не идут совместно. Буфер 485 достаточно сложный я делаю по привычке. Размер более двух размеров пакетов. Подкачка начинается задолго до полного опустошения буфера (так как надо успеть принять пакет целиком и сверить КС до полного опустошения буфера). Естественно он не инициализируется. Ну и указатели я тоже не инициализирую а выравниваю. Таким образом закачка продолжается с того места на котором остановилась предыдущая. При написании я хомутнул и задействовал на 1 байт больше размера вх буфера (при переходе по кольцу). В результате пока я пишу побайтно (то есть буфер I2C не использую) то всё замечательно, а как только начинаю использовать, то происходят единичные сбои в момент перехода по кольцу и одновременной записи в EEPROM. В связи с описанными выше особенностями, сбои проявлялись достаточно хаотично. В разных местах и в разное время.  Кстати раз уж зашёл разговор об этом. Подскажите спецы кто как работает в Си. Можно работать с массивами и указателями. Что эффективней? А то у меня кое где массивы, а кое где указатели. Смотрю IAR достаточно эффективно компилит, но всё равно думается если индекс массива более 1 байта (в смысле менее разрядности процессора), то наверное всётаки лучше с указателями работать. Кто выскажется по данному вопросу?
|
|
|
|
|
Jun 30 2007, 04:15
|
Гуру
     
Группа: Свой
Сообщений: 2 702
Регистрация: 14-07-06
Пользователь №: 18 823

|
Цитата(SasaVitebsk @ Jun 30 2007, 03:37)  А то у меня кое где массивы, а кое где указатели. Смотрю IAR достаточно эффективно компилит, но всё равно думается если индекс массива более 1 байта (в смысле менее разрядности процессора), то наверное всётаки лучше с указателями работать. Кто выскажется по данному вопросу? При разборе с указателями букав меньше  Но использую и то, и другое. Кстати или не кстати - при использовании протоколов запрос-ответ стараюсь использовать линейные буфера вместо циклических - так проще прописать автоматы приема-передачи.
--------------------
Уходя, оставьте свет...
|
|
|
|
|
Jul 1 2007, 06:26
|
Профессионал
    
Группа: Свой
Сообщений: 1 266
Регистрация: 22-04-05
Из: Киев
Пользователь №: 4 387

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