roboforum.ru

Технический форум по робототехнике.

Проблемы с аппаратным I2C на AVR ATmega32

В разделе рассматриваются вопросы информационного обмена в робототехнике.
Аппаратный уровень, протоколы.

Re: Проблемы с аппаратным I2C на AVR ATmega32

Сообщение dccharacter » 19 июн 2011, 14:05

нет нет и нет - все вообще не так

Логика работы такая:
1. Мастер открывает соединение со слейвом на запись, и посылает пакетом, например, пять байт.
2. Слейв их получает. Вопрос - куда их слейв пишет? Да куда угодно. Например, первый байт - это адрес слова, потом четыре байта пишутся в адреса: (адрес_слова), (адрес_слова+1)...(адрес_слова+3). Или, первые байт - адрес слова, потом значение, потом адрес другого слова, потом значение и т.д. Вся логика того, как работать с принятым пакетом - исключительно на стороне слейва отрабатывает! Но для того, чтобы правильно записать соответствующие байты в слейва, мастер должен знать логику работы слейва и правильно формировать посылку.

1б. Теперь мастер открывает соединение на чтение. Слейв будет отсылать байты мастеру, пока тот не скажет, что ему достаточно. Вопрос - какие байты будет отсылать слейв? Опять же, вся логика на стороне слейва, мастер только должен знать, что именно отсылает слейв.

Простейший случай - у нас есть контрольный регистр у слейва из трех байт. Соответственно надо реализовать две функции - записи и чтения контрольного регистра.
Первая имеет вид: [s][addr/w][byte1][byte2][byte3][p]. При получении такого запроса слейв пишет первый байт в control_reg[1], второй в control_reg[2] и т.д.
На чтение: [s][addr/r][byte1/ack][byte2/ack][byte3/nack][p]. При получении такого запроса слейв начинает пихать в канал байты control_reg[pointer_to_word++], пока не получит nack от мастера, после этого указатель на байт ресеттится.

Я рекомендую такой алгоритм отладки:
1. Пишем 16 байт в слейва. Слейв каждый полученный байт кидает в отладочную консоль. Сравниваем. убеждаемся, что на стороне слейва все правильно приняли. Можно еще отдельно потом вывести весь массив байт, чтобы убедиться, что все, что мы приняли, мы правильно сохранили в массив.
2. При запросе на чтение отдаем один и тот же байт, какой-нить красивый, типа AE, или 6B. Убеждаемся, что мастер получил 16-ть байт AE.
3. При запросе на чтение отдаем байт byte++, убеждаемся, что мастер получил массив увеличивающихся байт, типа {0, 1, 3, 4, ..., F}
4. При запросе на чтение отдаем значения байт, расположенных в памяти по увеличивающемуся указателю - проверям...

"как на еепроме" стоит реализовывать логику только в случае, если нужно писать/читать индивидуальные байты.

Вот на всякий случай мой код от ПИКа, в нем можно разобраться (первый байт при записи - адрес слова, остальное - значения):
Код: Выделить всёРазвернуть
if (SSP1IF && SSP1IE)
    {
        unsigned char SSPSTAT_TEMP = SSP1STAT & 0b00101101;
        unsigned char tempBuf;
        if (SSPSTAT_TEMP == 0b00001001)
            //STATE 1: MASTER WRITE, LAST BYTE WAS AN ADDRESS
        {
            tempBuf = SSPBUF;
            i2c_set_register = 1;
        }
        else if (SSPSTAT_TEMP == 0b00101001)
            //STATE 2: MASTER WRITE, LAST BYTE WAS DATA
        {
            if (i2c_set_register)
            {
                do i2c_register = SSPBUF; while (SSP1STATbits.BF);
                if (i2c_register >= sizeof(CONTROL_REG))
                    i2c_register = 0x00;
                i2c_set_register = 0;
            } else
            {
                CONTROL_REG[i2c_register++] = SSPBUF;
            }
        }
        else if (SSPSTAT_TEMP == 0b00001101)
            //STATE 3: MASTER READ, LAST BYTE WAS AN ADDRESS
        {
            SSP1IF = 0;
            tempBuf = SSPBUF;
            while (SSP1STATbits.BF) continue;
            do {
                SSP1CON1bits.WCOL = 0;
                SSPBUF = CONTROL_REG[i2c_register++];
            } while (SSP1CON1bits.WCOL);
            SSP1CON1bits.CKP = 1;
        }
        else if (SSPSTAT_TEMP == 0b00101100)
            //STATE 4: MASTER READ, LAST BYTE WAS DATA
        {
            while (SSP1STATbits.BF) continue;
            do {
                SSP1CON1bits.WCOL = 0;
                SSPBUF = CONTROL_REG[i2c_register++];
            } while (SSP1CON1bits.WCOL);
            SSP1CON1bits.CKP = 1;
        }
        else if ((SSPSTAT_TEMP == 00101000) && SSP1CON1bits.CKP)
            //STATE 5: MASTER NACK
        {
            //SSP1CON1bits.CKP = 1;
            i2c_register = 0x00;
        }
        else
        {
            //i2c error
            SSP1CON1bits.SSPEN = 0;
            SSP1CON1bits.SSPEN = 1;
        }
        SSP1IF = 0;
        SSP1CON1bits.CKP = 1;
    }
