Медленная работа LiquidCrystal_I2C

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

Попытался сегодня подключить дисплей 1602 через LiquidCrystal_I2C и был неприятно поражен скоростью ее работы.

Нет, что там не все так гладко, я предполагал и ранее, но чтобы до такой степени...

В общем, при сиандартных настройках один символ выводится примерно 1500 мкс, а строка - более 20000 соответственно.

Выяснил, что:

1. На один символ по интерфейсу I2C передается 12 байт. Причем, с солидными "зазорами" между ними.

2. Реальная скорость I2C растет совсем не пропорционально "номинально" скорости. Например, если скорость по умолчанию составляет 100, то при увеличении ее вроде бы а 8 раз - до 800 реальная частота следования битов увеличивается примерно до 640к (вместо ожидаемых 800к), а за счет увеличения относительной доли "промежутков" реальная скорость возрастает только в 3 вместо ожидаемых 8 раз. На один символ при этом затрачивается 500 мкс.

 

Чтение дэйташитов и статей по этому поводу привело к некотороым выводам:

1. Общение ведется в 4-бином режиме, т.е. для передачи одного байта нужно отослать два.

2. Пересылка через I2C осуществляется порциями по 1 байту, т.е. фактически по полбайта. Каждая, естественно, со своим заголовком.

3. Есть две разные рекомендации по обеспечению графика работы:

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

б) полностью отказаться от операцйий чтения и выдерживать паузы в 40 мкс между командами.

Таким образом получается, что время ввода символа можно сократить где-то до 80-90 мкс для 4-битного режима. Т.е. более, чем в 5 раз.

Если речь идет об I2C, то проверка готовности - накладная операция.

Интересно, можно ли каким-либо способом (не обязательно через I2C) заставить работать контроллер с временами существенно лучшими, чем гарантирует дэйташит?

Ну и, на худой конец, кто-нибудь пробовал довести скорость обмена с дисплеем хотя бы до порядка величин, гарантируемых дэйташитом (т.е. раз в 17-19 быстрее тех, что по умолчанию)?

Клапауций 232
Offline
Зарегистрирован: 05.04.2016

LiquidCrystalFast - пин RW доподключить.

http://www.pjrc.com/teensy/td_libs_LiquidCrystal.html

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

Андриано! Не будет ли наглостью попросить уточнить проблему?

С И2С да, на каждый символ две сырые отправки по полубайту, Каждый полубайт это три записи в регистр И2С расширителя портов. Одна для данных и две для строба синхры. Каждая запись в регистр это два байта отправки - ардес (0x27) и данные, по 10 бит на кадый. Итого 12х10 бит = 120 бит. При 100 КГц это 1200 мкс. Задержки можно выкинуть, но это предел. PCF8574, вроде как не поддерживает 400КГц.

Вопрос про задачу - не праздный. Вы сами - хороший программист и поймете меня: Что является проблемой - скорость на экране? Скорость отправки из главной программы? Время непродуктивного занятия процессора?

Есть несколько решений. При подключении на 8 бит, если проводов хватит - можно получить максимальную скорость. Если нет столько ног, то можно повесить ЛСД на отдельный камень, тут хватит 168 или даже 48. Ног - достаточно, а с основным камнем можно через сериал общаться с дикими скоростями, И интерфейс весь рисовать на служебном камне, а из основного передавать только минимум данных.

Как-то так.

 

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

wdrakula пишет:

Андриано! Не будет ли наглостью попросить уточнить проблему?

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

Цитата:

С И2С да, на каждый символ две сырые отправки по полубайту, Каждый полубайт это три записи в регистр И2С расширителя портов. Одна для данных и две для строба синхры. Каждая запись в регистр это два байта отправки - ардес (0x27) и данные, по 10 бит на кадый. Итого 12х10 бит = 120 бит. При 100 КГц это 1200 мкс. Задержки можно выкинуть, но это предел. PCF8574, вроде как не поддерживает 400КГц.

Вот сразу непонятки.

1. Чтение данных происходит по заднему фронту строба. На разных диаграммах передний фронт и выставление данных как-то представляются по-разному. Отсюда идея - устанавливать данные одновременно с передним фронтом. Тогда не 3, а 2 байта на полубайт.

2. Когда возился с OLED 0.96", обнаружил, что практически во всех библиотеках данные передаются именно таким способом - по одному на каждый цикл передачи. Т.е. каждый байт данных снабжается байтом заголовка. Передалал на отправку от 6 до 16 байт данных вместе с единственным байтом заголовка. Скорость выросла раза так в 2.5. Ну там еще конец передачи тоже общий.

3. Не смотрел, какой точно чип стоит на плате, но на 800 кГц он данные принимает и на экране отображает. (на самом деле получилось не 800, а 640) Попытка разогнать до 1000 успехом не увенчалась, но мне кажется, что тут уже виновата Ардуина. Как-то двухбайтовая посылка перестала быть похожа на двухбайтовую (по внешнему виду - на осциллографе).

Цитата:

Вопрос про задачу - не праздный. Вы сами - хороший программист и поймете меня: Что является проблемой - скорость на экране? Скорость отправки из главной программы? Время непродуктивного занятия процессора?

Понятно, что не праздный. Именно последний вариант. Для меня крайне важно опрашивать последовательный порт не реже раза за 300 мкс. А тут за это время даже одного символа не вывести. Опрос на прерывание заводить не хочу, т.к. единственное прерывание по таймеру выполняет еще более критичную ко времени работу.

Цитата:

Есть несколько решений. При подключении на 8 бит, если проводов хватит - можно получить максимальную скорость. Если нет столько ног, то можно повесить ЛСД на отдельный камень, тут хватит 168 или даже 48. Ног - достаточно, а с основным камнем можно через сериал общаться с дикими скоростями, И интерфейс весь рисовать на служебном камне, а из основного передавать только минимум данных.

В качестве запасного варианта (ну предполагал, что с экраном могут быть задержки, хотя, конечно, недооценивал масштаб проблемы) изначально планировалось поставить Про Мини. Так что пока этот вариант основным и остается. Просто хочется для себя решить, стоит ли пытаться вылизывать программно-аппаратную часть общения с дисплеем в расчете на единственную Мегу 2560 или плюнуть на это как на затею бесперспективную. Пока на Меге свободен 1 порт (8 пинов), ну, может, еще пару пинов где наскребется. Но пока проект не обкатан до конечных деталей, занимать последнее тоже не хочется.

 

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

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

В случае 1602 не получится отправка данных потоком, потому что I2C регистр подключен и к данным и к урпавлению LCD, а защелкивает он после получения ack. На i2c вы скорость не нагоните. Лучше про-мини. и нагрузить ее весь интерфейс рисовать, а может еще и кнопки слушать.

Посмотрите всю "кухню" изнутри. Я, как раз, в ветке про attiny13 опубликовал полностью софтверную реализацию и и2с и лсд поверх него. Это я дурью маялся, но будет полезно, чтобы в деталях обмена разобраться. если будут вопросы - пишите. На софтовом варианте можно поиграться со многими параметрами "вживую".

Кстати, как вариант, можно строб отдельным пином кинуть  и сразу в ТРИ раза быстрее станет.

 

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

Клапауций 232 пишет:

LiquidCrystalFast - пин RW доподключить.

http://www.pjrc.com/teensy/td_libs_LiquidCrystal.html

