Архат! Мне, правда, неловко спрашивать, но Вы точно не баба? Ровно, как в той памятной истории про преобразование к int. Это очень по-женски - ни-за-что не признать косяк... смешно, право-слово.
Ладно... тема полностью исчерпана. Было и правда интересно. Пределы скорости lcd1602 с i2c регистром PCF8574 мы определили весьма точно. Больше не выжать.
На самом деле - вот ради таких тем и нужен форум, а не новичкам про диод и мосфет объяснять. ИМХО.
Ладно... тема полностью исчерпана. Было и правда интересно. Пределы скорости lcd1602 с i2c регистром PCF8574 мы определили весьма точно. Больше не выжать.
Замечательно.
Я, правда, из-за периодической путаницы милисекунд с микросекундами и кучи вообще безразмерных цифр общего порядка не уловил.
Точнее, не уверен, что уловил.
Если я правильно понял, предел составляет где-то 120 мкс на символ на скорости 800, это так?
Wdrakula, вы все уже достали читать по диагоналям. Ещё раз: косяки и расхождения версий реализаций компиляторов, а равно объявленные "фичами" в стандартах против полноценно строгого описания а-ля Алгол-68 или Ада - я НЕ СЧИТАЮ ОШИБКАМИ программистов. Да, их НАДО учитывать и, тот кто этого не сделал - ошибся. В этом плане я свою ошибку признал и там и тут отписал уже: "если Вы считаете это ошибкой". Но все что в библиотеке написано - сделано СОЗНАТЕЛЬНО. И, если оно "где-то не работает" это проблема того самого "где-то", ибо библиотека НЕ АДАПТИРОВАЛАСЬ к различным версиям плат, компиляторов и т.д и т.п. Тот кому требуется адаптация вполне способен сделать её САМОСТОЯТЕЛЬНО (ибо писано не для идиотов). Библиотека писалась для вполне конкретного применения на конкретном камне - Atmega2560 и его клонов, слегка адаптирована к ATmega328p и его клонам. Но только "слегка".
Это - моя позиция как программиста этой библиотеки. Причем тут ваши всхлипывания про баб, не могу понять вот никак.
Andriano, не удивительно что Вы ничего не поняли. Остальные участники точно столько же "не поняли", просто "сделали вид". Давайте подведу "итоги":
1. На какой конкретно частоте способен работать I2C у PCF8574 - тут НЕ ВЫЯСНЕНО, ибо I2C-slave способен тормозить шину для обеспечения нужной ЕМУ скорости. То, что Мега-мастер спосоден И пытается отдавать на 800кгц - да, может .. но, в общем-то, "ни о чем". Тут эта сторона вопроса не выяснялась и вовсе.
2. LCD1602 способен принимать свои полубайты - БЫСТРО. Так быстро как может PCF8574, но только на 1 символ. Соответственно, правильная работа с этим экраном по I2C - это отправка пачкой обоих полубайт, для каждого из которых требуется отправить 3 байта в PCF8574 и это МОЖНО СДЕЛАТЬ ОДНОЙ ПОСЫЛКОЙ. Это самый быстрый способ работы с этим дисплеем. Wiring так не умеет.
3. Задержка отрисовки одного символа на моем дисплее составляет 4.1мсек или 4100 микросекунд. Это та пауза, которую Вы обязаны обеспечить если хотите прочитать отправленное на экране. В даташите на МК дисплея указано 37 микросекунд - это теоретический миниум .. у меня такое НЕ РАБОТАЕТ, но возможно вам повезло.. вот у Wdrakula он явно реагирует шустрее ..
4. Поскольку сам дисплей "экранирован" чипом PCF8574, то способа "узнать" готов ли дисплей принять следующий символ у вас практически нет. Паузу вы должны отрабатывать самостоятельно. Можно в лоб delay() как в моем примере, можно через прерывания по таймеру, можно ещё 100500 разными способами. Зависит от вашей программы, знаний, умений и навыков. Тут возможно есть способ "задрочить" PCF8574 так, чтобы можно было и читать 1 ногу дисплея .. но я этого не пробовал.
5. Скорости работы моего теста для 100х10 символов + позиционирование курсора (отправка +1 команды на каждые 10 символов): Время выдерживания паузы между посылками = 5500мсек; Время подготовки данных для отправки = 17мсек; Время отправки данных - НЕ ИЗМЕРЯЛОСЬ ибо проводилось через прерывания в процессе отработки паузы. Теоретическое время отправки подсчитано Logik-ом = 70мсек. для 800кГц, но поскольку реальная скорость интерфейса тут не замерялась вовсе - то неизвестно.
Собственно, 5500-70 = 5430мсек - это то время, которое ваш скетч способен потратить на свое усмотрение пока дисплей рисует символ. На каждый символ. В отличии от прямого способа отправки ногодрыгом у Wdrakula или Logik.
В Даташите указано время отрисовки символа действительно в микросекундах, но на самом деле он отрисовывает символ за 4.1 миллисекунды или 4100 микросекунд. И преодолеть этот барьер - никак. Интерфейс вполне способен работать на частотах мастера в 800кгц: сам мастер - позволяет, а слейв может в любой момент притормозить прием до приемлемой для себя скорости. И расходы на передачу, в сравнении с временем отклика - невелики. В даташите на дисплей и вовсе указано что принимать он может на скоростях аж до 1..2Мгц .. там характерные времена сигналов - 250..500 наносекунд. Только "толку-то"?
800кгц = 1.25 микросекунды на передачу 1 бита. * 9 бит * 7 байт (6+адрес) = 78,75мксек на посылку. Тест отправляет 100х(10+1) посылок 78.75 *1100 = 86625 мксек или 86.6мсек .. Logik давал цифирьку в 70. Это более точный расчет работы по прерываниям.
Собственно, 5500-70 = 5430мсек - это то время, которое ваш скетч способен потратить на свое усмотрение пока дисплей рисует символ. На каждый символ. В отличии от прямого способа отправки ногодрыгом у Wdrakula или Logik.
реализовано "скетч способен потратить на свое усмотрение"?
Особенно учитывая что функции lcd... у Вас блокирующие! Несмотря на то, что под ними неблокирующие лежат. И зачем они там? )))) И весь выиграш ,о котором Вы пишите, в этих блокирующих lcd.. и седается )))
А теперь к вопросу почму они у Вас блокирующие. Потому что если сделать их неблокирующими, то возникнет проблема хранения информуции о типе вызова и параметрах (назовем это контекст) в промежутке времени между вызовом функциии lcd.. и фактическим выводом на экран. Теперь обратим внимание на то, что взовы lcd.. могут ити подряд и много, какраз как в нашем примере, и станет ясно что контекст нужно хранить в очереди и её размер вобщем то не ограничен какими либо разумными доводами. Вот и получим сотни байт ОЗУ (а если экран графический то и тысячи и даже сотни тысяч байт) и издержки на работу с очередью контекста (а там потребуется синхронизация её использования из прерывания и основного потока, и комуто из них прийдется ждать пока другой загружает/выгребает контекст). Что в сумме окажется хуже чем прямой вывод. И по скорости и по ОЗУ и по сложности реализации.
Так то вот!
ПС. Постарайтесь понять написаное выше, несмотря на свои эмоции и гордыню. У Вас банальный неверный выбор архитектуры, непродуманый подход.
Перечитайте всё что было написано выше и в предыдущих постах. Там есть все ответы на ваши "гениальные догадки" и не пишите дальше свой фантастический бред. Метать бисер перед недоучками у меня желание уже давно пропало. Уж извините, но достали со своей непроходимой тупостью.
P.S. Тема в том ракусе что была поднята - исчерпана чуть более чем полностью. А поддерживать ваш срач - у меня нет никакого желания. За сим, таки откланяюсь тут. Разбирайтесь, перечитывайте .. всё есть.
1. Logik, писал: "Как в нашем коде, вот этом - ... реализовано "скетч способен потратить на свое усмотрение"? "
Ответ: это НЕ МОЙ код, а Wdrakula, который решил проверить скорость отрисовки ваще-то. Конечно в нем - НИКАК. Но это же не "весь код применения", так ведь? :)
2. Logik, писал: "Особенно учитывая что функции lcd... у Вас блокирующие! "
Ответ: Если Вы откроете lcd1602.h из библиотеки, то сможете обнаружить что все функции lcd..() по большей части являются макроопределениями, которые в конечном счете вызывают единственную функцию lcdSend(), которая в свою очередь вызывает twiWrite(), которая .. упс НЕ ЯВЛЯЕТСЯ блокирующей даже с включенным delay() в lcdSend()? а тупо устанавливает область и размер передачи и запускает обработчик прерывания. :)
Синхронность обработчика прерывания и основного потока здесь обеспечивается только большой задержкой в lcdSend(), которая гарантирует что к моменту повторного вызова lcdSend() не только закончится предыдущая передача, но и дисплей уже отрисует символ. И это - никак НЕ блокирующая работа, заметьте.
Да, и про это было сразу сказано в посту №17, последним предложением, но .. Вы похоже его не читали.
3. Logik писал: "Несмотря на то, что под ними неблокирующие лежат. И зачем они там?"
Ответ: Вы были просто невнимательны. Весь тест Wdrakula, работает НЕБЛОКИРУЮЩЕ. Об чем вам и было посоветовано: перечитайте. а вы .. "не буду" .. прямо как дите малое.
4. Logik писал: "И весь выиграш ,о котором Вы пишите, в этих блокирующих lcd.. и седается )))"
Ответ: нет. Весь выигрыш тут съедается оператором delay() внутри lcdSend(). Это легко поправить для конкретного применения. Разъяснение дано выше.
5. Logik писал: "А теперь к вопросу почму они у Вас блокирующие." и далее весь остальной бред из-за "читать не буду"
Они НЕБЛОКИРУЮЩИЕ. Перечитайте. Они даже в этом тесте работают НЕБЛОКИРУЮЩЕ. :)
6. Logik писал: "то возникнет проблема хранения информуции о типе вызова и параметрах (назовем это контекст) в промежутке времени между вызовом функциии lcd.."
Ответ: это вовсе необязательно. Необходимо и достаточно иметь признак (1 бит/байт) завершен ли предыдущий вызов вывода на дисплей и соответствующие проверки в коде "если дисплей ещё занят, то ..". Обычное автоматное программирование.
Ну и процитирую вас же:
ПС. Постарайтесь понять написаное выше, несмотря на свои эмоции и гордыню. У Вас банальный неверный выбор архитектуры, непродуманый подход.
Разумеется не Ваш )) Вы здесь не одни. Выделю жирным может так просчитаете верно. "Как в нашем коде"
2. Logik, писал: "Особенно учитывая что функции lcd... у Вас блокирующие! "
Arhat109-2 пишет:
Синхронность обработчика прерывания и основного потока здесь обеспечивается только большой задержкой в lcdSend(), которая гарантирует что к моменту повторного вызова lcdSend() не только закончится предыдущая передача, но и дисплей уже отрисует символ.
Вы конечно можете черное белым называть сколько угодно, даже большими буквами, но выполнение лупа заблокировано до момента когда "закончится предыдущая передача". Это типичный блокирующий код. Причем кривой как турецкая сабля, за синзронизацию выполнения потоков (основног и прерывания) на основе ожидания. Разрабам за такое дают по рукам. т.к. либо будет ждать лишнего либо может недождатся. А еще и с делеем - нет слов, уровень новичка которого посылают на блинкбезделея. Позорище.
Arhat109-2 пишет:
. Весь выигрыш тут съедается оператором delay().
Наконец признали очевидное.
Arhat109-2 пишет:
. Это легко поправить для конкретного применения. Разъяснение дано выше.
Костыль костылем всегда поправится. Про все хороше будет в новой версии уже слышали
Arhat109-2 пишет:
Ответ: это вовсе необязательно. Необходимо и достаточно иметь признак (1 бит/байт) завершен ли предыдущий вызов вывода на дисплей и соответствующие проверки в коде "если дисплей ещё занят, то ..". Обычное автоматное программирование.
Вот это и была бы неблокирующая реализация. Но Вы как всегда не хотите продумывать последствия.
1. автоматное програмирование, в котором каждый вызов lcd... отдельное состояние - это мрак.
2. при таком подходе в реальном приложении скорость вывода еще ниже окажется, т.к. основной цикл совсем не обязательно прокрутится за 5мсек, там как повезет может 4, может 20 а то и 100. И все отклонения будут означать простой вывода и снижение скорости.
3. Вывод на экран начнет мигать малопредсказуемо, т.к. периодически попадающие паузы вывода в десятки и сотни мсек будут просто видны.
Но вы делайте, делайте, потом еще поржем и мокнем.
У Вас банальный неверный выбор архитектуры, непродуманый подход.
"Не ругайтесь, девочки!"(с) ))))))))
Берите правильную архитектуру, тулите полный буфер, заводите хардварный вывод и вопрос отпадёт сам собой. Это ж просто красота! Меняем буфер дисплея когда хотим, запускаем обновление экрана дисплея когда хотим. А вы тут со своими поднадоевшими микро и миллисекундами. Срамота! )))))))
Окей, пусть будет " в нашем коде", тоже оказался невнимателен.
Вы конечно можете черное белым называть сколько угодно, даже выделять жирным, но покажите где выполнение лупа заблокировано до момента когда "закончится предыдущая передача"? Именно до этого момента. :)
Logik, писал: "А еще и с делеем - нет слов, уровень новичка которого посылают на блинкбезделея. Позорище."
Вы наивны как дитё. Это - пример, и написан он был вовсе не для демонстрации работы с дисплеем, а как пример реализации работы с моим twi интерфейсом. Пример как раз для тех, кто пользуется делеем. Кстати, неблокирующее исполнение delay() есть в wiring .. функция yield() кажется так. Ознакомьтесь, иногда тоже полезна.
Но, в целом почти разобрались, уже лучше.
Самый простой неблокирующий подход тут - использование функции yield() для выполнения кода во время отработки паузы отрисовки. В моем delay() её нет, но никто не мешает дополнить. Этим легко и ненапряжно опровергается ваше утверждение про "блокирующую" работу теста, а заодно и все ваши попытки хамить от незнаний. Осваивайте, это просто один из 100500 способов как использовать время ожидания.
Кажется дошло. У вас неверное понимание "блокирующего" и "неблокирующего" кода. попробую помочь:
Любое последовательное исполнение - есть "блокирующий" код для всех последующих команд. Так например:
A=B+C*3 // разворачивается у компилятора в последовательность:
A=C; // тут сложение блокировано умножением
A=C*3; // и реализовать его "до" завершения умножения никак нельзя
A=A+B;
// аналогично вывод:
print("ABC")
// в конечном счете при выполнении будет выглядеть так:
print("A");
print("B");
print("C");
// и выполнить вывод символа "С" не представляется возможным
// ранее вывода "B" и "A"
// это последовательное или блокирующее исполнение. Согласны?
Теперь смотрим на наш тест и видим, что ничего, кроме вывода строк символов он не делает, соответственно сам по себе тест является последовательным или блокирующим исполнением. Нельзя вывести второй символ ранее, чем выведен первый. Нельзя вывести следующую строку раньше чем выведена предыдущая. Согласны?
А вот давайте теперь посмотрим как происходит сам вывод И отправка данных в дисплей по I2C:
// пост №29:
for (int j=0; j< 500; j++)
{
lcdSetCursor( 0,0 ); // отправка команды (1 посылка)
lcdWrite( s+(j%25), 10 ); // отправка 10 символов (10 посылок)
}
// Разворачивая вызовы (см. пост №14), получаем для тела цикла:
lcdPrepare(LCD_SHOW_RAM, 0); // lcdsetCursor() -> lcdCommnad()
twiWrite(0x27, lcdBuffer, 6); // .. lcdSend()
delay(LCD_WAIT_1);
twiMode |= TWI_SEND_STOP; // lcdWrite()
while(10--) // тут длина строки
{
lcdPrepare( *b++, 0); // .. lcdWrite1()
twiWrite(0x27, lcdBuffer, 6); // .. .. lcdSend()
delay(LCD_WAIT_1);
}
Обратите внимание, что строго последовательная задача посимвольного ВЫВОДА решена строго последовательно. А вот сам "вывод данных" делается неблокирующее: через запуск автомата I2C функцией twiWrite(), которая .. ничего не ждет а тупо запускает автомат, если он свободен. Соответственно, Вы ошибаетесь и не единожды, повторяя "вывод на дисплей - блокирующий". Нет, работа интерфейса I2C, которая тут и есть "вывод на дисплей" - делается не блокирующее а "параллельно" с основным циклом.
Ну и напоследок, пример использования этой части библиотеки моим сыном, осваивайте:
/**
* Замена для delay() -- вызывает опрос датчиков линии и главный мозг робота
* пока идет отрисовка текущих параметров на экран
* getSensors() -- получает и усредняет датчики "бегущим средним" по 20шт - папина
* brain() -- мой главный мозг моего робота запускается каждые 2 милисек!
*/
#define delay(vrema) \
{ \
static uint8_t t = (uint8_t)millis(); \
while( (uint8_t)millis() - t < ((uint8_t)vrema ) \
{ \
getSensors(); \
brain(); \
} \
}
#include "lcd1602.h"
Уж не помню, с рабочей версии стащил или какой .. осваивайте "неблокирующую работу с дисплеем.
P.S. Забыл указать, что в loop() есть вызов WriteAll() -- функция которая периодически обновляет показания и состояния автоматов на дисплее. Ну и конечно же как и положено, все реализовано на широком применении глобалов. :)
Такой подход позволил ему видеть онлайн как реагирует робот на изменение обстановки при движении по линии на двух датчиках: верхняя строка дисплея показывала левый и правый датчики, а на нижней выводились скорости моторов. В правой части экрана на 2-х строках рисовался "символ" - решение мозга "куда едем" псевдографикой.
"В информатике асинхронный ввод/вывод, или неблокирующий ввод/вывод является формой обработки ввода/вывода, который позволяет другим процессам продолжить выполнение до того, какпередача будет завершена."
Т.е. в нашем случае lcd... должен завершаются до окончания вывода на экран, и существенно ранше. И независимо от того, что там выводится от предыдущих вызовов. Это принципиально возможно, но сложно, я выше писал как.
Arhat109-2 пишет:
Нельзя вывести следующую строку раньше чем выведена предыдущая. Согласны?
Нет. На уровне вызовов это возможно lcd.., если работа неблокирующая асинхронная. Как будет разгребатся это Ваша либа - Ваши проблемы. Пользователям либы об этом знать не нужно. И не надо тут левый код постить, разварачивать как в либе, он не интересен никому. Я и так понимаю лучше Вас с какими проблемами Вы там сталкиваетесь, даже знаю как их решать и что это в конце концов тупик. Тест вывода, аналогичный сделаным еще может гляну. А тем более постить откровенное шопопало:
/**
* Замена для delay() -- вызывает опрос датчиков линии и главный мозг робота
* пока идет отрисовка текущих параметров на экран
* getSensors() -- получает и усредняет датчики "бегущим средним" по 20шт - папина
* brain() -- мой главный мозг моего робота запускается каждые 2 милисек!
*/
#define delay(vrema) \
{ \
static uint8_t t = (uint8_t)millis(); \
while( (uint8_t)millis() - t < ((uint8_t)vrema ) \
{ \
getSensors(); \
brain(); \
} \
}
#include "lcd1602.h"
Где в этом коде вобще работа с экраном? Постите хуйню, в расчете что всем будет пофиг и зачтется? Вы в натуре - баба? Биологическая или так просто, по жизни?
Вы в натуре - баба? Биологическая или так просто, по жизни?
Я уже спрашивал... он ушел от ответа ;) ;) ;)...
------------------------
Да, к теме, а не к дерьму на вентиляторе, хотел добавить:
Я довел софварный вариант до 720 мс на 1000 символов. Но вот в чем прикол: получается, что PCF8574, все таки, не держит более 100 МГц. Странно, но я проверил код Архата. Он действительно устанавливает 800КГц в регистры. Нужно посмотреть осцилом, Я сам пока не могу - жду нового ослика с али. В софтовом варианте обмен прекращается на времени удежржания уровня SCL меньше 4.5 мкс.Это не столь важно для жизни, но просто интересно! ЧОрт возьми!
Пипец как достали долбо*бы. Разберись сначала что выложено а потом поливай дерьмом, а не наоборот. Сами как бабы, ничего кроме как обосрать оппонента не умеют, а туда же! Вот уж действительно "метать бисер" .. перед кем?!?
.. афигеть! "он обнаружил" .. обнаружь и все остальное.
Он действительно устанавливает 800КГц в регистры. Нужно посмотреть осцилом,
Я особо и не сомниваюсь, что 800КГц использует. Просто данные идут не непрерывным потоком а с паузами, и эти паузы очень большие. А чтоб обеспечить непрерывный поток надо или буфер большой, т.е. много ОЗУ чего нету или непрерывно и быстро из основного потока получать, а значить основной поток не сможет заниматся другими задачами и просто исчезает смысл всей затеи с аппаратными 800КГц на прерываниях. То что было отличным решением на 100 стало не очень на 800 )))
Arhat109-2 пишет:
ничего кроме как обосрать оппонента не умеют
еще умеем быстрый код писать ;) См. результаты тестов.
Не умеете. Ничего не умеете кроме как срать на форуме и ногордыгами заниматься. Уже проверено неоднократно. Вы даже тут разобраться не способны, митрофанушки.
Какие же Вы, Logik и Wdrakula оба ЗАСРАНЦЫ! Слов нет. Мало того что Ваш тест не компилируется, ибо массив символов должен быть объявлен не в 10, а 11 символов, так ещё и врете. Это тест с другого дисплея (не моего). Задержка LCD_WAIT_1 установлена в 50 МИКРОСЕКУНД с заменой вызова delay() на delayMicroseconds()..
только бабы могут насрать и не извиниться. Ибо Женщина - всегда права. .. какие чмори.. слов нет.
Это - код вашего теста. Исправлена ошибка в размере массива.
Теперь смотрим на наш тест и видим, что ничего, кроме вывода строк символов он не делает, соответственно сам по себе тест является последовательным или блокирующим исполнением. Нельзя вывести второй символ ранее, чем выведен первый. Нельзя вывести следующую строку раньше чем выведена предыдущая. Согласны?
С вашим очередным бредом? Конечно нет! )))))))))))))))
В прерывании или через ДМА можно вывести что угодно и как угодно, хоть символ, хоть строку. Так что сам по себе последовательный код не является блокирующим, он просто выполняет последовательность команд согласно алгоритму, как ему и положено.
Архат! Ты псих совсем или ...нулся? Я давно на твоей библиотеке не 140, а 116 получил. Причесав ее. Я хоть раз писал, что мне твоя библиотека не нравится???? Совсем рехнулся? Пустырнику попей! У меня есть вопросы по релизу аппаратного и2с, но не к тебе, а к производителю. Например держит оно 800 или нет? В даташите написано до 400, потому и хочу осликом посмотреть. Но у тебя - все нормально и правильно, успокойся уже!
-----
Наезд был исключительно за твой тупой апломб и непризнание очевидных ошибок, которые пришлось править самому. Но неблокирующий мастер - очень хорош. Логик спорит о том,что он нахер никому не нужен. Возможно. Но, как чисто програмистская задача, ты написал хороший драйвер и2с.
Пи...дец! Я тебе про это и говорил, когда описывал ситуацию и просил погуглить текст ошибки. А как, по твоему, я про волатиль догадался, если не прочтя вот именно эту ссылку? Только вместо "юзед" для функции я поставил волатиль для переменной. Но это именно ошибка, если более строгий подход оптимизатора ее выявляет. Только мудак, из этой ссылки, считает это багом. Если ты точно считаешь, что оптимизатор не должен трогать твой код, пометь его "волатиль" и "юзед".
Во-первых, сестра перестаньте хамить, тыкать и матерится. Это плохо отражается на внешности.
А во-вторых, освежу вашу "девичью память", ибо Вы конкретно писали это:
1. "Писал народ про то,что с 4.9 опять оптимизатор стал выбрасывать переменные без волатиля и даже функции, без атрибут (юзед)."
2. "Советую гугль на слова из диагностики, там и найдете про avr-gcc 4.7, 4.8, 4.9, у них в этом и разница. На 4.8 ошибка как раз не должна проявляться."
И теперь, найдите в ссылке, указанной мною: "This seems to be a compiler bug that was fixed in gcc-4.7 and reapeared in gcc-4.8 (gcc bugreport for 4.6, reapearance in 4.8). A quick workaround is to mark the function used:", последняя фраза в переводе с нерусского означает:
Быстрый обходной путь
Кроме этого, там же можно найти и номер бага и данные о его всплытии и правках .. Вы не знаете зачем пишут баг-репорты, а особенно что исправляют, что вменили это мне?!? Вы все ещё продолжаете настаивать что это МОЯ ОШИБКА и я был просто обязан применять volatile или used?!?
Окей, продолжим. опция -flto - это указание ЛИНКОВЩИКУ (а не компилятору, как можно подумать исходя из вашей позиции), КАК оптимизировать сборку всего проекта. Так в частности у avr-gcc в хелпе даже прямо сказано:
Options starting with -g, -f, -m, -O, -W, or --param are automatically
passed on to the various sub-processes invoked by avr-gcc.
И у обоих про опцию читаем: "-flto Enable link-time optimization."
Тут точно ТОЧКА. Ибо это - не моя ошибка, как бы Вам не хотелось и не чесалось, барышня.
Да, и перестаньте вилять задним проходом, ибо это тоже писали Вы:
"Вот ты, когда пишешь, на зрителя расчитываешь, или пиздоболишь просто из любви к искусству? У тебя в архат.х "сишным по белому" 6 байт высылаются.", .. "Я н е стану писать про ошибки,ни у всех есть. Но, млядть, пиздобольство раздражает.", .. "Архат! Тупите нарочно? ШЕСТЬ байт + адрес=7, против 12 байт стандартной библиотеки. Это быстрее, но не в три раза.", .. "и перепешите setCursor, стыдно, ей Б..гу! У всех 4-х строк - разные смещения начала. Вы б в даташит взглядывали иногда, что ли.", .. "Вы с утра совершенно охренели??? .. и пойду искать ошибку в Вашем, заметьте, сырье.", .. "То есть Вы написали библиотеку, котора включает в код всякую херню, даже если там ей не место?", .."Вы влезли в разговор о том, как ускорить вывод на экран. Вы, как еще один персонаж на форуме, стали размахивать своим архат.х, с криками о том, что с ним решатся все проблеммы (пройдут прыщи и геморрой втянется сам). Грубого моего намека, что Вы несете чушь, Вы не поняли. Про то, что драйвер ЛСД у вас написан с ошибками - тоже не поняли. На мое прямое замечание, что в 4-х строчных дисплеях начала строк идут не 0 и 0x40, а другие (см. даташит) - Вы слили фразой, что Вас 4-х строчные не интересуют. Вот Вы не баба, после этого?", .. "1. В вашем коде была ошибка. при объявлении переменной timer0_hook_run не стоял волатиль. Поэтому и не компилировалось. Диагностика и Ваш код в сообщении 28. 2. Ваш драйвер лсд в два раза медленнее.", .. "Вы, Архат, удивительная комбинация понтов и амбиций!"
.. мало Вашего хамства и прямых оскорблений в теме, "девушка"? Извиняться - будем?
1.Тыкать или нет, уж прости - сам решать буду. Я, наверняка, старше, если нужно, то я 1969 г.р., а, следовательно буду тыкать.
2. по аглицки читаешь? "seems to be a compiler bug" - значит КАЖЕТСЯ -баг компилятора. В баг репорте читаем про мемсет... ни слова про другой "дискард".
-------------------------
Для гармонии, пусть будет "Вы" ;), не жалко.
Вы добросоветсно перечислили все невежливые мои высказывания. Память - просто восторг! Я в ах...уе, дорогая редакция. Тем не мение, я - вероятно единственный оставшийся программист на форуме, который не считает Вас клоуном и дураком. Наезд был исключительно на абициозное заявление - "применяйте мой драйвер и все будет хорошо". У всех есть и хорошие и плохие идеи и реализации, но: Найдите пример саморекламы у меня или у Евгения, или у Логика и т.д. Вот собственно и все, что нужно знать ...
Кстати, Ваш драйвер давал 5000 мс примерно, я его причесал до 116 мс. Но это уже не совсем Ваш драйвер, не так ли?
Я не собираюсь меряться с вами возрастом, кого это интересует - легко найдет ответ на этот вопрос. В целом, история начинает приобретать четкие очертания, так что - приношу свои извинения, за то что причислил вас к женскому полу, хоть Вы и продолжаете наставивать на "Женщина - всегда права".
Поясню, для читателей:
Я в начале темы порекомендовал использовать свой драйвер, поскольку он полностью решает задачи подобные вопросу автора топика и названия темы.
Этот "спициализд" набросился со своим срачем как базарная баба, сделав вид, что "даже не разбирался". Потом, когда ему я начал объяснять что к чему, он сделал вид что у меня в коде присутствует ошибка, которая как в конце выяснилось и вовсе не ошибка даже, а багрепорт. И все это продолжалось базарным срачем. После чего он же, выложил НЕРАБОТАЮЩИЙ код теста, с синтаксической ошибкой, и некими фотографиями по времени исполнения. То, что ОДНО НЕ СООТВЕТСТВУЕТ ДРУГОМУ, ибо просто не компилируется - ЕСТЬ ФАКТ. И каждый его способен проверить самостоятельно. Все коды выложены тут, в теме. После того, как был разобран тест .. этот "диверсант" ушел молча в кусты и молчал РОВНО ДО ТЕХ ПОР, пока я не выложил свою перепроверку его вранья.
.. далее, этот герой заявил, что он "даже улучшил" мой код и добился якобы 116мсек его исполнения, типа "причесав", но теперь оказывается что "это уже не мой код".. ВО ОНО КАК ОКАЗЫВАЕТСЯ!
Не, батенька, Вы - не баба, извиняюсь. Вы - ДИВЕРСАНТ, который СОЗНАТЕЛЬНО ВРЕТ ДЛЯ СОЗДАНИЯ ИМИДЖА. Вы такой же "искперд" как и те, кто настроил укроаинцев против русских, которым поверили Клапауции, и теперь настраивают нас против амеров и всех против РФ .. ЭТО БЛАГОДАРЯ ТАКИМ КАК ВЫ по миру льется Кровь.
Это то, что меня больше всего возмущает во всей этой теме. И теперь Вы продолжаете вилять задом "я один из тех кто к вам не относится" .. ВРЕТЕ. КРУГОМ ВРЕТЕ. Все ваши утверждения надо перепроверять на 146%.
По существу. После допилинга Arhat109-2 привел скорость работы в разумные пределы, я думаю все Высокие Срущиеся Стороны приймут мысль что показания 140, 124 и 116 мсек можна считать с практической стороны равными. Из этого вывод простой - каким бы способом не производилась бы работа с экраном на i2c при частоте шины 800КГц достижима скорость порядка 50% от максимума.
В чем же состоит допилинг. Самое интересное здесь.
#define LCD_WAIT_1 50 // тиков Т0: 4мксек - мало! (>37мксек пауза на команду "в среднем")
/**
* Отправка буфера дисплею по 4-битному протоколу с "ручным" стробированием
* и типовой задержкой на выполнение команды
*/
#define lcdSend(len) \
{ \
twiWrite(lcdAddress, lcdBuffer, (uint8_t)(len)); \
delayMicroseconds(LCD_WAIT_1); \
}
#define lcdWrite1(d) {lcdPrepare((uint8_t)(d), 1); lcdSend(6);}
И видим здесь следующее: на один символ выводится 6 байт (не криминал, но люди разное говорят ;); вывод данных запускается неблокирующим вызовом (Вах! Хараше! Всебы так - ан нет ;); делей блокирует выполнение кода на 50мксек в течени которых в подсистеме прерываний должна быть выполнена отправка 5 байтов и инициализирована отправка 6-го. А вот это уже лажа, Arhat109-2! Не, я верю что вы написали аккуратно обработчик прерываний i2c и вобщем представляете верно: типа освободился регистр, взвелся флаг, вызвался обработчик, записали в регистр следующий байт... Проблема в том, что между "взвелся флаг" и "вызвался обработчик" может пройти достаточно много времени. Если по несчастному стечению обстоятельств как раз попало другое прерывание, например таймера. И если оно не позволяет прервать себя - а это как правило так, то прийдется ждать его завершения не один десяток мксек. Как следствие - за 50мксек не успеваем отправить 5 байт и инициализирована отправка 6-го. Возвращаемся в цикл где вызов снова lcdWrite() а в нем сразу без проверок uint8_t *_b = (uint8_t *)buf; uint8_t _l = len; затем lcdPrepare() который и ломает данные в еще не полностью выведеном буфере.
Ваш код нестабилен. Иногда работает, иногда мусор на экране.
Ну и как обычно, Вас об этом предупреждал "Причем кривой как турецкая сабля, за синзронизацию выполнения потоков (основног и прерывания) на основе ожидания. Разрабам за такое дают по рукам. т.к. либо будет ждать лишнего либо может недождатся." И как обычно Вы ничего не поняли. Пока паузы были здоровенные, они скрывали проблему, а теперь вот так оно...
вы уже определитесь хоть куда-нибудь "блокирующее тут исполнение" или "исполнение неблокировано, а СИНХРОНИЗИРОВАНО" делеем. а то мечетесь то туда, то сюда .. а в целом сильно рекомендую РАЗОБРАТЬСЯ с аппаратным I2C у мег. Он не просто хорош, он замечателен! Ну и заодно код обработчика обнаружить в библиотеке, дабы не писать ляпов в очередной раз. А то вас не поймешь то он "очень хорош", то "нестабилен" .. вы уж там договоритесь как-то промеж себя предварительно, так сказать "согласуйте позиции". :)
P.S. Да, и я не Иисус Христос, чтобы в "меня верить". Есть библиотека, есть файлик arhat_twi.c откройте и ознакомьтесь наконец-то. Зачем свое неумение читать код выставлять настолько напоказ-то? :)
P.P.S. Да, и ещё: 140мсек - результат полученный и продемонстрированный тут. 124мсек - результат не относящийся к вопросу (дисплей иной), а 116мсек - результат заявлен и подлежит ПРОВЕРКЕ. на все 146%.
Логик! Оставим его.Он же уже спалил меня, как виновника всех бед....
То, что ты написал, происходит, если снизить скорость и2с. Если оставить 50мкс и скорость100000, например. Я много играл с Архатовским драйвером. Сочетание 800 и 50 мкс устойчиво. Устройство полсуток отработало три дня назад.
Тем не менее, он в этой части прав. Работа конкретно тут только СИНХРОНИЗИРОВАНА задержкой. Поставьте задержку в 2мксек и получите "банан". Кстати, на моем дисплее задержка менее 41 миллисекунды - дает точно такой же "банан". Не знаю почему так.
Andriano, в целом мой первый пост в этой теме как раз полностью решал вашу задачу:
Вот похоже что это максиум того, что можно выжать при моем подходе. Тут частота I2C установлена в 880кГц, буфер для lcdPrepare() укорочен до 4-х байт и передача идет порцией в 4 байта по 2 байта на полубайт данных. Строб устанавливается в первом байте и сбрасывается во втором. Да, и здесь подчищен код теста для повышения скорости его работы:
#include "arhat.h"
//#define TWI_ON 15 // Debug: Включить все режимы обработчика I2C
//#include "arhat_twi.h" // Debug: Подключить явно тут с заданным комплектом режимов
/**
* Замена для delay() -- вместо Serial.writeln(); можно воткнуть любой иной код
* который будет работать пока вывод ждет готовности дисплея, если это долго..
*//*
#define delay(vrema) \
{ \
static uint8_t t = (uint8_t)millis(); \
while( (uint8_t)millis() - t < ((uint8_t)vrema)) \
{ \
Serial.println(vrema); \
} \
}
*/
#define LCD_I2C_SPEED 880000 // Установить типовую скорость (внутри задано 800кгц!)
#define LCD_WAIT_1 26
#include "lcd1602.h"
// ************* Example *********** //
void setup() {
lcdSetup(0x27, 16, 2, 1);
// lcdWrite("Hello, Arhat!", 13);
// lcdSetCursor(0,1);
// lcdWrite("Bye, Bye..", 10);
// Serial.begin(115200);
}
void loop()
{
const char *s=(char *)"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
char ss[16];
uint32_t m,om;
int l;
float mm;
delay(1000);
lcdSetCursor(0,1);
lcdWrite(" ", 16);
om=getOvfCount();
for( uint8_t j=0,jj=0; j < 100; j++){
lcdSetCursor(0,0);
lcdWrite(s+jj, 10);
if( jj++ > 24 ) jj=0;
}
m=getOvfCount()-om;
itoa((int)m, ss, 10);
lcdSetCursor(0,1);
l=0;
while(ss[++l]);
lcdWrite(ss,l);
}
Изменения: отказ от операции %, которой нет в наборе команд и замена медленной у меня millis() на быструю getOvfCount(). Соответственно 95 - это количество тиков таймера по 1024мксек. В миллисекундах тест показал = 95/1.024 = 93 мсек. :)
В целом, возвращаясь к началу темы, ответ положительный. Можно быстро выводить на дисплей и при этом иметь возможность каждые 300мксек получать данные из сериала. Даже остается "запас" не менее 200 микросекунд.
Arhat109-2, спасибо (заодно скажу спасибо и за Вашу библиотеку, фрагментами которой пользуюсь).
Да, этот код, пожалуй, дает ответ на один из моих вопросов, а остальное обсуждение - и на остальные вопросы.
В результате полученной информации все больше склоняюсь к варианту установить на экран (а заодно и на несколько органов управления) отдельную Pro Mini. Возможно, там и воспользуюсь Вашим кодом. Использовать его на 2560 у меня не получится из-за дефицита свободных ног (могу подключить по i2c, но не хватает скорости, а 7 лишних ного - нет). И так запланировано 4 сдвиговых регистра - по 2 на вход и на выход. Ну и кроме опроса порта там для 2560 еще хватает другой работы.
К сожалению, Вы не посвятили всех участников в детали проекта, кроме одной заметки за "надо опрашивать порт, хотя бы каждые 300мксек". Я конечно догадываюсь что 2560 можно нагрузить большим объемом работы, но хотелось бы прочитать за хотя бы какие-то детали.
Дело в том, что эти 5518, 1118, 140, 116 или даже 95 мсек исполнения этого теста .. никоим образом не есть ответ на ваш вопрос, ибо это вовсе НЕ время работы аппаратного драйвера I2C, а "всего лишь" время работы самого теста. Сколько и как долго работает аппаратный драйвер - тут ни разу не измерялось НИКЕМ и НИЧЕМ .. помнится я уже писал про это. А, впрочем .. оно и НЕ ВАЖНО, как ни странно.
Как пример, для выпуклого показу: Вы настраиваете таймер на аппаратный ШИМ, скажем типовые 490гц и далее, всего одной командой записи в регистр изменяете его скважность. Вопрос: сколько времени требуется аппаратному таймеру чтобы скважность изменилась? Ответ: "а это кого-то волнует?" :)
Так и тут. Достоинство аппаратного I2C в том, что совершенно не важно сколько он пашет на самом деле. Его пнули - он отдал в шину. Сказали байт - отдал 1 байт, сказали 8килов - отдаст все 8. И такое невозможно при "программной эмуляции" ногодрыгами: прилетело прерывание таймера, сериала и т.д. и усё .. поплыли длительности SCL,SDA, а то и надолго. Закрывать прерывания - не выход.
А то что тут измеряли - это по сути длительность минимальной задержки в посылках, которые дисплей ещё способен переваривать. И только.
Соответственно, делаем длительность паузы между отправками пачек на дисплей любой, достаточной для отрисовки величины и спокойненько решаем свои задачи во время такой паузы .. пример я приводил выше с макрозаменой функции delay() на полезный код.
Вот этот подход и есть решение многих "проблем". То, что я Вам и хотел отписать своим первым постом.
Вопрос в том, что нужно опрашивать MIDI-порт и выполнять MIDI-команды так, чтобы человек не ощутил какой-либо задержки, не говоря уже о пропуске команд. При этом программно генерировать все LFO и ADSR и управлять 4-мя собственными таймерами, фильтром на MAX261 и цифровым регулятором громкости.
Цитата:
Достоинство аппаратного I2C в том, что совершенно не важно сколько он пашет на самом деле.
Собственно, в той реализации, которой я пользовался, это не так, т.к. каждый байт отправляется в своем пакете. Соответственно, чтобы послать следующий, нужно дождаться, пока уйдет предыдущий.
В целом, мысль интересная (и, возможно, перспективная), но, честно говоря, сейчас мне проще поставить дополнительную Pro Mini.
В типовой реализации из LiquidCrystal_I2C все ещё хуже: там каждый полубайт мало того, что отправляется в своем пакете, так он ещё и каждый раз делает это через Wire.h, производя инициализацию передачи заново. И делает это через виртуальную связь любимой пачки классов от Stream или кто там из них "первее". После того, как мне удалось продраться сквозь всю эту белиберду и понять что на самом деле происходит .. сел и сваял свой драйвер I2C. С сериалом кстати ровно таже самая история. Надеюсь Вы пользуете свой драйвер UART/USART на аппаратных прерываниях, а не Serial.. .h?
В кратце, идея звучит банально просто: в loop() работает самый медленный поток обработки, всё что дергается аппаратно - работает из прерываний "быстро и шустро", а основной алгоритм работы вызывается из yield() или его аналога из под пауз, которые обязан отрабатывать самый медленный поток в loop().
Собственно таким измененным подходом и отличается программирование микроконтроллеров от "ЭВМ общего назначения".
В данном, конкретном случае ваще можно сделать такую вот "рыбу":
#include "arhat.h"
//
// тут подключаем всё, что нам понадобится ишо..
// .. и объявляем все глобалы для взаимодействия аппаратных потоков-обработчиков
// , "главного" loop-потока и основного потока управления из yield()
//
// На примере робота, бегающего по линии:
// uint8_t speedLeft, speedRight, .. и т.д.
//
/**
* Замена для delay() -- (arhat.h не имеет yield()!) вызывает опрос датчиков линии и главный мозг робота
* пока идет отрисовка текущих параметров на экран
* getSensors() -- получает и усредняет датчики "бегущим средним" по 20шт - папина
* brain() -- мой главный мозг моего робота запускается каждые 2 милисек!
*/
#define delay(vrema) \
{ \
static uint8_t t = (uint8_t)millis(); \
while( (uint8_t)millis() - t < ((uint8_t)vrema ) \
{ \
getSensors(); \
brain(); \
} \
}
#include "lcd1602.h"
// Если переопределение далее мешает, то можно сделать #undef ..
// Это и есть "главный loop-поток": отрисовка всего что требуется на экран из глобалов:
void lcdWriteAll(void)
{
uint8_t strBuffer[16];
uint8_t len;
len = itoa(strBuffer, speedLeft, 10);
strBuffer[len] = '___';
len += itoa(strBuffer, speedRight, 10);
strBuffer[len] = '___';
lcdSetCursor(0,0);
lcdWrite(strBuffer, len);
// все остально что надо вывести на экран во вторую строку и остаток первой
}
void setup(void)
{
// все инициализации как и раньше ..
}
void loop(void)
{
lcdWriteAll(); // и всё! Первый раз отрисовываем стартовые значения ..
}
// собственно основной поток, вызываемый из под вывода, ибо он - медленный.
// тут и происходит "самое главное" .. :)
void Brain(void)
{
}
Кстати, вынеся работу с экраном в отдельное устройство, Вы ни разу не решите проблему "медленного вывода". Оно все равно всплывет, но на следующем уровне абстракции. И тогда уже, Вам полноценно понадобится всё то, чего так испугался Logik: "семафоры, очереди и т.д. и т.п."
Посмотрите внимательнее этот подход: просто, дешево и сердито. :)
Кстати, вынеся работу с экраном в отдельное устройство, Вы ни разу не решите проблему "медленного вывода". Оно все равно всплывет, но на следующем уровне абстракции.
Да.
Arhat109-2 пишет:
И тогда уже, Вам полноценно понадобится всё то, чего так испугался Logik: "семафоры, очереди и т.д. и т.п."
Не провоцировать Вы уже не можете? Не испугался, а избегаю сложных неэффективных решений. А "семафоры, очереди и т.д. и т.п." на самом деле Вам нужны здесь и сейчас , а Вы от них прячитесь подбирая делеи. Как только вместо одного потока появляется 2 взаимодействующих, не суть важно даже это 2 контроллера или прерывание и луп, сразу есть проблема межпоточной синхронизации.
Что Вы предлогаете andriano, код с известной проблемой?
Arhat109-2 пишет:
Тем не менее, он в этой части прав. Работа конкретно тут только СИНХРОНИЗИРОВАНА задержкой. Поставьте задержку в 2мксек и получите "банан". Кстати, на моем дисплее задержка менее 41 миллисекунды - дает точно такой же "банан". Не знаю почему так.
Не знаете почему - так я ж выше разжевал. " делей блокирует выполнение кода на 50мксек в течени которых в подсистеме прерываний должна быть выполнена отправка 5 байтов и инициализирована отправка 6-го." Если за время делея действие не выполнено то и будет Ваш "банан". Вы это увидели сократив задержку. Но и при 50мс получится тоже самое если "левое" прервание, например таймера, произойдет в течении этих 50мс и задержит выполнение прерываний i2c. Сопоставив период системного таймера около 1000мксек и делея 50мксек, возникает подозрение что даже в Вашем тесте каждая 20 строка на экране битая (чтоб подозрение переросло в увереност надо знать время обработки прерывания системного таймера). Понятно что в тесте "созерцая" на экране строку аж 1мсек глазами это незаметить. Бага вылезит в реальном приложении позже. И чем интенсивней работают прерывапния - тем чаще.
И чего вы andriano, паритесь с надумаными сложностяи. Ну опрос порта 300мксек - в прерывание по таймеру, вывод на экран в основной цикл. Всех делов то. Очевидно после опроса порта надо чегото сделать с получеными данными. Так для этого есть минимум 300мксек (про максимум можно поговорить отдельно, там и 600 вероятно не проблема) до следующего прерывания, вполне достаточно я думаю.
Клапауций!
Вентилятор то есть? Со свои дерьмом приходить или на месте найти можно? Про лопату даже не спрашиваю.
Клапауций!
Вентилятор то есть? Со свои дерьмом приходить или на месте найти можно? Про лопату даже не спрашиваю.
есть весь стандартный инструмент - эстетам и гурманам просьба уточнять наличие желаемого инвентаря в личку.
Wdrakula, Вы точно нашли ошибку? ...
Или Вы не согласны, что забыли волатиль? ...
Архат! Мне, правда, неловко спрашивать, но Вы точно не баба? Ровно, как в той памятной истории про преобразование к int. Это очень по-женски - ни-за-что не признать косяк... смешно, право-слово.
Ладно... тема полностью исчерпана. Было и правда интересно. Пределы скорости lcd1602 с i2c регистром PCF8574 мы определили весьма точно. Больше не выжать.
На самом деле - вот ради таких тем и нужен форум, а не новичкам про диод и мосфет объяснять. ИМХО.
Пределы скорости lcd1602 с i2c регистром PCF8574 мы определили весьма точно. Больше не выжать.
мы не определили максимально комфортную для восприятия скорость передачи.
потому, как максимальная нафиг не нужна.
Ладно... тема полностью исчерпана. Было и правда интересно. Пределы скорости lcd1602 с i2c регистром PCF8574 мы определили весьма точно. Больше не выжать.
Замечательно.
Я, правда, из-за периодической путаницы милисекунд с микросекундами и кучи вообще безразмерных цифр общего порядка не уловил.
Точнее, не уверен, что уловил.
Если я правильно понял, предел составляет где-то 120 мкс на символ на скорости 800, это так?
Wdrakula, вы все уже достали читать по диагоналям. Ещё раз: косяки и расхождения версий реализаций компиляторов, а равно объявленные "фичами" в стандартах против полноценно строгого описания а-ля Алгол-68 или Ада - я НЕ СЧИТАЮ ОШИБКАМИ программистов. Да, их НАДО учитывать и, тот кто этого не сделал - ошибся. В этом плане я свою ошибку признал и там и тут отписал уже: "если Вы считаете это ошибкой". Но все что в библиотеке написано - сделано СОЗНАТЕЛЬНО. И, если оно "где-то не работает" это проблема того самого "где-то", ибо библиотека НЕ АДАПТИРОВАЛАСЬ к различным версиям плат, компиляторов и т.д и т.п. Тот кому требуется адаптация вполне способен сделать её САМОСТОЯТЕЛЬНО (ибо писано не для идиотов). Библиотека писалась для вполне конкретного применения на конкретном камне - Atmega2560 и его клонов, слегка адаптирована к ATmega328p и его клонам. Но только "слегка".
Это - моя позиция как программиста этой библиотеки. Причем тут ваши всхлипывания про баб, не могу понять вот никак.
Andriano, не удивительно что Вы ничего не поняли. Остальные участники точно столько же "не поняли", просто "сделали вид". Давайте подведу "итоги":
1. На какой конкретно частоте способен работать I2C у PCF8574 - тут НЕ ВЫЯСНЕНО, ибо I2C-slave способен тормозить шину для обеспечения нужной ЕМУ скорости. То, что Мега-мастер спосоден И пытается отдавать на 800кгц - да, может .. но, в общем-то, "ни о чем". Тут эта сторона вопроса не выяснялась и вовсе.
2. LCD1602 способен принимать свои полубайты - БЫСТРО. Так быстро как может PCF8574, но только на 1 символ. Соответственно, правильная работа с этим экраном по I2C - это отправка пачкой обоих полубайт, для каждого из которых требуется отправить 3 байта в PCF8574 и это МОЖНО СДЕЛАТЬ ОДНОЙ ПОСЫЛКОЙ. Это самый быстрый способ работы с этим дисплеем. Wiring так не умеет.
3. Задержка отрисовки одного символа на моем дисплее составляет 4.1мсек или 4100 микросекунд. Это та пауза, которую Вы обязаны обеспечить если хотите прочитать отправленное на экране. В даташите на МК дисплея указано 37 микросекунд - это теоретический миниум .. у меня такое НЕ РАБОТАЕТ, но возможно вам повезло.. вот у Wdrakula он явно реагирует шустрее ..
4. Поскольку сам дисплей "экранирован" чипом PCF8574, то способа "узнать" готов ли дисплей принять следующий символ у вас практически нет. Паузу вы должны отрабатывать самостоятельно. Можно в лоб delay() как в моем примере, можно через прерывания по таймеру, можно ещё 100500 разными способами. Зависит от вашей программы, знаний, умений и навыков. Тут возможно есть способ "задрочить" PCF8574 так, чтобы можно было и читать 1 ногу дисплея .. но я этого не пробовал.
5. Скорости работы моего теста для 100х10 символов + позиционирование курсора (отправка +1 команды на каждые 10 символов): Время выдерживания паузы между посылками = 5500мсек; Время подготовки данных для отправки = 17мсек; Время отправки данных - НЕ ИЗМЕРЯЛОСЬ ибо проводилось через прерывания в процессе отработки паузы. Теоретическое время отправки подсчитано Logik-ом = 70мсек. для 800кГц, но поскольку реальная скорость интерфейса тут не замерялась вовсе - то неизвестно.
Собственно, 5500-70 = 5430мсек - это то время, которое ваш скетч способен потратить на свое усмотрение пока дисплей рисует символ. На каждый символ. В отличии от прямого способа отправки ногодрыгом у Wdrakula или Logik.
Вот, так как-то.
Arhat109-2, перечитайте, пожалуйста, свое сообщение. У меня стойкое ощущение, что Вы путаете мсек с мксек.
Перечитал, все верно. 1мсек - 1 миллисекунда = 1/1000 сек; 1мксек - 1 микросекунда = 1/1000 миллисекунды.
В Даташите указано время отрисовки символа действительно в микросекундах, но на самом деле он отрисовывает символ за 4.1 миллисекунды или 4100 микросекунд. И преодолеть этот барьер - никак. Интерфейс вполне способен работать на частотах мастера в 800кгц: сам мастер - позволяет, а слейв может в любой момент притормозить прием до приемлемой для себя скорости. И расходы на передачу, в сравнении с временем отклика - невелики. В даташите на дисплей и вовсе указано что принимать он может на скоростях аж до 1..2Мгц .. там характерные времена сигналов - 250..500 наносекунд. Только "толку-то"?
800кгц = 1.25 микросекунды на передачу 1 бита. * 9 бит * 7 байт (6+адрес) = 78,75мксек на посылку. Тест отправляет 100х(10+1) посылок 78.75 *1100 = 86625 мксек или 86.6мсек .. Logik давал цифирьку в 70. Это более точный расчет работы по прерываниям.
Перечитал, все верно. 1мсек - 1 миллисекунда = 1/1000 сек; 1мксек - 1 микросекунда = 1/1000 миллисекунды.
:) Да, весело получилось. Это не "минус", а тире .. типа "это". :)
Собственно, 5500-70 = 5430мсек - это то время, которое ваш скетч способен потратить на свое усмотрение пока дисплей рисует символ. На каждый символ. В отличии от прямого способа отправки ногодрыгом у Wdrakula или Logik.
Ох уж эти сказки..
Как в нашем коде, вот этом -
реализовано "скетч способен потратить на свое усмотрение"?
Особенно учитывая что функции lcd... у Вас блокирующие! Несмотря на то, что под ними неблокирующие лежат. И зачем они там? )))) И весь выиграш ,о котором Вы пишите, в этих блокирующих lcd.. и седается )))
А теперь к вопросу почму они у Вас блокирующие. Потому что если сделать их неблокирующими, то возникнет проблема хранения информуции о типе вызова и параметрах (назовем это контекст) в промежутке времени между вызовом функциии lcd.. и фактическим выводом на экран. Теперь обратим внимание на то, что взовы lcd.. могут ити подряд и много, какраз как в нашем примере, и станет ясно что контекст нужно хранить в очереди и её размер вобщем то не ограничен какими либо разумными доводами. Вот и получим сотни байт ОЗУ (а если экран графический то и тысячи и даже сотни тысяч байт) и издержки на работу с очередью контекста (а там потребуется синхронизация её использования из прерывания и основного потока, и комуто из них прийдется ждать пока другой загружает/выгребает контекст). Что в сумме окажется хуже чем прямой вывод. И по скорости и по ОЗУ и по сложности реализации.
Так то вот!
ПС. Постарайтесь понять написаное выше, несмотря на свои эмоции и гордыню. У Вас банальный неверный выбор архитектуры, непродуманый подход.
Перечитайте всё что было написано выше и в предыдущих постах. Там есть все ответы на ваши "гениальные догадки" и не пишите дальше свой фантастический бред. Метать бисер перед недоучками у меня желание уже давно пропало. Уж извините, но достали со своей непроходимой тупостью.
P.S. Тема в том ракусе что была поднята - исчерпана чуть более чем полностью. А поддерживать ваш срач - у меня нет никакого желания. За сим, таки откланяюсь тут. Разбирайтесь, перечитывайте .. всё есть.
Ну раз среди ночи Вам так неспалось, что захотелось мне похамить то выводы очевидны:
1. Вы таки поняли свой про..б в архитектуре.
2. Отсутствие аргументов - отсутствие выхода с тупика.
Действительно, говорить не о чем. Тема исчерпана.
:) Перечитывайте. Тут все уже есть. :)
Ниче нихто перечитівать небудет. Нет у Вас там ничерта толкового. И сказать Вам больше нечего ))
Ну вот почто Вы такой упертый "нечитатель"? :)
Ладно, давайте помогу:
1. Logik, писал: "Как в нашем коде, вот этом - ... реализовано "скетч способен потратить на свое усмотрение"? "
Ответ: это НЕ МОЙ код, а Wdrakula, который решил проверить скорость отрисовки ваще-то. Конечно в нем - НИКАК. Но это же не "весь код применения", так ведь? :)
2. Logik, писал: "Особенно учитывая что функции lcd... у Вас блокирующие! "
Ответ: Если Вы откроете lcd1602.h из библиотеки, то сможете обнаружить что все функции lcd..() по большей части являются макроопределениями, которые в конечном счете вызывают единственную функцию lcdSend(), которая в свою очередь вызывает twiWrite(), которая .. упс НЕ ЯВЛЯЕТСЯ блокирующей даже с включенным delay() в lcdSend()? а тупо устанавливает область и размер передачи и запускает обработчик прерывания. :)
Синхронность обработчика прерывания и основного потока здесь обеспечивается только большой задержкой в lcdSend(), которая гарантирует что к моменту повторного вызова lcdSend() не только закончится предыдущая передача, но и дисплей уже отрисует символ. И это - никак НЕ блокирующая работа, заметьте.
Да, и про это было сразу сказано в посту №17, последним предложением, но .. Вы похоже его не читали.
3. Logik писал: "Несмотря на то, что под ними неблокирующие лежат. И зачем они там?"
Ответ: Вы были просто невнимательны. Весь тест Wdrakula, работает НЕБЛОКИРУЮЩЕ. Об чем вам и было посоветовано: перечитайте. а вы .. "не буду" .. прямо как дите малое.
4. Logik писал: "И весь выиграш ,о котором Вы пишите, в этих блокирующих lcd.. и седается )))"
Ответ: нет. Весь выигрыш тут съедается оператором delay() внутри lcdSend(). Это легко поправить для конкретного применения. Разъяснение дано выше.
5. Logik писал: "А теперь к вопросу почму они у Вас блокирующие." и далее весь остальной бред из-за "читать не буду"
Они НЕБЛОКИРУЮЩИЕ. Перечитайте. Они даже в этом тесте работают НЕБЛОКИРУЮЩЕ. :)
6. Logik писал: "то возникнет проблема хранения информуции о типе вызова и параметрах (назовем это контекст) в промежутке времени между вызовом функциии lcd.."
Ответ: это вовсе необязательно. Необходимо и достаточно иметь признак (1 бит/байт) завершен ли предыдущий вызов вывода на дисплей и соответствующие проверки в коде "если дисплей ещё занят, то ..". Обычное автоматное программирование.
Ну и процитирую вас же:
ПС. Постарайтесь понять написаное выше, несмотря на свои эмоции и гордыню. У Вас банальный неверный выбор архитектуры, непродуманый подход.
Удачи. :)
писал: "Как в нашем коде,
Ответ: это НЕ МОЙ код,
2. Logik, писал: "Особенно учитывая что функции lcd... у Вас блокирующие! "
Синхронность обработчика прерывания и основного потока здесь обеспечивается только большой задержкой в lcdSend(), которая гарантирует что к моменту повторного вызова lcdSend() не только закончится предыдущая передача, но и дисплей уже отрисует символ.
Вы конечно можете черное белым называть сколько угодно, даже большими буквами, но выполнение лупа заблокировано до момента когда "закончится предыдущая передача". Это типичный блокирующий код. Причем кривой как турецкая сабля, за синзронизацию выполнения потоков (основног и прерывания) на основе ожидания. Разрабам за такое дают по рукам. т.к. либо будет ждать лишнего либо может недождатся. А еще и с делеем - нет слов, уровень новичка которого посылают на блинкбезделея. Позорище.
Костыль костылем всегда поправится. Про все хороше будет в новой версии уже слышали
Ответ: это вовсе необязательно. Необходимо и достаточно иметь признак (1 бит/байт) завершен ли предыдущий вызов вывода на дисплей и соответствующие проверки в коде "если дисплей ещё занят, то ..". Обычное автоматное программирование.
Вот это и была бы неблокирующая реализация. Но Вы как всегда не хотите продумывать последствия.
1. автоматное програмирование, в котором каждый вызов lcd... отдельное состояние - это мрак.
2. при таком подходе в реальном приложении скорость вывода еще ниже окажется, т.к. основной цикл совсем не обязательно прокрутится за 5мсек, там как повезет может 4, может 20 а то и 100. И все отклонения будут означать простой вывода и снижение скорости.
3. Вывод на экран начнет мигать малопредсказуемо, т.к. периодически попадающие паузы вывода в десятки и сотни мсек будут просто видны.
Но вы делайте, делайте, потом еще поржем и мокнем.
У Вас банальный неверный выбор архитектуры, непродуманый подход.
"Не ругайтесь, девочки!"(с) ))))))))
Берите правильную архитектуру, тулите полный буфер, заводите хардварный вывод и вопрос отпадёт сам собой. Это ж просто красота! Меняем буфер дисплея когда хотим, запускаем обновление экрана дисплея когда хотим. А вы тут со своими поднадоевшими микро и миллисекундами. Срамота! )))))))
Окей, пусть будет " в нашем коде", тоже оказался невнимателен.
Вы конечно можете черное белым называть сколько угодно, даже выделять жирным, но покажите где выполнение лупа заблокировано до момента когда "закончится предыдущая передача"? Именно до этого момента. :)
Logik, писал: "А еще и с делеем - нет слов, уровень новичка которого посылают на блинкбезделея. Позорище."
Вы наивны как дитё. Это - пример, и написан он был вовсе не для демонстрации работы с дисплеем, а как пример реализации работы с моим twi интерфейсом. Пример как раз для тех, кто пользуется делеем. Кстати, неблокирующее исполнение delay() есть в wiring .. функция yield() кажется так. Ознакомьтесь, иногда тоже полезна.
Но, в целом почти разобрались, уже лучше.
Самый простой неблокирующий подход тут - использование функции yield() для выполнения кода во время отработки паузы отрисовки. В моем delay() её нет, но никто не мешает дополнить. Этим легко и ненапряжно опровергается ваше утверждение про "блокирующую" работу теста, а заодно и все ваши попытки хамить от незнаний. Осваивайте, это просто один из 100500 способов как использовать время ожидания.
Кажется дошло. У вас неверное понимание "блокирующего" и "неблокирующего" кода. попробую помочь:
Любое последовательное исполнение - есть "блокирующий" код для всех последующих команд. Так например:
Теперь смотрим на наш тест и видим, что ничего, кроме вывода строк символов он не делает, соответственно сам по себе тест является последовательным или блокирующим исполнением. Нельзя вывести второй символ ранее, чем выведен первый. Нельзя вывести следующую строку раньше чем выведена предыдущая. Согласны?
А вот давайте теперь посмотрим как происходит сам вывод И отправка данных в дисплей по I2C:
Обратите внимание, что строго последовательная задача посимвольного ВЫВОДА решена строго последовательно. А вот сам "вывод данных" делается неблокирующее: через запуск автомата I2C функцией twiWrite(), которая .. ничего не ждет а тупо запускает автомат, если он свободен. Соответственно, Вы ошибаетесь и не единожды, повторяя "вывод на дисплей - блокирующий". Нет, работа интерфейса I2C, которая тут и есть "вывод на дисплей" - делается не блокирующее а "параллельно" с основным циклом.
Ну и напоследок, пример использования этой части библиотеки моим сыном, осваивайте:
Уж не помню, с рабочей версии стащил или какой .. осваивайте "неблокирующую работу с дисплеем.
P.S. Забыл указать, что в loop() есть вызов WriteAll() -- функция которая периодически обновляет показания и состояния автоматов на дисплее. Ну и конечно же как и положено, все реализовано на широком применении глобалов. :)
Такой подход позволил ему видеть онлайн как реагирует робот на изменение обстановки при движении по линии на двух датчиках: верхняя строка дисплея показывала левый и правый датчики, а на нижней выводились скорости моторов. В правой части экрана на 2-х строках рисовался "символ" - решение мозга "куда едем" псевдографикой.
Нет, работа интерфейса I2C, которая тут и есть "вывод на дисплей" - делается не блокирующее а "параллельно" с основным циклом.
Вы реально бредите в попытке оправдаться и очень сильно. И с этим нужно что-то делать.
Гы. Ты сначала посмотри и дочитай что тут обсуждается а потом сри в тему. Ещё один говнокодер-проприетарщик.
Кажется дошло. У вас неверное понимание "блокирующего" и "неблокирующего" кода. попробую помочь:
ненадо. Мое понимание строго согласно https://ru.wikipedia.org/wiki/Асинхронный_ввод-вывод
Именно:
"В информатике асинхронный ввод/вывод, или неблокирующий ввод/вывод является формой обработки ввода/вывода, который позволяет другим процессам продолжить выполнение до того, какпередача будет завершена."
Т.е. в нашем случае lcd... должен завершаются до окончания вывода на экран, и существенно ранше. И независимо от того, что там выводится от предыдущих вызовов. Это принципиально возможно, но сложно, я выше писал как.
Нельзя вывести следующую строку раньше чем выведена предыдущая. Согласны?
Где в этом коде вобще работа с экраном? Постите хуйню, в расчете что всем будет пофиг и зачтется? Вы в натуре - баба? Биологическая или так просто, по жизни?
Вы в натуре - баба? Биологическая или так просто, по жизни?
Я уже спрашивал... он ушел от ответа ;) ;) ;)...
------------------------
Да, к теме, а не к дерьму на вентиляторе, хотел добавить:
Я довел софварный вариант до 720 мс на 1000 символов. Но вот в чем прикол: получается, что PCF8574, все таки, не держит более 100 МГц. Странно, но я проверил код Архата. Он действительно устанавливает 800КГц в регистры. Нужно посмотреть осцилом, Я сам пока не могу - жду нового ослика с али. В софтовом варианте обмен прекращается на времени удежржания уровня SCL меньше 4.5 мкс.Это не столь важно для жизни, но просто интересно! ЧОрт возьми!
Пипец как достали долбо*бы. Разберись сначала что выложено а потом поливай дерьмом, а не наоборот. Сами как бабы, ничего кроме как обосрать оппонента не умеют, а туда же! Вот уж действительно "метать бисер" .. перед кем?!?
.. афигеть! "он обнаружил" .. обнаружь и все остальное.
Разберетесь - пишите.
Он действительно устанавливает 800КГц в регистры. Нужно посмотреть осцилом,
Я особо и не сомниваюсь, что 800КГц использует. Просто данные идут не непрерывным потоком а с паузами, и эти паузы очень большие. А чтоб обеспечить непрерывный поток надо или буфер большой, т.е. много ОЗУ чего нету или непрерывно и быстро из основного потока получать, а значить основной поток не сможет заниматся другими задачами и просто исчезает смысл всей затеи с аппаратными 800КГц на прерываниях. То что было отличным решением на 100 стало не очень на 800 )))
ничего кроме как обосрать оппонента не умеют
Не умеете. Ничего не умеете кроме как срать на форуме и ногордыгами заниматься. Уже проверено неоднократно. Вы даже тут разобраться не способны, митрофанушки.
нашел время, перепроверил ваш тест:
Какие же Вы, Logik и Wdrakula оба ЗАСРАНЦЫ! Слов нет. Мало того что Ваш тест не компилируется, ибо массив символов должен быть объявлен не в 10, а 11 символов, так ещё и врете. Это тест с другого дисплея (не моего). Задержка LCD_WAIT_1 установлена в 50 МИКРОСЕКУНД с заменой вызова delay() на delayMicroseconds()..
только бабы могут насрать и не извиниться. Ибо Женщина - всегда права. .. какие чмори.. слов нет.
Это - код вашего теста. Исправлена ошибка в размере массива.
А это код lcd1602.h с заменой константы и функции задержки:
Можете перепроверить.
*******
// ждем >4.1ms
Это чё за хрень? )))))))))))))))
Не умеете. Ничего не умеете кроме как срать на форуме и ногордыгами заниматься.
А ардуина умеет по другому? Не пугайте не смешите, не врите! ))))))))
Любое последовательное исполнение - есть "блокирующий" код для всех последующих команд.
Башорг просто плачет от такого бреда! )))))))))))))))
Теперь смотрим на наш тест и видим, что ничего, кроме вывода строк символов он не делает, соответственно сам по себе тест является последовательным или блокирующим исполнением. Нельзя вывести второй символ ранее, чем выведен первый. Нельзя вывести следующую строку раньше чем выведена предыдущая. Согласны?
С вашим очередным бредом? Конечно нет! )))))))))))))))
В прерывании или через ДМА можно вывести что угодно и как угодно, хоть символ, хоть строку. Так что сам по себе последовательный код не является блокирующим, он просто выполняет последовательность команд согласно алгоритму, как ему и положено.
Архат! Ты псих совсем или ...нулся? Я давно на твоей библиотеке не 140, а 116 получил. Причесав ее. Я хоть раз писал, что мне твоя библиотека не нравится???? Совсем рехнулся? Пустырнику попей! У меня есть вопросы по релизу аппаратного и2с, но не к тебе, а к производителю. Например держит оно 800 или нет? В даташите написано до 400, потому и хочу осликом посмотреть. Но у тебя - все нормально и правильно, успокойся уже!
-----
Наезд был исключительно за твой тупой апломб и непризнание очевидных ошибок, которые пришлось править самому. Но неблокирующий мастер - очень хорош. Логик спорит о том,что он нахер никому не нужен. Возможно. Но, как чисто програмистская задача, ты написал хороший драйвер и2с.
Что тебя на говно пробило? Странный ты какой-то.
А вот и нашлось объяснение "якобы моей ошибки", которую исправляет "волатил" у Wdrakula: http://stackoverflow.com/questions/28708234/how-to-fix-defined-in-discarded-section-linker-error - "compiler bug version 4.9.2"
Wdrakula, Вам ещё не стыдно? или таки "женщина всегда права"? :)
Пи...дец! Я тебе про это и говорил, когда описывал ситуацию и просил погуглить текст ошибки. А как, по твоему, я про волатиль догадался, если не прочтя вот именно эту ссылку? Только вместо "юзед" для функции я поставил волатиль для переменной. Но это именно ошибка, если более строгий подход оптимизатора ее выявляет. Только мудак, из этой ссылки, считает это багом. Если ты точно считаешь, что оптимизатор не должен трогать твой код, пометь его "волатиль" и "юзед".
Да вот уж точно.
Во-первых, сестра перестаньте хамить, тыкать и матерится. Это плохо отражается на внешности.
А во-вторых, освежу вашу "девичью память", ибо Вы конкретно писали это:
1. "Писал народ про то,что с 4.9 опять оптимизатор стал выбрасывать переменные без волатиля и даже функции, без атрибут (юзед)."
2. "Советую гугль на слова из диагностики, там и найдете про avr-gcc 4.7, 4.8, 4.9, у них в этом и разница. На 4.8 ошибка как раз не должна проявляться."
И теперь, найдите в ссылке, указанной мною: "This seems to be a compiler bug that was fixed in gcc-4.7 and reapeared in gcc-4.8 (gcc bugreport for 4.6, reapearance in 4.8). A quick workaround is to mark the function used:", последняя фраза в переводе с нерусского означает:
Быстрый обходной путь
Кроме этого, там же можно найти и номер бага и данные о его всплытии и правках .. Вы не знаете зачем пишут баг-репорты, а особенно что исправляют, что вменили это мне?!? Вы все ещё продолжаете настаивать что это МОЯ ОШИБКА и я был просто обязан применять volatile или used?!?
Окей, продолжим. опция -flto - это указание ЛИНКОВЩИКУ (а не компилятору, как можно подумать исходя из вашей позиции), КАК оптимизировать сборку всего проекта. Так в частности у avr-gcc в хелпе даже прямо сказано:
Options starting with -g, -f, -m, -O, -W, or --param are automatically
passed on to the various sub-processes invoked by avr-gcc.
И у обоих про опцию читаем: "-flto Enable link-time optimization."
Тут точно ТОЧКА. Ибо это - не моя ошибка, как бы Вам не хотелось и не чесалось, барышня.
Да, и перестаньте вилять задним проходом, ибо это тоже писали Вы:
"Вот ты, когда пишешь, на зрителя расчитываешь, или пиздоболишь просто из любви к искусству? У тебя в архат.х "сишным по белому" 6 байт высылаются.", .. "Я н е стану писать про ошибки,ни у всех есть. Но, млядть, пиздобольство раздражает.", .. "Архат! Тупите нарочно? ШЕСТЬ байт + адрес=7, против 12 байт стандартной библиотеки. Это быстрее, но не в три раза.", .. "и перепешите setCursor, стыдно, ей Б..гу! У всех 4-х строк - разные смещения начала. Вы б в даташит взглядывали иногда, что ли.", .. "Вы с утра совершенно охренели??? .. и пойду искать ошибку в Вашем, заметьте, сырье.", .. "То есть Вы написали библиотеку, котора включает в код всякую херню, даже если там ей не место?", .."Вы влезли в разговор о том, как ускорить вывод на экран. Вы, как еще один персонаж на форуме, стали размахивать своим архат.х, с криками о том, что с ним решатся все проблеммы (пройдут прыщи и геморрой втянется сам). Грубого моего намека, что Вы несете чушь, Вы не поняли. Про то, что драйвер ЛСД у вас написан с ошибками - тоже не поняли. На мое прямое замечание, что в 4-х строчных дисплеях начала строк идут не 0 и 0x40, а другие (см. даташит) - Вы слили фразой, что Вас 4-х строчные не интересуют. Вот Вы не баба, после этого?", .. "1. В вашем коде была ошибка. при объявлении переменной timer0_hook_run не стоял волатиль. Поэтому и не компилировалось. Диагностика и Ваш код в сообщении 28. 2. Ваш драйвер лсд в два раза медленнее.", .. "Вы, Архат, удивительная комбинация понтов и амбиций!"
.. мало Вашего хамства и прямых оскорблений в теме, "девушка"? Извиняться - будем?
1.Тыкать или нет, уж прости - сам решать буду. Я, наверняка, старше, если нужно, то я 1969 г.р., а, следовательно буду тыкать.
2. по аглицки читаешь? "seems to be a compiler bug" - значит КАЖЕТСЯ -баг компилятора. В баг репорте читаем про мемсет... ни слова про другой "дискард".
-------------------------
Для гармонии, пусть будет "Вы" ;), не жалко.
Вы добросоветсно перечислили все невежливые мои высказывания. Память - просто восторг! Я в ах...уе, дорогая редакция. Тем не мение, я - вероятно единственный оставшийся программист на форуме, который не считает Вас клоуном и дураком. Наезд был исключительно на абициозное заявление - "применяйте мой драйвер и все будет хорошо". У всех есть и хорошие и плохие идеи и реализации, но: Найдите пример саморекламы у меня или у Евгения, или у Логика и т.д. Вот собственно и все, что нужно знать ...
Кстати, Ваш драйвер давал 5000 мс примерно, я его причесал до 116 мс. Но это уже не совсем Ваш драйвер, не так ли?
Я не собираюсь меряться с вами возрастом, кого это интересует - легко найдет ответ на этот вопрос. В целом, история начинает приобретать четкие очертания, так что - приношу свои извинения, за то что причислил вас к женскому полу, хоть Вы и продолжаете наставивать на "Женщина - всегда права".
Поясню, для читателей:
Я в начале темы порекомендовал использовать свой драйвер, поскольку он полностью решает задачи подобные вопросу автора топика и названия темы.
Этот "спициализд" набросился со своим срачем как базарная баба, сделав вид, что "даже не разбирался". Потом, когда ему я начал объяснять что к чему, он сделал вид что у меня в коде присутствует ошибка, которая как в конце выяснилось и вовсе не ошибка даже, а багрепорт. И все это продолжалось базарным срачем. После чего он же, выложил НЕРАБОТАЮЩИЙ код теста, с синтаксической ошибкой, и некими фотографиями по времени исполнения. То, что ОДНО НЕ СООТВЕТСТВУЕТ ДРУГОМУ, ибо просто не компилируется - ЕСТЬ ФАКТ. И каждый его способен проверить самостоятельно. Все коды выложены тут, в теме. После того, как был разобран тест .. этот "диверсант" ушел молча в кусты и молчал РОВНО ДО ТЕХ ПОР, пока я не выложил свою перепроверку его вранья.
.. далее, этот герой заявил, что он "даже улучшил" мой код и добился якобы 116мсек его исполнения, типа "причесав", но теперь оказывается что "это уже не мой код".. ВО ОНО КАК ОКАЗЫВАЕТСЯ!
Не, батенька, Вы - не баба, извиняюсь. Вы - ДИВЕРСАНТ, который СОЗНАТЕЛЬНО ВРЕТ ДЛЯ СОЗДАНИЯ ИМИДЖА. Вы такой же "искперд" как и те, кто настроил укроаинцев против русских, которым поверили Клапауции, и теперь настраивают нас против амеров и всех против РФ .. ЭТО БЛАГОДАРЯ ТАКИМ КАК ВЫ по миру льется Кровь.
Это то, что меня больше всего возмущает во всей этой теме. И теперь Вы продолжаете вилять задом "я один из тех кто к вам не относится" .. ВРЕТЕ. КРУГОМ ВРЕТЕ. Все ваши утверждения надо перепроверять на 146%.
Не тема - просто поэма!
Еще немного и всемирное зло будет повержено ))))
По существу. После допилинга Arhat109-2 привел скорость работы в разумные пределы, я думаю все Высокие Срущиеся Стороны приймут мысль что показания 140, 124 и 116 мсек можна считать с практической стороны равными. Из этого вывод простой - каким бы способом не производилась бы работа с экраном на i2c при частоте шины 800КГц достижима скорость порядка 50% от максимума.
В чем же состоит допилинг. Самое интересное здесь.
И видим здесь следующее: на один символ выводится 6 байт (не криминал, но люди разное говорят ;); вывод данных запускается неблокирующим вызовом (Вах! Хараше! Всебы так - ан нет ;); делей блокирует выполнение кода на 50мксек в течени которых в подсистеме прерываний должна быть выполнена отправка 5 байтов и инициализирована отправка 6-го. А вот это уже лажа, Arhat109-2! Не, я верю что вы написали аккуратно обработчик прерываний i2c и вобщем представляете верно: типа освободился регистр, взвелся флаг, вызвался обработчик, записали в регистр следующий байт... Проблема в том, что между "взвелся флаг" и "вызвался обработчик" может пройти достаточно много времени. Если по несчастному стечению обстоятельств как раз попало другое прерывание, например таймера. И если оно не позволяет прервать себя - а это как правило так, то прийдется ждать его завершения не один десяток мксек. Как следствие - за 50мксек не успеваем отправить 5 байт и инициализирована отправка 6-го. Возвращаемся в цикл где вызов снова lcdWrite() а в нем сразу без проверок uint8_t *_b = (uint8_t *)buf; uint8_t _l = len; затем lcdPrepare() который и ломает данные в еще не полностью выведеном буфере.
Ваш код нестабилен. Иногда работает, иногда мусор на экране.
Ну и как обычно, Вас об этом предупреждал "Причем кривой как турецкая сабля, за синзронизацию выполнения потоков (основног и прерывания) на основе ожидания. Разрабам за такое дают по рукам. т.к. либо будет ждать лишнего либо может недождатся." И как обычно Вы ничего не поняли. Пока паузы были здоровенные, они скрывали проблему, а теперь вот так оно...
вы уже определитесь хоть куда-нибудь "блокирующее тут исполнение" или "исполнение неблокировано, а СИНХРОНИЗИРОВАНО" делеем. а то мечетесь то туда, то сюда .. а в целом сильно рекомендую РАЗОБРАТЬСЯ с аппаратным I2C у мег. Он не просто хорош, он замечателен! Ну и заодно код обработчика обнаружить в библиотеке, дабы не писать ляпов в очередной раз. А то вас не поймешь то он "очень хорош", то "нестабилен" .. вы уж там договоритесь как-то промеж себя предварительно, так сказать "согласуйте позиции". :)
P.S. Да, и я не Иисус Христос, чтобы в "меня верить". Есть библиотека, есть файлик arhat_twi.c откройте и ознакомьтесь наконец-то. Зачем свое неумение читать код выставлять настолько напоказ-то? :)
P.P.S. Да, и ещё: 140мсек - результат полученный и продемонстрированный тут. 124мсек - результат не относящийся к вопросу (дисплей иной), а 116мсек - результат заявлен и подлежит ПРОВЕРКЕ. на все 146%.
Логик! Оставим его.Он же уже спалил меня, как виновника всех бед....
То, что ты написал, происходит, если снизить скорость и2с. Если оставить 50мкс и скорость100000, например. Я много играл с Архатовским драйвером. Сочетание 800 и 50 мкс устойчиво. Устройство полсуток отработало три дня назад.
Тем не менее, он в этой части прав. Работа конкретно тут только СИНХРОНИЗИРОВАНА задержкой. Поставьте задержку в 2мксек и получите "банан". Кстати, на моем дисплее задержка менее 41 миллисекунды - дает точно такой же "банан". Не знаю почему так.
Кстати, как можно проверить ваши "улучшения", что аж код "теперь не совсем мой"? Или так, болтнули лишнего ..
Andriano, в целом мой первый пост в этой теме как раз полностью решал вашу задачу:
Вот похоже что это максиум того, что можно выжать при моем подходе. Тут частота I2C установлена в 880кГц, буфер для lcdPrepare() укорочен до 4-х байт и передача идет порцией в 4 байта по 2 байта на полубайт данных. Строб устанавливается в первом байте и сбрасывается во втором. Да, и здесь подчищен код теста для повышения скорости его работы:
Изменения: отказ от операции %, которой нет в наборе команд и замена медленной у меня millis() на быструю getOvfCount(). Соответственно 95 - это количество тиков таймера по 1024мксек. В миллисекундах тест показал = 95/1.024 = 93 мсек. :)
В целом, возвращаясь к началу темы, ответ положительный. Можно быстро выводить на дисплей и при этом иметь возможность каждые 300мксек получать данные из сериала. Даже остается "запас" не менее 200 микросекунд.
Arhat109-2, спасибо (заодно скажу спасибо и за Вашу библиотеку, фрагментами которой пользуюсь).
Да, этот код, пожалуй, дает ответ на один из моих вопросов, а остальное обсуждение - и на остальные вопросы.
В результате полученной информации все больше склоняюсь к варианту установить на экран (а заодно и на несколько органов управления) отдельную Pro Mini. Возможно, там и воспользуюсь Вашим кодом. Использовать его на 2560 у меня не получится из-за дефицита свободных ног (могу подключить по i2c, но не хватает скорости, а 7 лишних ного - нет). И так запланировано 4 сдвиговых регистра - по 2 на вход и на выход. Ну и кроме опроса порта там для 2560 еще хватает другой работы.
К сожалению, Вы не посвятили всех участников в детали проекта, кроме одной заметки за "надо опрашивать порт, хотя бы каждые 300мксек". Я конечно догадываюсь что 2560 можно нагрузить большим объемом работы, но хотелось бы прочитать за хотя бы какие-то детали.
Дело в том, что эти 5518, 1118, 140, 116 или даже 95 мсек исполнения этого теста .. никоим образом не есть ответ на ваш вопрос, ибо это вовсе НЕ время работы аппаратного драйвера I2C, а "всего лишь" время работы самого теста. Сколько и как долго работает аппаратный драйвер - тут ни разу не измерялось НИКЕМ и НИЧЕМ .. помнится я уже писал про это. А, впрочем .. оно и НЕ ВАЖНО, как ни странно.
Как пример, для выпуклого показу: Вы настраиваете таймер на аппаратный ШИМ, скажем типовые 490гц и далее, всего одной командой записи в регистр изменяете его скважность. Вопрос: сколько времени требуется аппаратному таймеру чтобы скважность изменилась? Ответ: "а это кого-то волнует?" :)
Так и тут. Достоинство аппаратного I2C в том, что совершенно не важно сколько он пашет на самом деле. Его пнули - он отдал в шину. Сказали байт - отдал 1 байт, сказали 8килов - отдаст все 8. И такое невозможно при "программной эмуляции" ногодрыгами: прилетело прерывание таймера, сериала и т.д. и усё .. поплыли длительности SCL,SDA, а то и надолго. Закрывать прерывания - не выход.
А то что тут измеряли - это по сути длительность минимальной задержки в посылках, которые дисплей ещё способен переваривать. И только.
Соответственно, делаем длительность паузы между отправками пачек на дисплей любой, достаточной для отрисовки величины и спокойненько решаем свои задачи во время такой паузы .. пример я приводил выше с макрозаменой функции delay() на полезный код.
Вот этот подход и есть решение многих "проблем". То, что я Вам и хотел отписать своим первым постом.
Ну, в свое время размещал в "Проектах" http://arduino.ru/forum/proekty/analog-analogovogo-sintezatora
Вопрос в том, что нужно опрашивать MIDI-порт и выполнять MIDI-команды так, чтобы человек не ощутил какой-либо задержки, не говоря уже о пропуске команд. При этом программно генерировать все LFO и ADSR и управлять 4-мя собственными таймерами, фильтром на MAX261 и цифровым регулятором громкости.
Собственно, в той реализации, которой я пользовался, это не так, т.к. каждый байт отправляется в своем пакете. Соответственно, чтобы послать следующий, нужно дождаться, пока уйдет предыдущий.
В целом, мысль интересная (и, возможно, перспективная), но, честно говоря, сейчас мне проще поставить дополнительную Pro Mini.
В типовой реализации из LiquidCrystal_I2C все ещё хуже: там каждый полубайт мало того, что отправляется в своем пакете, так он ещё и каждый раз делает это через Wire.h, производя инициализацию передачи заново. И делает это через виртуальную связь любимой пачки классов от Stream или кто там из них "первее". После того, как мне удалось продраться сквозь всю эту белиберду и понять что на самом деле происходит .. сел и сваял свой драйвер I2C. С сериалом кстати ровно таже самая история. Надеюсь Вы пользуете свой драйвер UART/USART на аппаратных прерываниях, а не Serial.. .h?
В кратце, идея звучит банально просто: в loop() работает самый медленный поток обработки, всё что дергается аппаратно - работает из прерываний "быстро и шустро", а основной алгоритм работы вызывается из yield() или его аналога из под пауз, которые обязан отрабатывать самый медленный поток в loop().
Собственно таким измененным подходом и отличается программирование микроконтроллеров от "ЭВМ общего назначения".
В данном, конкретном случае ваще можно сделать такую вот "рыбу":
Кстати, вынеся работу с экраном в отдельное устройство, Вы ни разу не решите проблему "медленного вывода". Оно все равно всплывет, но на следующем уровне абстракции. И тогда уже, Вам полноценно понадобится всё то, чего так испугался Logik: "семафоры, очереди и т.д. и т.п."
Посмотрите внимательнее этот подход: просто, дешево и сердито. :)
Кстати, вынеся работу с экраном в отдельное устройство, Вы ни разу не решите проблему "медленного вывода". Оно все равно всплывет, но на следующем уровне абстракции.
Да.
И тогда уже, Вам полноценно понадобится всё то, чего так испугался Logik: "семафоры, очереди и т.д. и т.п."
Не провоцировать Вы уже не можете? Не испугался, а избегаю сложных неэффективных решений. А "семафоры, очереди и т.д. и т.п." на самом деле Вам нужны здесь и сейчас , а Вы от них прячитесь подбирая делеи. Как только вместо одного потока появляется 2 взаимодействующих, не суть важно даже это 2 контроллера или прерывание и луп, сразу есть проблема межпоточной синхронизации.
Что Вы предлогаете andriano, код с известной проблемой?
Тем не менее, он в этой части прав. Работа конкретно тут только СИНХРОНИЗИРОВАНА задержкой. Поставьте задержку в 2мксек и получите "банан". Кстати, на моем дисплее задержка менее 41 миллисекунды - дает точно такой же "банан". Не знаю почему так.
Не знаете почему - так я ж выше разжевал. " делей блокирует выполнение кода на 50мксек в течени которых в подсистеме прерываний должна быть выполнена отправка 5 байтов и инициализирована отправка 6-го." Если за время делея действие не выполнено то и будет Ваш "банан". Вы это увидели сократив задержку. Но и при 50мс получится тоже самое если "левое" прервание, например таймера, произойдет в течении этих 50мс и задержит выполнение прерываний i2c. Сопоставив период системного таймера около 1000мксек и делея 50мксек, возникает подозрение что даже в Вашем тесте каждая 20 строка на экране битая (чтоб подозрение переросло в увереност надо знать время обработки прерывания системного таймера). Понятно что в тесте "созерцая" на экране строку аж 1мсек глазами это незаметить. Бага вылезит в реальном приложении позже. И чем интенсивней работают прерывапния - тем чаще.
И чего вы andriano, паритесь с надумаными сложностяи. Ну опрос порта 300мксек - в прерывание по таймеру, вывод на экран в основной цикл. Всех делов то. Очевидно после опроса порта надо чегото сделать с получеными данными. Так для этого есть минимум 300мксек (про максимум можно поговорить отдельно, там и 600 вероятно не проблема) до следующего прерывания, вполне достаточно я думаю.