Мой волшебник это я сам. Всю архитектуру программы придумал лично, а ребята помогли воплотить её. Я бы и сам мог написать, но лень учить язык и его конструкции.
Аватара пользователя
dccharacter
 
Сообщения: 4995
Зарегистрирован: 10 дек 2010, 13:16
Откуда: Красногорск МО
прог. языки: C, Python, wiring/processing
ФИО: Андрей

Re: Проблемы с аппаратным I2C на AVR ATmega32

Сообщение HarryStar » 20 июн 2011, 00:20

Это я понимаю, что логика обмена между моими МК определяется только моим воспаленным мозгом.
Проблема у меня именно в негарантированном приеме.
Вчера посидел до 4 утра, разобрался, выпрямил немного руки. Теперь ПОЧТИ нормально.
В чем это выражается:
- Запускаем слейв. Он ждет посылки от мастера.
- Запускаем мастер. он посылает 16 байт (16 посылок по 3 байта, первые 2 адрес, 3й - байт)
- Дальше проблемы. На слейве иногда первые 1-2 байта пропускаются.
Т.о. для гарантированной передачи приходится первые 2 байта перепосылать 2 раза, а остальные по 1 уже. Тогда все совпадает с переданным.

Т.о. для гарантированной передачи склоняюсь к 2м методам защиты:
1) Передача master -> slave пачками по 15 байт + 1 байт контрольная сумма.
2) после того как слейв принимает 16 байт, он ждет запроса на чтение и возвращает 1 байт crc8. Соотв. если мастер принимает неправильную crc, он перепосылает 16 байт еще раз.
Как только crc совпадает мастер посылает следующий блок.

Логика работы ЕЕПРОМа мне не подходит, я ее от безысходности уже пробовал.
Мне нужно передавать команды длиной 12-14 байт и иногда длинные строки средней длиной в 20-50 байт. Читать контрольную сумму последней передачи и статус.

Вообще в этих апноутах столько ошибок ... точнее недоработок или условностей, которые приходится долго отлавливать.

Проблема еще в том, что слейв как только получит команду от мастера он уходит в себя и занят на несколько секунд. Потом освобождается и опять ждет подачек от мастера. Это тоже вносит проблемы в процесс обмена.
Аватара пользователя
HarryStar
 
Сообщения: 995
Зарегистрирован: 15 ноя 2010, 13:56
Откуда: Нижний Новгород
прог. языки: С, С++, РНР

Re: Проблемы с аппаратным I2C на AVR ATmega32

Сообщение dccharacter » 20 июн 2011, 01:04

(16 посылок по 3 байта, первые 2 адрес, 3й - байт) <- ЗАЧЕМ?

почему нельзя 18 байт - два байта адреса и шестнадцать - данных?
Мой волшебник это я сам. Всю архитектуру программы придумал лично, а ребята помогли воплотить её. Я бы и сам мог написать, но лень учить язык и его конструкции.
Аватара пользователя
dccharacter
 