Насколько я понял, там используется то, что первом посте я обозначил как 3а), и утверждается, что это увеличивает производительность до 4 раз. Правда, не обнаружил конкретных цифр, и что-то у меня сомнение по поводу "быстрых" процедур, котороые используют "медленные" digitalRead и digitalWrite. Боюсь, речь идет не о переходе от 40-мкс операции по дэйташиту к 10-мкс, а от 1500-мкс в стандартной библиотеке к 400-мкс в "быстрой". Но это, естественно, надо проверять. А для этого нужно еще распаять экранчик, т.к. те, что у меня есть, либо с I2C, либо с "дырочками".

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

wdrakula пишет:

Кстати, как вариант, можно строб отдельным пином кинуть  и сразу в ТРИ раза быстрее станет.

Блестящая идея!

Правда, боюсь, для 2560+I2C этого недостаточно, а ПроМини+стандартный_4-проводный это неактуально.

Клапауций 232
Offline
Зарегистрирован: 05.04.2016

andriano пишет:

Насколько я понял, там используется...

там активно используется пин индикатора RW, в то время как при классическом подключении он заземлён и мы не знаем, готов ли индикатор принимать данные, но предполагаем это, а что бы подстаховаться от сбоев при передаче, тупим скорость передачи данных.

попробуй - там бенчмарк в примерах к библиотеки есть.

Logik
Offline
Зарегистрирован: 05.08.2014

Я тоже в общем не пойму проблему. Получается 20мс на строку 40мс на экран, 25 раз в секунду перерисовывается, даже анимация получится))) Если архитектура в совте правильная, без делеев, то все нормас предпочтительней аппаратный I2c. То, что передача полубайтами - исторически сложившийся бардак. И то, что требуется каждый раз заголовок - тоже, но с учетом итоговой скорости не существенен.

andriano пишет:

2. Когда возился с OLED 0.96", обнаружил, что практически во всех библиотеках данные передаются именно таким способом - по одному на каждый цикл передачи. Т.е. каждый байт данных снабжается байтом заголовка. Передалал на отправку от 6 до 16 байт данных вместе с единственным байтом заголовка. Скорость выросла раза так в 2.5. Ну там еще конец передачи тоже общий.

Не. То Вам с либами невезло, что OLED, что LCD (понятно не 1602), отлично работают с потоком длиной во весь экран. Ну к примеру очистка 

void SSD1306::update()
{
    sendTWIcommand(SSD1306_SET_COLUMN_ADDR);
    sendTWIcommand(0);
    sendTWIcommand(127);

    sendTWIcommand(SSD1306_SET_PAGE_ADDR);
    sendTWIcommand(0);
    sendTWIcommand(7);

    sendStart(SSD1306_ADDR<<1);
    writeByte(SSD1306_DATA_CONTINUE);

    for (int b=0; b<1024; b++)		// Send data
    {
            writeByte(ob);
    }

    sendStop();
}

Это лишний раз говорит о качестве распостраненных библиотек.

andriano пишет:
 Не смотрел, какой точно чип стоит на плате, но на 800 кГц он данные принимает и на экране отображает. (на самом деле получилось не 800, а 640) Попытка разогнать до 1000 успехом не увенчалась, но мне кажется, что тут уже виновата Ардуина. Как-то двухбайтовая посылка перестала быть похожа на двухбайтовую (по внешнему виду - на осциллографе).

 

Завелся на 800кГц - вобще круть, делайте софтверный i2c, как wdrakula пишет, на такой скорости лучше не придумаеш.

 

 

andriano пишет:
  Для меня крайне важно опрашивать последовательный порт не реже раза за 300 мкс. А тут за это время даже одного символа не вывести. Опрос на прерывание заводить не хочу, т.к. единственное прерывание по таймеру выполняет еще более критичную ко времени работу.

Делайте софтверный i2c на 800кГц прямо из лупа, без запрета прерываний, оно это терпит. Далее дело известное, проверяем прошло ли 40мкс, если да то машинка состояний быстенько выпихивает очередной байт. И не надо перерисовывать экран чаще нескольких раз в секунду. Человек невосприймет все что быстрей!

 

 

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

Logik пишет:

Далее дело известное, проверяем прошло ли 40мкс,

Логик! До меня вчера дошло, что через PCF8574 нет НИКАКОГО смысла писать все эти "40 мкс" из протокола.

Просто следующая команда придет не раньше чем 6 байт отправки по И2С. Смотри:

1. адрес данные,

2. адрес, данные | (строб_Е)

3. адрес, данные & ! (строб_Е).

Это минимум 60 циклов и2с, то есть, ДАЖЕ на 800КГц это 48 мкс. Так что ждать точно не нужно ;). Я уже убрал все глупые задержки из софтовой реализации. После команды 0x01, которая "очистка", нам приказывают ждать 1500 мкс. Я, по инерции пишу "delay(1)", но полагаю, что и это не нужно. Хотя clear в loop вызывать  ...неясно - зачем?

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

Кстати вот идея для стартапа ;) ;) ;):

берем контроллер типа атмеги 48 (ее уже хватит, но можно и 168- их больше и купить проще) , кварц на 16, пяток резисторов, 4 конденсатора.

И делаеи НОРМАЛЬНЫЙ и2с контроллер для 1602-2004 лсд. С прописывание элементов (виджетов) на экране, их каталогом, свойствами... ну всем все и так понятно.

Ну и пытаемся продавать не по 40 рублей, как просто регистр и2с, а уже за 150-200. Не взлетит? ;) ;) ;). Готов код написать за 50%.Для начала можно готовую про мини за 80 р штука использовать, но переходной шнурок или платка понадобится, а нужно, как у китайцев на PCF8574 - "вот прям вот" в дисплей втыкать. Можно такие платки чайникам продавать, рублей по 100, типа на нее напаиваешь про миньку, и там тебе уже сразу гребенка под дисплей и разъем для и2с и ISP, штоп прошивку обновлять.

А в прошивке - просто сказка, и тебе древовидные и циклические меню, и поддержка всего мыслимого ввода, от кнопок и тактовых и аналоговых и джойстик и енкодер и матричные клавы. И и2и обмен на максималке, с необходимостью только значения передавать, в готовое оформление. И очереди событий, шо твой виндуз... ;). Ну, как-то так

...

чет меня понесло.

-------

если у кого ЧЮ подводит, то это шЮтка.

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

проверка показала, что ДА, дейчтвительно можно треть выиграть, если не три раза, а  два засылать новое состояние в лсд. Можно поднять строб при первой засылке и потом опустить. Так - работает. Этот момент можно в функции write4bits() в стандартной библиотеке изменить.

(я все делал через свою. потому, что одновременно тиньку13 гонял с лсд и ртс3231).

Все дурацкие 5 мкс, 40 мкс и пр. тоже можно выкинуть - как бессмысленные (из стандартной библиотеки). Получится немного быстрее.

Arhat109-2
Offline
Зарегистрирован: 24.09.2015

откройте версию с гитхаба arhat.h там есть переделка работы с этим дисплеем, которая плюет в интерфейс все три посылки за 1 раз, то есть работает по-вашему в 3 раза шустрее. И задержки ставятся там строго согласно даташиту, то есть миллисекундные (4мсек, кажись). Да и I2C там способен работать на 800кгц "только так".

Logik
Offline
Зарегистрирован: 05.08.2014

wdrakula пишет:

 НИКАКОГО смысла писать все эти "40 мкс" из протокола.

...Это минимум 60 циклов и2с, то есть, ДАЖЕ на 800КГц это 48 мкс. Так что ждать точно не нужно ;). 

Ну не надо, так и не надо. Я чё, я не возражаю )))  Я просто о том что общая скорость перерисовки не такая уж и малая, и экран хоть и с причудами, но подключить его должно быть не проблемно. Но я такие принципиально не использую - только графические: OLED или TFT. А если уж графические на 800 летают, то символьный тоже не должен тормозить.

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