Сообщения: 4995
Зарегистрирован: 10 дек 2010, 13:16
Откуда: Красногорск МО
прог. языки: C, Python, wiring/processing
ФИО: Андрей

Re: Проблемы с аппаратным I2C на AVR ATmega32

Сообщение HarryStar » 20 июн 2011, 01:16

Это на данный момент так. Я по разному пробовал. Из тех что перебрал, пока это самый надежный.
Буду реализовывать то, что описал - просто 16 байт одним куском, где 15 - данные, 1 - crc и ответное подтверждение.
Аватара пользователя
HarryStar
 
Сообщения: 995
Зарегистрирован: 15 ноя 2010, 13:56
Откуда: Нижний Новгород
прог. языки: С, С++, РНР

Re: Проблемы с аппаратным I2C на AVR ATmega32

Сообщение HarryStar » 23 июн 2011, 11:55


Вот видео, демонстрирующее данные грабли.
Голос мой правда тиховат получился.
Сначала я пробую простую прогу на обычном LCD, показываю, что она всегда работает одинаково корректно, а потом подключаю OLED. При первом запуске все ок, а дальше после каждого резета МК - новые эффекты. Если нажать на резет раз 20-30 можно опять попасть на нормальное состояние.
Аватара пользователя
HarryStar
 
Сообщения: 995
Зарегистрирован: 15 ноя 2010, 13:56
Откуда: Нижний Новгород
прог. языки: С, С++, РНР

Re: Проблемы с аппаратным I2C на AVR ATmega32

Сообщение =DeaD= » 23 июн 2011, 11:56

Может OLED надо как-то инициализировать?
Проект [[Open Robotics]] - Универсальные модули для построения роботов
Аватара пользователя
=DeaD=
 
Сообщения: 24218
Зарегистрирован: 06 окт 2004, 18:01
Откуда: Ебург
прог. языки: C++ / PHP / 1C
ФИО: Антон Ботов

Re: Проблемы с аппаратным I2C на AVR ATmega32

Сообщение dccharacter » 23 июн 2011, 12:39

=DeaD= писал(а):Может OLED надо как-то инициализировать?

Похож.
Мой волшебник это я сам. Всю архитектуру программы придумал лично, а ребята помогли воплотить её. Я бы и сам мог написать, но лень учить язык и его конструкции.
Аватара пользователя
dccharacter
 
Сообщения: 4995
Зарегистрирован: 10 дек 2010, 13:16
Откуда: Красногорск МО
прог. языки: C, Python, wiring/processing
ФИО: Андрей

Re: Проблемы с аппаратным I2C на AVR ATmega32

Сообщение =DeaD= » 23 июн 2011, 12:45

Причем при включении питания он сам стартует правильно, а вот когда МК сбросился, дисплей находится в промежуточном состоянии и из него начинает некорректно воспринимать все следующие команды.
Проект [[Open Robotics]] - Универсальные модули для построения роботов
Аватара пользователя
=DeaD=
 
Сообщения: 24218
Зарегистрирован: 06 окт 2004, 18:01
Откуда: Ебург
прог. языки: C++ / PHP / 1C
ФИО: Антон Ботов

Re: Проблемы с аппаратным I2C на AVR ATmega32

Сообщение HarryStar » 23 июн 2011, 13:09

Блин. Только сейчас понял что не в ту тему поместил видео с ОЛЕД
Нужно было сюда forum2/topic10205.html
:(
Сейчас в ту добавлю видео, чтоб было правильно. А отсюда можно удалить, а ответы перенести туда если можно.

Добавлено спустя 13 минут 2 секунды:
Тут продолжим по теме. Продолжаю разбираться с аппаратным I2C...
Из-за чего может выдаваться событие "BUS FAIL"?

Сейчас пробую на другой библиотеке. Мастер посылает 1 байт слейв контроллеру. После отсылки получает
код 0×48 SLA+R+NACK - это или не ответили или слейв занят или его нет
В это же время на слейве срабатывает прерывание и выдает код 00 - аппаратная ошибка шины.

Из-за чего такое может быть?
Аватара пользователя
HarryStar
 
Сообщения: 995
Зарегистрирован: 15 ноя 2010, 13:56
Откуда: Нижний Новгород
прог. языки: С, С++, РНР

Re: Проблемы с аппаратным I2C на AVR ATmega32

Сообщение HarryStar » 01 июл 2011, 23:04

Разобрался с I2C аппаратным на Меге наконец-то. Теперь все работает. И мастером и слейвом и всем вместе и как угодно.

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

Планируются следующие модули в порядке приоритета:

1) Звуковой. Воспроизведение любых звуков с SD карты.
2) Модуль сопряжения с модельными радиоприемниками на любое кол-во каналов. Для начала будет 16 каналов.
3) Модуль LCD дисплея. Стандартные варианты типа 16х2 или 20х4. А то больно много ног жрут, неудобно пользоваться.
4) Возможно клавиатурный модуль. Иногда нужно несколько кнопок для отладки.

возможно по ходу дела придумаю еще что-то, но первые 2 мне нужно срочно, у меня мой робот простаивает из за этого :)

После доделки первого модуля напишу про него отдельно поподробнее.
Аватара пользователя
HarryStar
 
Сообщения: 995
Зарегистрирован: 15 ноя 2010, 13:56
Откуда: Нижний Новгород
прог. языки: С, С++, РНР

Re: Проблемы с аппаратным I2C на AVR ATmega32

Сообщение HarryStar » 18 июл 2011, 00:13

Закончил первую версию своего Звукового Модуля.

Краткое описание:
АТмега32-16 Мгц.

При включении пытается обнаружить подключенную SD карту со всякими звуками. Если обнаружена говорит "Звуковой модуль загружен", если не обнаружена, то пищит. В следующих версиях частичный функционал будет поддерживаться и без карты.

После инициализации ждет команды по I2C.

Чтение 1 байта из модуля возвращает статус модуля. Не готов, готов, идет воспроизведение и несколько служебных.
Пример использования: status=SM_GetStatus();

Запись в модуль делится на 3 команды:
1) Возпроизведение unsigned int (2 байта). Произносит число от 0 до 65535.
Пример использования: SM_PlayNum(98);
2) Воспроизведение файла. Передается полный путь к файлу.
Пример использования: SM_PlayFile("0:/8kHz/Music/enya.wav");
Если файл не найден, модуль говорит "Файл не найден".
Если модуль занят, например воспроизведением, команды игнорируются. В последующих версиях будет обработка очереди. Т.о. сейчас, если нужно гарантированно что то воспроизвести, то нужно делать так:
while(SM_GetStatus()!='R') delay_ms(10); SM_PlayFile("0:/8kHz/Music/enya.wav");
3) Воспроизведение "произвольной" строки. :wink:
Пример использования: SM_PlayString("lapa nomer 4 servo nomer 17 work_ok");
Воспроизводит фразу: "Лапа номер 4 сервопривод номер 17 работает нормально".
Синтезатора никакого нет. Алгоритм следующий:
Строка разбивается на слова. Каждое слово произносится отдельно. Если это число - говорится число. Поддерживаются числа от 0 до 1 млн. К остальным словам прибавляется ".wav" и полученное имя файла ищется по списку каталогов в порядке приоритета (заданного заранее).
Сейчас список просто хранится в массиве
{"0:/HS/8kHz/",
"0:/8kHz/Other/",
"0:/8kHz/Weapon/",
"0:/8kHz/TF/",
"0:/8kHz/Music/",
"0:/16kHz/Other/",
"0:/16kHz/Weapon/",
"0:/16kHz/TF/",
"0:/16kHz/Music/",
"0:/R2D2/"};
Скорее всего в следующих версиях список будет считываться с SD карты. Например из файлика в корне.

Пробел воспроизводится как небольшая задержка. Если слово нигде не найдено, оно игнорируется.

Пока приступаю ко второму I2C модулю, управляющего 24 сервами.
В связи с этим важный вопрос!!!

Если включен аппаратный I2C, то соотв задействованы пины PC0 и PC1. У меня на остальные 6 пинов порта С подключены сервы и я записываю в порт С всякие значения например PORTC = 0xFF;

Это помешает работе аппаратного I2C? Или когда он включен, он не воспринимает на этих пинах программное управление состоянием? В даташите что-то не нашел нужную информацию.
Аватара пользователя
HarryStar
 