Arhat109-2 пишет:

откройте версию с гитхаба arhat.h там есть переделка работы с этим дисплеем, которая плюет в интерфейс все три посылки за 1 раз, то есть работает по-вашему в 3 раза шустрее. И задержки ставятся там строго согласно даташиту, то есть миллисекундные (4мсек, кажись). Да и I2C там способен работать на 800кгц "только так".

Вот ты, когда пишешь, на зрителя расчитываешь, или пиздоболишь просто из любви к искусству? У тебя в архат.х "сишным по белому" 6 байт высылаются.

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

#define lcdSend(len)                               \
{                                                  \
  twiWrite(lcdAddress, lcdBuffer, (uint8_t)(len)); \
  delay(LCD_WAIT_1);                               \
}

#define lcdWrite1(d)     {lcdPrepare((uint8_t)(d), 1); lcdSend(6);}
#define lcdCommand(p)    {lcdPrepare((uint8_t)(p), 0); lcdSend(6);}
//.....я тут лишнее не стал копировать......................
    /**
     * Подготовка байта в буфер потоковой записи
     * @param _rs=[0 -- команда,!0 -- данные]
     */
    void lcdPrepare(uint8_t _data, uint8_t _rs)
    {
        uint8_t nibble = (_data&0xf0) | lcdBackLight;

        if( _rs ) nibble |= LCD_RS;
        lcdBuffer[2] = lcdBuffer[0] = nibble;
        nibble |= LCD_E;
        lcdBuffer[1] = nibble;

        nibble = ((_data&0x0f)<<4) | lcdBackLight;

        if( _rs ) nibble |= LCD_RS;
        lcdBuffer[5] = lcdBuffer[3] = nibble;
        nibble |= LCD_E;
        lcdBuffer[4] = nibble;
    }

    /**
     * Вывод строки заданной длины (буфера) на экран.
     * Повторная установка скорости работы дисплея по I2C и режима (мало ли кто и как работает ещё)
     */
    void lcdWrite(const void *buf, uint8_t len)
    {
        uint8_t *_b = (uint8_t *)buf;
        uint8_t  _l = len;

        twiMode |= TWI_SEND_STOP;
        while(_l--)
            lcdWrite1(*_b++);
    }
andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

Logik пишет:

Я тоже в общем не пойму проблему. Получается 20мс на строку 40мс на экран, 25 раз в секунду перерисовывается, даже анимация получится)))

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

Собственно, об этом я уже отвечал на пост wdrakula.

Цитата:

Не. То Вам с либами невезло, что OLED, что LCD (понятно не 1602), отлично работают с потоком длиной во весь экран. Ну к примеру очистка 

void SSD1306::update()
{
    sendTWIcommand(SSD1306_SET_COLUMN_ADDR);
    sendTWIcommand(0);
    sendTWIcommand(127);

    sendTWIcommand(SSD1306_SET_PAGE_ADDR);
    sendTWIcommand(0);
    sendTWIcommand(7);

    sendStart(SSD1306_ADDR<<1);
    writeByte(SSD1306_DATA_CONTINUE);

    for (int b=0; b<1024; b++)		// Send data
    {
            writeByte(ob);
    }

    sendStop();
}

Это лишний раз говорит о качестве распостраненных библиотек.

 

В данном фрагменте, увы, не расписано, что именно делает writeByte(), а это существенно, т.к. она организует для передачи одного байта данных целый пакет с заголовком.

Согласно документации https://www.arduino.cc/en/Reference/WireEndTransmission данные накапливаются в буфере, а сама передача начинается по endTransmission(). Длина буфера 32 байта. Следовательно, одним пакетом можно передать максимум 31 байт данных, 1 приходится на заголовок. Все остальное - обрезается. Проверено.

И это действительно говорит о качестве распространяемых библиотек.

Logik
Offline
Зарегистрирован: 05.08.2014

andriano]</p> <p>[quote=Logik пишет:

Я тоже в общем не пойму проблему. Получается 20мс на строку 40мс на экран, 25 раз в секунду перерисовывается, даже анимация получится)))

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

Собственно, об этом я уже отвечал на пост wdrakula.

Нет, тек не считаю. Но считаю что вывод нескольких сотен байт по i2c ногодрыгом на 800КГц, пяток раз в секунду, без использования и запретов прерывания, без использования таймеров и др. переферии - легко интегрируемая в любую адекватно спроектированую програму. Я такой подход для отладки использую, когда надо чтото смотреть и других возможностей нет - на любые 2 пина цепляю SSD1306, лиш бы пару килобайт в програмной памяти нашлось. 

andriano пишет:

В данном фрагменте, увы, не расписано, что именно делает writeByte(), а это существенно, т.к. она организует для передачи одного байта данных целый пакет с заголовком.

Согласно документации https://www.arduino.cc/en/Reference/WireEndTransmission данные накапливаются в буфере, а сама передача начинается по endTransmission(). Длина буфера 32 байта. Следовательно, одним пакетом можно передать максимум 31 байт данных, 1 приходится на заголовок. Все остальное - обрезается. Проверено.

Это все очень прикольно, но не нужно.

В скетче создается функция с помощю макроса такого (его часть, еще заодно упоминаемые SDA_... и SCL_... и функция на чтение и еще коече)

void ssd1306_i2cWriteByte##scl(byte v)           \
{                                            \
     SDA_OUT();                       \
    for (byte i=8;i;i--)  { if (v & 0x80)   SDA_HIGHT();  else  SDA_LOW();asm volatile ("nop");asm volatile ("nop");asm volatile ("nop");SCL_HIGHT();asm volatile ("nop");asm volatile ("nop"); v <<=1;  SCL_LOW(); }                \
  SDA_HIGHT();SDA_IN();  SCL_HIGHT(); WITE_HIGHT_SDA(); SDA_LOW(); SCL_LOW();       \
}\

Указатели на эти функции передаются в конструктор и указатель сохраняются внутри класса в свойсиве Wr. В результате вышеупомянутая функция выглядит примитивно.

void writeByte(uint8_t value){Wr(value);};

А тем, у кого буфера 32..1024 - мои соболезнования ))) 

Arhat109-2
Offline
Зарегистрирован: 24.09.2015

Не заметил вашего поста сразу..

А при чем тут "Пи*больство"? Да, отправляются всего 6 байт. Одной посылкой - "сеанс связи", а не 6 раз по байту с вызовом хреновой горы в т.ч. и отнаследованных и уж не помню виртуальных(?) функций.

То, что вы опубликовали - функция заполнения буфера отправки. Отсылается он из прерывания TWI обработчиком. 6 байт - одной пачкой. Запуск обработчика прерывания делается функцией lcdSend(), которая получает .. размер пачки на отправку. Задержка, стоящая в ней - согласно даташиту на дисплей. Шустрее он .. никак, поэтому готовить следующий буфер конечно можно, но там сделано так.

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

Архат! Тупите нарочно? ШЕСТЬ байт + адрес=7, против 12 байт стандартной библиотеки. Это быстрее, но не в три раза. И PCF8574 НЕ ПОДДЕРЖИВАЕТ!!!! 800. Он по дпташиту даже 400 не держит, но в жизни работает. В этом и звездежь... уж простите мой французский.

Arhat109-2
Offline
Зарегистрирован: 24.09.2015

Бли-ин. 6 байт - аппаратной пересылкой за раз, да + адрес. Или 12 байт поштучно, продираясь через 6 или 12 ВЫЗОВОВ, передавая каждый раз по 1 полубайту? Ну вы даете.. вы хоть смотрели, что там происходит в библиотеках или куда? :)