Сообщения: 995
Зарегистрирован: 15 ноя 2010, 13:56
Откуда: Нижний Новгород
прог. языки: С, С++, РНР

Re: Проблемы с аппаратным I2C на AVR ATmega32

Сообщение =DeaD= » 18 июл 2011, 08:52

SM_GetStatus() - это уже функция из библиотеки головного МК?

Добавлено спустя 29 минут 31 секунду:
И как это в даташите не сказано?

Раздел I/O Ports / Alternate port functions / Alternate functions of Port C:
• SDA – Port C, Bit 1
SDA, Two-wire Serial Interface Data: When the TWEN bit in TWCR is set (one) to enable the
Two-wire Serial Interface, pin PC1 is disconnected from the port and becomes the Serial Data
I/O pin for the Two-wire Serial Interface. In this mode, there is a spike filter on the pin to suppress
spikes shorter than 50 ns on the input signal, and the pin is driven by an open drain driver
with slew-rate limitation. When this pin is used by the Two-wire Serial Interface, the pull-up can
still be controlled by the PORTC1 bit.

• SCL – Port C, Bit 0
SCL, Two-wire Serial Interface Clock: When the TWEN bit in TWCR is set (one) to enable the
Two-wire Serial Interface, pin PC0 is disconnected from the port and becomes the Serial Clock
I/O pin for the Two-wire Serial Interface. In this mode, there is a spike filter on the pin to suppress
spikes shorter than 50 ns on the input signal, and the pin is driven by an open drain driver
with slew-rate limitation. When this pin is used by the Two-wire Serial Interface, the pull-up can
still be controlled by the PORTC0 bit.
Проект [[Open Robotics]] - Универсальные модули для построения роботов
Аватара пользователя
=DeaD=
 
Сообщения: 24218
Зарегистрирован: 06 окт 2004, 18:01
Откуда: Ебург
прог. языки: C++ / PHP / 1C
ФИО: Антон Ботов

Re: Проблемы с аппаратным I2C на AVR ATmega32

Сообщение boez » 18 июл 2011, 10:57

HarryStar писал(а):У меня на остальные 6 пинов порта С подключены сервы и я записываю в порт С всякие значения например PORTC = 0xFF;

А ты отучайся так делать. PORTC = ((PORTC & leave_mask) & (~and mask)) ^ or_mask;
Ну или если есть серьезные ограничения по производительности, то конкретно в твоем случае можно и писать напрямую число в порт, токо выясни, какие значения PC0 и PC1 нужны для правильной работы I2C и всегда записывай в младшие биты именно их.
boez
 
Сообщения: 1981
Зарегистрирован: 27 авг 2008, 10:45
Откуда: Харьков
прог. языки: С/С++

Re: Проблемы с аппаратным I2C на AVR ATmega32

Сообщение =DeaD= » 18 июл 2011, 11:00

Видимо 00 нужно туда писать, чтобы pull-up случайно не активировать...

Хотя оно, наверное, не особо помешает, даже если активировать... :oops:
Проект [[Open Robotics]] - Универсальные модули для построения роботов
Аватара пользователя
=DeaD=
 
Сообщения: 24218
Зарегистрирован: 06 окт 2004, 18:01
Откуда: Ебург
прог. языки: C++ / PHP / 1C
ФИО: Антон Ботов

Re: Проблемы с аппаратным I2C на AVR ATmega32

Сообщение HarryStar » 18 июл 2011, 16:45

=DeaD= писал(а):SM_GetStatus() - это уже функция из библиотеки головного МК?

Да.
=DeaD= писал(а):И как это в даташите не сказано?

О, спасибо, видимо просмотрел. Это хорошо, значит ничего не помешает записывать данные.
boez писал(а):Ну или если есть серьезные ограничения по производительности

Да, там очень жестко по производительности. Где не критично, я так и делаю, но тут другой случай.
Аватара пользователя
HarryStar
 
Сообщения: 995
Зарегистрирован: 15 ноя 2010, 13:56
Откуда: Нижний Новгород
прог. языки: С, С++, РНР

Пред.

Вернуться в Коммуникации

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 1