Да, и быстрее чем сделано у меня - у вас все одно не выйдет. Каждую пачку надо выдерживать паузой перед отправкой следующей.

И кстати, PCF8574 вполне справляется с передачей в режиме 400кГц и даже 600. 800 - да, не держит. Проверено экспериментально.

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

короче так. Если Вас это не сильно затруднит....

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

#include "lcd1602.h"

// ************* Example *********** //

void setup() {
    lcdSetup(0x27, 16, 2, 1);
    lcdWrite("Hello, Arhat!", 13);
    lcdSetCursor(0,1);
    lcdWrite("Bye, Bye..", 10);
}

void loop()  {
constant char s[40]=(char *)"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
char ss[10] = "          ";
uint32_t  m,om=millis();

delay(2000);

    lcdSetCursor(0,1);
    lcdWrite("                ", 16);

for (int j=0; j< 500; j++){
  lcdSetCursor(0,0);
  lcdWrite(s+ (j%25));
  }

m=millis()-om;

itoa((int)m,ss,10);
  lcdSetCursor(0,1);
  lcdWrite(ss,10);


}

Это просто Ваш пример, к которому добавлена печать 5000 знаков (500 раз по 10 разных) и подсчет времени.

Опубликуйте результат, если не трудно. Я, повторю, не смог, Последняя IDE, для нанки, ругается на этапе уже сборки, на что-то про таймер хуки, из Вашей библиотеки. Я - не стал разбираться, при живом авторе ;).

То есть я ответа на тест НЕ ЗНАЮ. Знаю, что дает стандартная библиотека.

-----------------

Я - не настаиваю. Нет желания - можете не делать. Разберусь со временем, почему ваше "сырье" не собирается, но тогда это будет уже мой результат, без возможности, для вас, открутиться от гонева и сослаться на случайности.

--------

и перепешите setCursor, стыдно, ей Б..гу! У всех 4-х строк - разные смещения начала. Вы б в даташит взглядывали иногда, что ли.

Arhat109-2
Offline
Зарегистрирован: 24.09.2015

Ок, но чуть позже. Сейчас наш "лего-кирпич" разобран, делаю плату под драйвера и стабилизаторы, готовимся к соревнованиям. Ориентировочно потребуется ещё неделя, пока доедут детальки. Плату уже развел, драйвер мотора на макетке - работает "по полной" .. на днях буду травить.

P.S. Править чего-то там, что выложено на гитхабе - извините, но не буду. Хотите - подключайтесь, правьте .. а код проверю обязательно и выложу тут результаты. Там ничего сложного нет. А ругаться может на много чего, поскольку пилилось оно только под версию 1.6.4 .. чего там наваляли ардуинщики - я не в курсях уже давно, ибо ИДЕ пользуется только ребенком и только в сочетании с Ардублоком.

P.P.S. Не понял чего вам там "стыдно" ..

/**
 * Установить абсолютную позицию курсора
 */
#define lcdSetCursor(_col,_row) \
    (lcdCommand(LCD_SHOW_RAM | ((((_row)? 0x40 : 0x00) + (uint8_t)(_col)) & 0x7f)))

Это ваще-то макрос. Результат его разворачивания дает оба варианта. 1602 - это ваще-то ДВЕ строки по 40/80 символов. Что и написано в заголовочном комментарии. Какие "четыре варианта"? Может Вы имели ввиду 4-х строчные дисплеи .. так у меня их нет, не делал и не озадачивался даже. Надо - поправьте самостоятельно.

И по скорости. Там же в файле отписан результат испытаний: "тянет 800кгц". Так что, звиняюсь - запамятовал ужо. :)

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

давайте свернем болтологию. Дайте результат на компилируемом у других тесте: сколько мс на 5000 символов. Проверяем на нанке, как то, что есть у любого в столе.

Мне удобнее на Леонардо, Вам - на меге, но нанка - общеупотребительная вещь. На ней  и остановимся. Если религия требует не пользоваться иде, то выкладывайте программу для 328 16 Мгц, голого железа (студия или просто avr-gcc под динухом, как я буду собирать, это одно и тоже).

ИТОГО условия: Архат утверждает, что его вариант библиотеки для хардваре И2С+1602 ЛСД даст на 5000 символов время, адекватное скорости шины в 800 КГц. Стандартная библиотека дает порядка 8-10 сек на 100КГц.Пример должен компилироваться либо на ИДЕ либо на студии под голое железа Атмега 328 16 МГц. Результат должен отображаться на тестируемом экране.

Согласны?

Arhat109-2
Offline
Зарегистрирован: 24.09.2015

У меня нет нанки, есть мега и уно. Обе сейчас - РАЗОБРАНЫ, в том плане что подключить к ним мой дисплей (он тоже один и разобран) не представляется возможным. Компилять и показывать пример я вам буду на Мега2560 в оболочке 1.6.4 ибо другой ТОЖЕ НЕТ и не предвидится. Могу скомпилять прямо сегодня, но проверять Вы будете в таком разе самостоятельно.

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

И ещё раз: перечитайте мои комменты к этому коду. 5000, да хоть 50 символов запихать шустрее в LCD1602 чем он их переваривает - вы все равно НЕ СМОЖЕТЕ. Там задержка на 1 символ 4 МИЛЛИСЕКУНДЫ на пример символа.

Клапауций 232
Offline
Зарегистрирован: 05.04.2016

оказываю платные услуги по компилляции ваших проектов - хекс высылаю на указанную вами почту после предоплаты.

Arhat109-2
Offline
Зарегистрирован: 24.09.2015

Нащел на работе 1.6.9, выкачал с гитхаба библиотеку, скомпилял .. все компиляется:

Скетч использует 1 608 байт (0%) памяти устройства. Всего доступно 253 952 байт.
Глобальные переменные используют 52 байт (0%) динамической памяти, оставляя 8 140 байт для локальных переменных. Максимум: 8 192 байт.

Что у Вас не получилось? Да, там повылетала кучка warning и note .. но это как-бы и понятно: с wiring оно не дружит и не планировалось в общем-то.

P.S. перечитал ваше сообщение: "Последняя IDE, для нанки, ругается на этапе уже сборки, на что-то про таймер хуки, из Вашей библиотеки. Я - не стал разбираться, при живом авторе ;"

Вот собственно в этом и кроется ПРИЧИНА почему я перестал обновлять эту библиотеку и выкладывать что-то ещё.

Специально для вас в самом файле arhat.h указано: "!!!ВНИМАНИЕ!!! В связи с изменением логики Wiring, начиная с версии 1.6.7, а именно: принудительная вставка оператора #include "Arduino.h" в первую строку любого скетча, механизм приедложенный тут по его "выключению" - теперь не работает!" .. строки 33,34.

А также к библиотеке приложен файл readme.txt, в котором тоже явно указано: "Внимание! Если у Вас при запуске скетчей из примеров появляется ошибка типа 'redefine __vector_23()', то Вам необходимо переименовать файл wiring.c, лежащий в папке Ардуино ...\hardware\..\core. Где он конкретно лежит - зависит как от Вашей ОС, версии Ардуино ИДЕ, так и от метода установки (в Линукс)."

И ещё там же, в описании на гитхабе и практически везде: "При указании номера пина в переменной - этот подход НЕ РАБОТАЕТ!" в readme.txt даже сделана попытка разъяснить почто так.

Как понимаю, Вы это всё не читали.

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

Arhat109-2 пишет:

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

Вы с утра совершенно охренели??? Это же Ваш код! Я, конечно, могу его исправить, но зачем?

Не компилируется для Нано в 1.6.11 (или 12, не помню) ПРОСТО ВАШ ПРИМЕР.

Сейчас собак покормлю и пойду искать ошибку в Вашем, заметьте, сырье.

 

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

Arhat109-2 пишет:

И ещё там же, в описании на гитхабе и практически везде: "При указании номера пина в переменной - этот подход НЕ РАБОТАЕТ!" в readme.txt даже сделана попытка разъяснить почто так.

Как понимаю, Вы это всё не читали.

 

Нахера Вы приплели номер "пина в переменной", для заполнения места в форуме?

Где в ВАШЕМ примере из архат.х для ЛСД есть пин в переменной, и где там таймер хуки?

То есть Вы написали библиотеку, котора включает в код всякую херню, даже если там ей не место?

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

----

В Вашем примере вызывается ТОЛЬКО управление аппаратным И2С, Вы его тоже на "ху...ки" прицепили?

.....

и еще, я как бы был единственным человеком, кто летом помог вам с twi как раз, когда она у Вас с Serial конфликтовала.

Тогда ветка кончилась на том, что Вам придется свой сериал писать... ну и как, написали? В связи с этим мне немного странно слышать тупые поучения.

-----------------------------------------------------------

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

Про то, что драйвер ЛСД у вас написан с ошибками - тоже не поняли.

На мое прямое замечание, что в 4-х строчных дисплеях начала строк идут не 0 и 0x40, а другие (см. даташит) - Вы слили фразой, что Вас 4-х строчные не интересуют. Вот Вы не баба, после этого?

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

Я, конечно, запустил Архатовскую самоделку.

1. щас будет жесть!!!
Ощибка была такая:

Arduino: 1.6.11 (Linux), Плата:"Arduino Nano, ATmega328"

`timer0_hook_run' referenced in section `.text' of /tmp/ccUe8nHm.ltrans0.ltrans.o: defined in discarded section `.text' of libraries/ARHAT_H-master/arhat.c.o (symbol from plugin)
`timer0_hook_run' referenced in section `.text' of /tmp/ccUe8nHm.ltrans0.ltrans.o: defined in discarded section `.text' of libraries/ARHAT_H-master/arhat.c.o (symbol from plugin)
`timer0_hook_run' referenced in section `.text' of /tmp/ccUe8nHm.ltrans0.ltrans.o: defined in discarded section `.text' of libraries/ARHAT_H-master/arhat.c.o (symbol from plugin)
collect2: error: ld returned 1 exit status
exit status 1
Ошибка компиляции для платы Arduino Nano.

Этот отчёт будет иметь больше информации с
включенной опцией Файл -> Настройки ->
"Показать подробный вывод во время компиляции"

====================
То есть понятно, что оптимизатор сожрал переменную, как никому не нужную.
Про слово volatile автор явно слышал, это по коду будет видно.

Вот кусок из arhat.h

// @see in this below or wiring.c by ARHAT_MODE:
extern volatile uint32_t timer0_overflow_count;
extern  uint8_t           timer0_hook_run;       // !0: hook is running. Blocking twice calling. защелка, запрещающая повторный вызов.

вот из arhat.c

volatile uint32_t       timer0_overflow_count   = 0UL;  // timer overflow counter. Счетчик переполнений таймера 0 "тиков" по 1024мксек.
void        (* volatile timer0_hook)(void)      = 0;    // hook function pointer. функция "хук", вызываемая из обработчика, если надо.
uint8_t                 timer0_hook_run         = 1;    // hook is running. Blocking twice calling. защелка, запрещающая повторный вызов.

=======
ДА! Вы, дорогой читатель не ослепли! В .h файле переменная extern, которая ОПИСАНА в .с файле!!!!
нахера здесь extern - никто не знает, файлы компилируются вместе... ну да хрен с ним. В обоих файлах надо добавить volatile, и тогда все работает.

Я, из уважения к Автору ;) ;) ;), решил оставить его extern!
====================
как работает - в следующейй серии. Вполне ожидаемо работает, нужно сказать.

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

 вот тестовый код на Архатовской поделке.

#include "arhat.h"

//#define TWI_ON    15    // Debug: Включить все режимы обработчика I2C
//#include "arhat_twi.h"  // Debug: Подключить явно тут с заданным комплектом режимов

#define LCD_I2C_SPEED 800000 // Установить типовую скорость (внутри задано 800кгц!)
#include "lcd1602.h"

// ************* Example *********** //

void setup() {
    lcdSetup(0x27, 16, 2, 1);
    lcdWrite("Hello, Arhat!", 13);
    lcdSetCursor(0,1);
    lcdWrite("Bye, Bye..", 10);
}

void loop()  {
const char *s=(char *)"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
char ss[10] = "          ";
uint32_t  m,om;
int l=0;

delay(3000);

    lcdSetCursor(0,1);
    lcdWrite("                ", 16);

om=millis();
for (int j=0; j< 100; j++){
  lcdSetCursor(0,0);
  lcdWrite(s+ (j%25),10);
  }

m=millis()-om;

itoa((int)m,ss,10);
  lcdSetCursor(0,1);
  while(ss[++l]);
  lcdWrite(ss,l);


}

вот, что на экране

 

для сравнения, вот код, который я писал для тиньки, у нее нет хардварного и2с. и тест, такой же.



#define _NOP() asm volatile("nop")

//это у меня диагностическое моргание ледом на второй ноге тиньки
#define _LED()      (DDRB  |= 0B00001000)  
#define _LED_ON()   (PORTB |= 0B00001000)
#define _LED_OFF()  (PORTB &= 0B11110111)
  
 
// delay() для тиньки и свой нормальный, а delayMicroseconds() дурной
//поэтому свой нужен

//а вот глобального такого дефайна может и не быть, как ни странно, так для страховки завел
//#define F_CPU 4800000UL
#define LOOP_CYCLES 8
#define us(num) (num/(LOOP_CYCLES*(1/(F_CPU/1000000.0))))

inline __attribute__((gnu_inline)) void asm_delay(uint16_t delay){
  uint16_t u=us(delay);
do _NOP(); while(delay--);
}

#define wdelay_us(x)  asm_delay(us(x))
#define wdelay(x) delay(x)


/*****************************************************/
//дальше мелкий вариант i2c на любых ногах
//если работать через функции (закоментировано) то будет переносимость хоть куда

#define IICR  1
#define IICW  0
// на 100КГц примерно по 4 мкс нужно держать уровни SCL - со скоростью сами экспериментируйте, мне не нужно было
#define I2CDelay()  wdelay_us(1)
#define SDA_Pin   A4
#define SCL_Pin   A5

/**/
#define SDA_In()    digitalRead(SDA_Pin)
#define SCL_In()    digitalRead(SCL_Pin)

     void SDA_Hi()  { digitalWrite(SDA_Pin, HIGH); pinMode(SDA_Pin,  INPUT);}
     void SDA_Lo()  { digitalWrite(SDA_Pin, LOW ); pinMode(SDA_Pin, OUTPUT);}
     void SCL_Hi()  { digitalWrite(SCL_Pin, HIGH); pinMode(SCL_Pin,  INPUT);}
     void SCL_Lo()  { digitalWrite(SCL_Pin, LOW ); pinMode(SCL_Pin, OUTPUT);}
/**/
/*
#define SDA_In()    (PINB & 0B00000001)
#define SCL_In()    (PINB & 0B00000010)

     inline void SDA_Hi()  { PORTB |= 0B00000001; DDRB &= 0B11111110;}
     inline void SDA_Lo()  { PORTB &= 0B11111110; DDRB |= 0B00000001;}
     inline void SCL_Hi()  { PORTB |= 0B00000010; DDRB &= 0B11111101;}
     inline void SCL_Lo()  { PORTB &= 0B11111101; DDRB |= 0B00000010;}
*/
void I2CInit (void)
{
    SDA_Hi();
    SCL_Hi();
}

void I2CStart (void)
{
  SCL_Hi();
  //while (!SCL_In());
  I2CDelay();
  SDA_Lo();
  I2CDelay();
  SCL_Lo();  
  
}
 
void I2CStop (void)
{
  SCL_Lo();
  SDA_Lo();
  I2CDelay();
  SCL_Hi();
  //while(!SCL_In());
  I2CDelay();
  SDA_Hi();
  I2CDelay();
}

boolean I2CWrite(byte b)
{
  byte i = 1<<7;
  boolean ack=0;

  while(i)
    {
      //I2CDelay();
      if (b & i) SDA_Hi(); else SDA_Lo();
      I2CDelay();
      SCL_Hi();
      I2CDelay();
      SCL_Lo();
      
      i>>=1; 
    }
  SDA_Hi();
  I2CDelay();
  SCL_Hi();
 // while(!SCL_In());

  if ( SDA_In()==0 ) ack = 1;
  I2CDelay();
  SCL_Lo();
  SDA_Hi();
  return ack;
}

byte I2CRead(boolean ack)
{
  byte i=8;
  byte b=0;
  
  while(i--)
  {
   b <<= 1;
   SCL_Lo();
   SDA_Hi();
   I2CDelay();
   SCL_Hi();
   //while(!SCL_In());
   if (SDA_In()) b |= 1;
   
   I2CDelay();
   SCL_Lo();
  }
  if (ack) SDA_Lo();
  else SDA_Hi();
  I2CDelay();
  SCL_Hi();
  //while(!SCL_In());
  I2CDelay();
  SCL_Lo();
  return (b);
}

//==========================

/*************************************/
//Все ниже - для LCD дисплея на i2c. Принцип ясен, все легко переделать под свои варианты
//идеи взяты, ясен хрен, из стандарной библиотеки. Управление подсветкой похерено ради экономии ;)
#define LCDADDR 0x27


void lcdRaw(byte b)
  {
    I2CStart();
    I2CWrite(LCDADDR<<1);
    I2CWrite(b|8);
    I2CStop();
  }

void lcdWrite4(byte b)
  { //вот собственно проверка на то, что можно выкинуть делеи и передавать не  три, а два байта
   // lcdRaw  (b);
   // wdelay_us(5);
    lcdRaw  (b| 4);
    //wdelay_us(5);
    lcdRaw( (b&!4));
   // wdelay_us(40);
  }
void lcdCmd(byte b)
  {
    lcdWrite4(b&0xf0);
    lcdWrite4((b&0xf)<<4);  
  }
void lcdDate(byte b)
  {
    lcdWrite4 (b&0xf0     |1);
    lcdWrite4((b&0x0f)<<4 |1);  
  }

#define RTCADDR 0x68

void setup() {

I2CInit();
//где-то видел, что нехилая задержка нужна, чтобы дисплей проснулся, проверяйте сами, если нужно
wdelay(1000);

//init LCD acc docs
//just like lcd_i2c standart lib
lcdWrite4(0x30);
 wdelay(5);
 
 lcdWrite4(0x30);
 wdelay(5);
 
 lcdWrite4(0x30);
 wdelay(1);

 lcdWrite4(0x20);
 wdelay(1);
 
 //set 4 dig
 lcdCmd(0x28);
 lcdCmd(0x0c);
 lcdCmd(0x01);
 wdelay(1);
 lcdCmd(0x06);
 lcdCmd(0x02); 


lcdCmd(0x01);
    wdelay(2);

}

void loop() {

uint32_t s,os,ds,ds10;
char *ss="            ";
int l=0;
 
 os= millis();
       
    

for (int j=0;j<100;j++)
{
 lcdCmd(0x80 );
 for (byte i=0; i< 10;i++) lcdDate('A'+i + (j&0x0f));
}

   
    s= millis();
    
    lcdCmd(0x01);
    wdelay(1);
        
    ds=(s-os);
    itoa((int)ds,ss,10);
    lcdCmd(0xc0);
    while(ss[l]) lcdDate(ss[l++]); 
 wdelay(3000);   
}

вот результат, причем идея  передать в одной посылке может еще немного ускорить, ровно на 25%. Но оно и так в два раза быстрее.

прошу прощения за lcdDate() вместо lcdData(). Я - знаю как правильно ;), просто был поздний вечер и я был пьяноват... а править потом слишком много...

Arhat109-2
Offline
Зарегистрирован: 24.09.2015

Ни чё не понял пока что из написанного, кроме того что вы были пьяны.

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

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

Читайте - вам полезно будет.  Если кратко то:

1. В вашем коде была ошибка. при объявлении переменной timer0_hook_run  не стоял волатиль. Поэтому и не компилировалось. Диагностика и Ваш код в сообщении 28.

2. Ваш драйвер лсд в два раза медленнее.

Logik
Offline
Зарегистрирован: 05.08.2014

Посмотрел с любопытством. Да, "но два раза, есть два раза" ;) И это притом что первый как бы 800КГц, а второй - ленивая 100 )) Сделайте прямую работу с портом, и если экрану действительно ненужны задержки получится еще раз в 8 быстрей. А еще лучше - выкиньте этот дурноватый экран и  забыть про эти полубайты навсегда.

В свое время я Arhat109-2-у много писал про безсмысленную неэфективность апаратного i2c на прерываниях на 800КГц, а он мне - "неблокирующий, неблокирующий". Туева хуча издержек на организацию и обслуживание прерываний не спрячется в интегральном тесте. Вот оно и прорявляется. Ну понятно и отправка 6 байтов вместо 3-х тоже, но былабы скорость высокой, то такого не было бы.  

Arhat109-2
Offline
Зарегистрирован: 24.09.2015

1. Насчет ошибки: посмотрю, но у меня компилируется и собирается корректно, даже без особых варнингов .. как такое "бывает"? :)

2. Вы в моем коду убрали задержку в 4мсек на отправку КАЖДОГО символа или это с такой задержкой "в 2 раза медленнее"?

Логику: неблокирующий I2C из прерывания, работающий на большей частоте не приведет к ускорению работы основного цикла loop() .. ни при каком коде, в котором стоят delay() внутри loop() а только "разгрузят" процессор в виде меньшей занимаемой доли обработчиком. Это, конечно же очень сложная для осознания мысля и похоже не только для Вас.

Специально, для тех кто не умеет читать: пост №14, строка кода №4 указана задержка в 5(ПЯТЬ) миллисекунд на вывод КАЖДОГО символа.

Arhat109-2
Offline
Зарегистрирован: 24.09.2015

И после такого "теста" вы удивляетесь почему я больше ничего не обновляю и не выкладываю?!? Кому? Зачем? :)

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

Вы, Архат, удивительная комбинация понтов и амбиций!

Я никогда не писал, что Ваш код для аппататного и2с - плохой. Напротив - он очень хорош.

--------------------

"Наехал", если так можно выразиться, я только за на то, что Вы безответственно влезли, со своим arhat.h, в разговор вообще на другую тему. Это была отвратительная и навязчивая самореклама, с Вашей стороны. За что и получили.

------------------------

Теперь по делу: из Вашей поделки можно сделать нечто путное, если подойти правильно.

1. нужно проверить и исправить ошибки, типа указанной. У Вас компилировался пример, вероятно использующий эти Ваши хуки, а в случае Вашего же примера lcd1602, оптимизатор выкинул ненужное, на его взгляд. Чтобы он этого не делал есть волатиль.

Вы, правда, не в состоянии поставить на чистую машину IDE, скачать свой arhat.h и попробовать скомпилить пример для лсд1602? Удивительное нежелание видеть и признавать свои косяки.

2. Вы, как мне кажется, хоть и глубоко увлеклись Атмегой, но среду Ардуино знаете не очень хорошо. В Вашем случае, если не подходит типовой wiring.c нужно сделать СВОЕ ЯДРО, в виде отдельной "платформы". Тогда в среде можно будет выбирать ПЛАТУ, например "arhat-mega2560" или "arhat-nano328". И Ваш код внести прямо в ядро, не сверху, а ВМЕСТО wiring. Тогда он линковаться будет правильно - только нужные модули, а не как сейчас - все объектники проекта.

3. поскольку много интересного в Вашей разработки есть, я могу помочь. Тогда Ваша личная игрушка может преврятиться в нормальный инструмент, удобно интегрируемый в IDE, не требующий странных переименований (кстати - не нужно, и так все собирается). Платформы устанавливаются, как и либы в пользовательский каталог. Изменить можно вообще все. Сохранив, а не переписывая, те веши, которые менять не обязательно.

4. и это очень логично: другая платформа, специально для многопоточного программирования - один "архат-проект" и библиотеки, уже ПОД ЭТУ платформу, там, где не подойдут (или не нравятся) стандартные - другой "архат-проект". Думайте.

Arhat109-2
Offline
Зарегистрирован: 24.09.2015

Указанная вами "ошибка" во-первых у меня не воспроизводится, поэтому колитесь как вы дожили до такого. Ибо объявление переменной как внешняя в хидерах и её определение в С-файлах - явление чуть более чем нормальное. Хидер (и этот тоже!) используются много где, и его включение в его же "родной" с-файл - вполне обыденное явление. Или покажите где в стандарте такое запрещено явно. В отличии от многих тут, я не боюсь сесть в лужу и признать свою ошибку. Я вам УЖЕ отписал что и как сделал. Вот вам ещё скриншот с домашнего компа, плата выбрана Ардуино нано, версия ИДЕ 1.6.4:

Надеюсь хорошо видно, что ошибка НЕ воспроизводится и пример выкачан с гитхаба? :)

Ежели вчё, то у меня и уже давно работает совсем другая версия arhat.h, в которой номера пинов задаются структурой из пары значений "порт, маска" (обсуждалось тут раньше и даже кое-кто у кого действительно страдает ЧСВ обещался "сделать")... поэтому и выкачивал с гитхаба.

Собственно, ваше предложение .. оно было бы интересно с год назад, ну может с полгода. В то время, когда я действительно по-поводу и без выкладывал эту поделку в надежде найти сообщников и запилить полноценный wiring++. Больше того! В то время (версии 1.6.7), я даже писал письмо ардуинщикам, предлагая им сделать полноценную автоматную версию для Мега2560 с тем, чтобы они допилили на другие платы и включили это как новую версию своего wiring .. увы.

Ответа я не получил до сих пор.

Учитывая все вышеизложенное .. не знаю "стоит ли" заниматься этой фигней. Я уже сильно не верю что это "кому-то надо". Да и Ардуино ИДЕ у нас уже практически не используется..

Если Вам интересно, то можно собраться толпой и сделать полноценный ИС "ДРАКОН" с компиляцией скетчей в С/С++ и вот для него уже можно запилить хорошую автоматную библиотеку. Тогда можно получить с одной стороны, наглядность и простоту визуального программирования для детишек, с другой стороны легкий и компактный код не хуже Атмел Студии для типовых применений, а с третьей - сразу приучать детишек к хорошему - конечным автоматам и программированию "без delay()".

Но .. опять жеж. Ежели учесть время жизни камней и сколько УЖЕ оно живет и требуемый срок для разработки и то, что Атмел куплен .. а стоит ли? :) Да и платы сами по себе скажем прямо у Ардуино далеко "не айс" .. чем больше ковыряюсь с дитенком, тем больше растет желание перепроектировать и плату Мега 2560.. дерьмо ещё то.

 

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

ради смеха - напишите версию avr-gcc, есть у меня сведения некие....сможет и неправда, про оптимизатор... версию напишите - тогда скажу какие.

2. К дракону у меня изначальное неприятие, сорри. Какое-то любительство, но это ИМХО.

Arhat109-2
Offline
Зарегистрирован: 24.09.2015

avr-gcc -v: версия 4.8.1

Зря. У него есть существенный недостаток - отсутствие существенной части: языка описания данных (DDL), но мне кажется это можно поправить по примеру Ардублока.

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

Писал народ про то,что с 4.9 опять оптимизатор стал выбрасывать переменные без волатиля и даже функции, без атрибут (юзед).

Arhat109-2
Offline
Зарегистрирован: 24.09.2015

А при чем тут "оптимизатор"? Включенный arhat.h при компиляции модуля arhat.c создает как-бы "единый файл компиляции", ибо включение происходит ДО компилятора - в препроцессоре. И, тут он сначала натыкается на ОБЪЯВЛЕНИЕ переменной как "внешней" (extern xxx), и помечает это место как "находящееся где-то ишо" - во внешнюю таблицу ссылок, а потом обнаруживает ОПРЕДЕЛЕНИЕ переменной, и ЗАПОЛНЯЕТ в таблице ссылок указанный пропуск. Всё. И только потом включается "оптимизатор" и может выбросить то, что по его мнению не требуется.

В данном конкретном случае, конкретно эта переменная ИСПОЛЬЗУЕТСЯ внутри обработчика прерывания от таймера, того самого, который считает время так любимого всеми millis() и, соответсвтенно НИКАКОЙ оптимизатор её выбросить из кода не в состоянии, даже без указания volatile ибо она внутри обработчика играет роль флага, то бишь изменяется "туда-сюда" в зависимости от .. volatile переменной. Упс, приехали.

Чтобы её "выбросить" надо в файле arhat.c переключить режим компиляции с 3 на 2 или вовсе закомментарить этот #define .. об чем там и написано (дабы я сам и не забыл тоже)..

А вот то, что у Вас компоновщик (заметьте, а не компилятор) заругался - есть некая странность в опциях настройки его работы .. про что и спросил "как Вы дошли до такой жизни" .. в общем, колитесь. :)

Arhat109-2
Offline
Зарегистрирован: 24.09.2015

Кстати, на вашем скрине тест моего варианта показал 5517 .. только сейчас сложилось .. там жеж 5 мсек пауза, а цикл из 100 символов! Итого, ежели паузы выкинуть моглибы поиметь 5517 - 5(мсек)*100(раз)*(10(симв)+1(команда)) = 5517 - 500*11 = ... упс 17мсек.

И это вы назвали ПЛОХИМ РЕЗУЛЬТАТОМ?!? :)))

Logik
Offline
Зарегистрирован: 05.08.2014

Arhat109-2 пишет:

Кстати, на вашем скрине тест моего варианта показал 5517 .. только сейчас сложилось .. там жеж 5 мсек пауза, а цикл из 100 символов! Итого, ежели паузы выкинуть моглибы поиметь 5517 - 5(мсек)*100(раз)*(10(симв)+1(команда)) = 5517 - 500*11 = ... упс 17мсек.

И это вы назвали ПЛОХИМ РЕЗУЛЬТАТОМ?!? :)))

))) Хороше хоть в минус не насчитали. Можем признать вашу реализацию самой быстрой по результатам подтасовки ))))

А факты мы видели на экране. Зачем же Вы ускорили, перейдя на 800КГц и тутже сами замедлили делеем? Неведаете что творите? Теперь как теоретически должен выглядеть вывод на экран не требующий пауз 100 строк по 10 символов при 6 байтах на символ и скорости 800КГц 100*10*6*10 бит на символ)/800000=75мсек. Не 5500!! а 70 раз быстрей. И разумеется 17мсек там не может быть никак.

Теперь к практике. Решил и я этот тестик поганять, самому посмотреть и людям показать как выглядит обмен на 800КГц.

Исходник, несколько адаптирован, но это может только замедлить.


#include "SSD1306.h"

#define OLED_SCL_PIN A1
#define OLED_SDA_PIN A0

ssd1306_i2c(OLED_SCL_PIN, OLED_SDA_PIN, myOLED) ;


void setup(void)

{
  myOLED.begin();
  myOLED.clrScr();
  myOLED.setFont( SSD1306::FONT_SIZE_1); 
  myOLED.drawString(0,1,"Hello, Arhat!");
}



void loop()  {
char* s="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
//const char *s=(char *)"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
char ss[11] = "          ";
uint32_t  m,om;
int l=0;

delay(300);


    myOLED.drawString(0,1,"                ");

om=millis();
for (int j=0; j< 100; j++){

  char r=s[(j%25)+10];
  s[(j%25)+10]=0;
  myOLED.drawString(0,0,s+(j%25));
  s[(j%25)+10]=r;
  }

  m=millis()-om;

  itoa((int)m,ss,10);
  myOLED.drawString(0,1,ss);


}

 

Тест по сути тотже только  5 байт на символ. Плюс 15 байт на каждую строку. Теория дает 81мсек, реализация дала 124мсек, что очень хороше со всех сторон. Как видим везде нормальные цифры, никаких 5 сек (как и 17мсек тоже))) нигде нет, кроме реализации Arhat109-2. Причина проста - его криворукость и тупость как разработчика и упрямство и закостенелость мышления как собеседника. Ну и конечно его ничего не останавливает публиковать и рекламировать свой хлам.

У Вас, wdrakula, тоже выйдут цифры, схожие с моими после перехода с 100 на 800 (это даст сразу ускорение гдето до 300мсек), перехода на прямую работу с портами ну и небольшой оптимизации.

Клапауций 232
Offline
Зарегистрирован: 05.04.2016

Logik пишет:

Теперь к практике. Решил и я этот тестик поганять, самому посмотреть и людям показать как выглядит обмен на 800КГц.

подожди - речь же идёт об экране 1602 через LiquidCrystal_I2C

или, это не принципиально?

*по достижении определённой скорости на 1602 проблема не в передаче данных, а в отрисовке пикселей - не успевают.

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

1. про скорость. С 0 в задержке не работает, с 1 - 1118 на 100 символов при 800 в установках. Это очень хороший результат.

2. Про ошибки: Вы перестаньте финтить. Вы забыли волатиль поставить и пытаетесь выкрутиться - зачем? Ошибка исправлена, денег не прошу.

Или Вы не согласны, что забыли волатиль? 

Конкретно на 1.6.11, под Линух Минт 17 - не собирается. Ошибку - вы видели. Объявление было в "дискардед" секшн. То есть секция, в которой было определение имени - "отброшена".

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

А то, что разные версии компилятора по разному себя ведут, это и раньше было известно. Моя версия выявила ошибку, это только радость должно вызывать, как мне кажется. А не желание выкрутиться обвиняя меня в хитрой перестройке среды. Голая среда, спецом поставлена. В нее влито куча доп платформ (есп, тинька, дигиспарк, я ж с ними со всеми работаю, только арм пока не купил. И все последние обновления).

Я ... среду знаю очень хорошо, и пользуюсь ею, как органайзером проектов. Мне - удобно. Просто как надстройка над GCC. Я знаю, что она добавит с проет и что не добавит. Студии под Линух нет, Еклипс - это монстр. Просто текст редактор - менее удобен, чем среда. Нужно будет среду из исходников пересобрать, чтобы в проекте тип платформы помнила, этого очень не хватает, так как я по 10 разных платформ за сеанс работы проверять могу.

Советую гугль на слова из диагностики, там и найдете про avr-gcc 4.7, 4.8, 4.9, у них в этом и разница. На 4.8 ошибка как раз не должна проявляться.

Logik
Offline
Зарегистрирован: 05.08.2014

Если 1602 не требует пауз при обмене и поддерживает 800КГц то принципиальные различия исчезают. Остаются мелочи 5 байт на символ у одного и 6 (или 7 или 3 - я так четко из темы и не уяснил) у другого.

Logik
Offline
Зарегистрирован: 05.08.2014

wdrakula пишет:

1. про скорость. С 0 в задержке не работает, с 1 - 1118 на 100 символов при 800 в установках. Это очень хороший результат.

Согласен , если нужна пауза 1 на символ то, 1мсек на 100*10 символов и даст 1000, а чистого времени 118мсек, что соответствует изложеному.

Logik
Offline
Зарегистрирован: 05.08.2014

Я думаю теперь andriano, должен быть удовлетворен подробным развернутым ответом на свой вопрос по теме )))

Клапауций 232
Offline
Зарегистрирован: 05.04.2016

Logik пишет:

Если 1602 не требует пауз при обмене и поддерживает 800КГц то принципиальные различия исчезают. Остаются мелочи 5 байт на символ у одного и 6 (или 7 или 3 - я так четко из темы и не уяснил) у другого.

я о субъективном восприятии - если запустить, например, lcd.print("asdfghj"); в лупе, то при подключении напрямую кроме мелькающих пикселей ничего не увидишь, поэтому странно слышать вопрос:

andriano пишет:

Интересно, можно ли каким-либо способом (не обязательно через I2C) заставить работать контроллер с временами существенно лучшими, чем гарантирует дэйташит?

Ну и, на худой конец, кто-нибудь пробовал довести скорость обмена с дисплеем хотя бы до порядка величин, гарантируемых дэйташитом (т.е. раз в 17-19 быстрее тех, что по умолчанию)?

складывается впечатление, что ТС никогда не юзал ничего кроме I2C

Arhat109-2
Offline
Зарегистрирован: 24.09.2015

Wdrakula, Вы точно нашли ошибку? Если это так, то я конечно рад за вас. Никогда не думал что разброс версий компиляторов является ошибкой. Но .. хотите поправить - пожалуйста. Если ещё остались сомнения, то я вас разачарую: эта версия arhat.h мною уже давно не поддерживается ибо незачем. Там, где она пользуется - там все нормально работает и уже давно развивается и сопровождается без меня. У меня - уже не используется, мне это - уже не интересно.

Logik, я рад за вас что Вы нашли для себя повод обосрать меня на этом форуме. На большее вы все одно - не способны. И да, вы в этом стремлении тут не одиноки. Лечите свое ЧСВ хотя бы таким способом, надеюсь что помогло.

Клапауций 232
Offline
Зарегистрирован: 05.04.2016

Arhat109-2 пишет:

Logik, я рад за вас что Вы нашли для себя повод обосрать меня на этом форуме. На большее вы все одно - не способны. И да, вы в этом стремлении тут не одиноки. Лечите свое ЧСВ хотя бы таким способом, надеюсь что помогло.

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

реквизит предоставляется бесплатно.

*обращаться в личку.