RSS блога
Подписка
Электронная бумага: пишем драйвер методом научного тыка
В предыдущей статье я рассказывал, как я затарился электроннобумажными дисплеями и даже сделал для них блок питания.
Наконец, пришли заказанные для них печатные платы и теперь можно заняться программным обеспечением. То, что описано ниже, касается только ED060SC4(LF) или LB060S01-RD02. Отличие в названии на одну букву, даже ту, что в скобке — и работать ничего не будет. Когда я задумал это безнадежное занятие, мне казалось, что я нашел кучу информации и исходников, и запустить этот дисплей проблемой не будет, несмотря на очень убогие спецификации от производителей. Не тут-то было, в каких-то местах описание оказалось на дисплей, название которого отличалась на одну букву, а в других — алгоритм просто не работал. В наше время верить нельзя никому, даже самому себе. Мне — можно.
Целых два дня я тупо перебирал очередность разных сигналов и задержки между ними, не зная, жив ли еще дисплей. Не было даже намеков на появившуюся точку. И в один прекрасный момент — вуаля! — получите целую линию мусора. Всё, больше ничего и не надо, все остальное, дело техники, теперь он никуда не денется.
Теперь расскажу, как все-таки удалось запустить это чудо. На истину в последней инстанции я не претендую, как заработало — так и опишу.
Для прорисовки экрана нужны следующие сигналы — сначала начало кадра, потом 600 строк, каждая имеет старт, потом данные и стоп. Завершается все концом кадра. За один пиксель отвечает два бита, комбинация 01 — черный цвет, 10 — белый, остальные — без изменения.
Таким образом, для одной строки из 800 пикселей нужно передать 200 байт.
Схема простая — источник питания, описанный в прошлой статье, STM32F103C8 для управления дисплеем и ESP32 на все про все, но пока его не используем.
Ардуним для начала — определяем макросы, которые будут управлять сигналами.
Ведь правду говорят — ардуино это для совсем отстойных, которым лень думать и документацию читать.
Старт кадра выглядит так:
и код:
Потом передаем 600 строк, каждая начинается так:
Уж все безумно просто:
Завершение строки очень критично, чуть что не так — и никакого изображения не будет:
Код, соответственно:
И завершаем кадр:
Котд:
void end_frame()
{
GMODE_IDLE
delay_us(1);
Vclock();
}
Все вместе образует вот такое безобразие:
И, наконец, тестовый код:
Извиняйте, если уж сильно тривиально все выглядит. Если бы мне все это кто-то рассказал до того, как я эту возню затеял…
Может, кому другому поможет.
А это то, что этот тест делает — рисует шахматную доску. Смотрим скорость обновления — получается более, чем достойно, судите сами:
За один цикл прорисовки черные точки получить не удастся, получаются серые. У меня для получения черного цвета нужно повторить передачу кадра раз 6 — для пущей надежности я передаю его 8 раз.
В реальном устройстве присутствует lookup table, где хранятся данные о длительностях сигналов в зависимости от температуры и интенсивности черного. Почему-то производители сделали большой секрет из этих данных, поэтому имеем то, что имеем. У реального контроллера дисплея куча памяти, где он хранит изображение и следующее формируется в зависимости от предыдущего — не нужно полностью стирать изображение и потом рисовать все по новой — обновление происходит с учетом текущего состояния, поэтому его можно выполнить быстрее. Но оперативной памяти нужно много — ведь у экрана 480 000 пикселей.
По схеме видно, что микроконтроллер у меня дохленький, у него всего 20К ОЗУ и 64К флеш.
Но я использую буфер длиной всего 200 байт, и каждую строку просчитываю перед выводом.
Что-то подобное я использовал много лет назад, когда делал полетный контроллер для игрушечного самолетика и выводил изображение поверх картинки с видеокамеры — там, если склероз не подводит, вообще у контроллера было 4К ОЗУ. И сделано было еще интереснее — пока контроллер прямого доступа выбрасывал одну строку, процессор просчитывал следующую. В итоге использовалось 4 буфера — два для белого и 2 для черного.
Это было небольшое отступление. В реальных дисплеях производители обычно используют 16 градаций серого, но у любителей получается и 32 использовать.
Но мне это не надо, двух уровней черного для моих целей достаточно и я легко это сделаю использованием количества перезаписываний кадра.
Алгоритм с многократной перезаписью кадра выглядит убого, если у кто знает, как сделать лучше — пожалуйста, напишите в комментариях. Моя благодарность не будет иметь границ (в разумных пределах).
Следующим шагом будет добыча погоды из интернета и формирование полного кадра, но для этого будет использоваться ESP32, а STM32 будет играть роль тупого драйвера. Печатную плату тоже планирую переделать — контрольные точки уже не нужны, зато надо добавить управление питанием, планируется использовать литиевый аккумулятор. Нужно добавить зарядку и позаботиться о уменьшении потребления энергии устройством.
А пока можно немного размяться и с STM32:
С ESP32 тоже не все так просто — при попытке выделить массив под кадр больше 96К, линкер отказывается работать, заявляя что все, памяти у него для вас больше нет. А где же ваши хваленые 320K Data RAM? При попытке выбросить SPI пакет, непрерывного потока не получается — после каждых 64 байта, кажется, идет разрыв несколько микросекунд. Но кому сейчас легко — будем бороться.
Небольшое скакание по исходникам показало, что посылка действительно разбивается, и это происходит в HAL — наверно, разработчики контроллера имели какую-то причину? Или они просто злобные Буратины, вся цель жизни которых — нагадить мне?
Библиотеку можно подправить, но при первом же обновлении мои правки накроются медным тазом. Пусть будет, как есть — не особо мешает.
Еще вариант — поставить дополнительную SPI RAM к дохленькому контоллеру. Где ее купить недорого — пока не нашел. А ставить мощный контроллер в качестве драйвера не особо хочется — у них и цена кусается, и слишком много ног, одни проблемы с пайкой.
RP2040 с его 264KB SRAM и программируемыми выводами выглядит хорошо, только там SRAM сегментирована по 64KB — опяь могут быть проблемы с буфером кадра. И кушать много изволит в спящем режиме. Что-то душа к нему не лежит. Короче, куда не кинь — везде клин, нет в жизни счастья :)
Гда брать погоду — еще одна проблема. Меньше всего ограничений у open-meteo.com, но они, как настоящие джентельмены, меняют правила по ходу игры. А поначалу смотрелось неплохо — регистрация не нужна, информацию можно брать по максимуму и безо всяких ограничений на запросы. Прогноз, надо сказать, не особо точный и еще и глюки имеются — как-то за окном шел дождь, а они на осадки на текущий день прогнозировали отрицательную величину. Интересно, это как?
Наверно, самый популярный сайт — это openweathermap.org, но они очень хотят денег и всячески затрудняют жизнь халявщиков. И необходимость регистрации и ограничение на запросы не радуют, хотя ограничения на запросы вполне разумные. Но информации open-meteo дает больше, хоть и неправильной.
Dark Sky куплена Apple, так что ловить там уже нечего.
Первые тесты выглядят так (прогноз с open-meteo):
Пока статья писалась — и новая схема поспела, можете покритиковать при желании, только не сильно:
Антенна оказалась рядом с металлом дисплея. Он весь покрыт металлом, а плата будет к нему приклеена.
Когда коту делать нечего — он платы разводит. Переделываем все так, чтобы антенна выступала из-за экрана:
Почему эта статья не на Хабре? Причин много — во-первых, там все рисуют какого-то бегемота в колпачке, а я даже не знаю, откуда он взялся, неудобно как-то (это про картинку слева, а про котенка с улицы Лизюкова я знаю).
Кроме того, там какие-то страшные джуны, мидлы и тимлиды проходят интервью и получают оферы. Может, это больно?
На английском, было дело, я наваял кучку сайтов, доверившись Гуглу и его репутации — через какое-то время их прихлопнули. Больше не хочется время терять.
А здесь хоть плюсик поставят :) — уже видно, что не зря старался.
В комментариях часто здравую идею подскажут — тоже польза.
Ну и писать на английском — это все-таки труд, а на русском — развлечение. Графоманы подтвердят.
Кстати, анонс — Марио таки ограбил банк, так что впереди много интересного.
Что это и с чем это едят — можно посмотреть здесь и здесь.
Наконец, пришли заказанные для них печатные платы и теперь можно заняться программным обеспечением. То, что описано ниже, касается только ED060SC4(LF) или LB060S01-RD02. Отличие в названии на одну букву, даже ту, что в скобке — и работать ничего не будет. Когда я задумал это безнадежное занятие, мне казалось, что я нашел кучу информации и исходников, и запустить этот дисплей проблемой не будет, несмотря на очень убогие спецификации от производителей. Не тут-то было, в каких-то местах описание оказалось на дисплей, название которого отличалась на одну букву, а в других — алгоритм просто не работал. В наше время верить нельзя никому, даже самому себе. Мне — можно.
В целях природы обуздания,
В целях рассеять неученья
Тьму
Берём картину мироздания – да!
И тупо смотрим, что к чему…
Целых два дня я тупо перебирал очередность разных сигналов и задержки между ними, не зная, жив ли еще дисплей. Не было даже намеков на появившуюся точку. И в один прекрасный момент — вуаля! — получите целую линию мусора. Всё, больше ничего и не надо, все остальное, дело техники, теперь он никуда не денется.
Теперь расскажу, как все-таки удалось запустить это чудо. На истину в последней инстанции я не претендую, как заработало — так и опишу.
Для прорисовки экрана нужны следующие сигналы — сначала начало кадра, потом 600 строк, каждая имеет старт, потом данные и стоп. Завершается все концом кадра. За один пиксель отвечает два бита, комбинация 01 — черный цвет, 10 — белый, остальные — без изменения.
Таким образом, для одной строки из 800 пикселей нужно передать 200 байт.
Схема простая — источник питания, описанный в прошлой статье, STM32F103C8 для управления дисплеем и ESP32 на все про все, но пока его не используем.
Ардуним для начала — определяем макросы, которые будут управлять сигналами.
Нажми меня
// ****************************************************
// power control
// en positive PB6
// en negative PB7
// en VDD PB8
//
#define INIT_POWER GPIOB->regs->CRL &= 0x00FFFFFF;\
GPIOB->regs->CRL |= 0x11000000;\
GPIOB->regs->CRH &= 0xFFFFFFF0;\
GPIOB->regs->CRH |= 0x00000001;\
GPIOB->regs->BRR = 0x01C0;
#define PWR_VDD_ON GPIOB->regs->BSRR = 0x0100;
#define PWR_VDD_OFF GPIOB->regs->BRR = 0x0100;
#define PWR_POS_ON GPIOB->regs->BSRR = 0x0040;
#define PWR_POS_OFF GPIOB->regs->BRR = 0x0040;
#define PWR_NEG_ON GPIOB->regs->BSRR = 0x0080;
#define PWR_NEG_OFF GPIOB->regs->BRR = 0x0080;
#define PWR_ALL_ON GPIOB->regs->BSRR = 0x01C0;
#define PWR_ALL_OFF GPIOB->regs->BRR = 0x01C0;
// ****************************************************
// SPV and SPH high, and all other pins low
// data
#define DATA_PORT GPIOA
// CL LE OE CPH GMODE SPV CKV
// CL PB9
#define CL_PORT GPIOB
#define CL_PIN 9
// LE PC13
#define LE_PORT GPIOC
#define LE_PIN 13
// OE PC14
#define OE_PORT GPIOC
#define OE_PIN 14
// CPH PC15
#define CPH_PORT GPIOC
#define CPH_PIN 15
// GMODE PB0
#define GMODE_PORT GPIOB
#define GMODE_PIN 0
// CKV PCB2
#define CKV_PORT GPIOB
#define CKV_PIN 2
// SPV PB1
#define SPV_PORT GPIOB
#define SPV_PIN 1
// DATA
// PC0...PC7
// PA0...PA7
#define INIT_DATA DATA_PORT->regs->CRL = 0x33333333; DATA_PORT->regs->BRR = 0xFF;
#define INIT_CL CL_PORT->regs->CRH &= ~(0xF << ((CL_PIN &0x7)<<2)); CL_PORT->regs->CRH |= 0x3 << ((CL_PIN &0x7)<<2);
#define CL_IDLE CL_PORT->regs->BRR = 1<<CL_PIN; // reset
#define CL_ACTIVE CL_PORT->regs->BSRR = 1<<CL_PIN; // set
#define INIT_LE LE_PORT->regs->CRH &= ~(0xF << ((LE_PIN &0x7)<<2)); LE_PORT->regs->CRH |= 0x3 << ((LE_PIN &0x7)<<2);
#define LE_IDLE LE_PORT->regs->BRR = 1<<LE_PIN; // reset
#define LE_ACTIVE LE_PORT->regs->BSRR = 1<<LE_PIN; // set
#define INIT_GMODE GMODE_PORT->regs->CRL &= ~(0xF << ((GMODE_PIN &0x7)<<2)); GMODE_PORT->regs->CRL |= 0x3 << ((GMODE_PIN &0x7)<<2);
#define GMODE_IDLE GMODE_PORT->regs->BRR = 1<<GMODE_PIN; // reset
#define GMODE_ACTIVE GMODE_PORT->regs->BSRR = 1<<GMODE_PIN; // set
#define INIT_CKV CKV_PORT->regs->CRL &= ~(0xF << ((CKV_PIN &0x7)<<2)); CKV_PORT->regs->CRL |= 0x3 << ((CKV_PIN &0x7)<<2);
#define CKV_IDLE CKV_PORT->regs->BRR = 1<<CKV_PIN; // reset
#define CKV_ACTIVE CKV_PORT->regs->BSRR = 1<<CKV_PIN; // set
#define INIT_SPV SPV_PORT->regs->CRL &= ~(0xF << ((SPV_PIN &0x7)<<2)); SPV_PORT->regs->CRL |= 0x3 << ((SPV_PIN &0x7)<<2);
#define SPV_IDLE SPV_PORT->regs->BRR = 1<<SPV_PIN; // reset
#define SPV_ACTIVE SPV_PORT->regs->BSRR = 1<<SPV_PIN; // set
#define INIT_OE OE_PORT->regs->CRH &= ~(0xF << ((OE_PIN &0x7)<<2)); OE_PORT->regs->CRH |= 0x3 << ((OE_PIN &0x7)<<2);
#define OE_IDLE OE_PORT->regs->BRR = 1<<OE_PIN; // reset
#define OE_ACTIVE OE_PORT->regs->BSRR = 1<<OE_PIN; // set
#define INIT_CPH CPH_PORT->regs->CRH &= ~(0xF << ((CPH_PIN &0x7)<<2)); CPH_PORT->regs->CRH |= 0x3 << ((CPH_PIN &0x7)<<2);
#define CPH_IDLE CPH_PORT->regs->BRR = 1<<CPH_PIN; // reset
#define CPH_ACTIVE CPH_PORT->regs->BSRR = 1<<CPH_PIN; // set
void Vclock()
{
CKV_ACTIVE
CKV_IDLE
}
void Hclock()
{
CL_ACTIVE
CL_IDLE
}
void PowerOn(void)
{
PWR_VDD_ON
delay(30);
PWR_NEG_ON
delay(5);
PWR_POS_ON
}
void PowerOff(void)
{
PWR_POS_OFF
delay(5);
PWR_NEG_OFF
delay(5);
PWR_VDD_OFF
}
Ведь правду говорят — ардуино это для совсем отстойных, которым лень думать и документацию читать.
Старт кадра выглядит так:
и код:
void start_frame()
{
GMODE_ACTIVE
delay_us(1);
CKV_ACTIVE
delay_us(1);
SPV_IDLE
delay_us(1);
CKV_IDLE
delay_us(1);
CKV_ACTIVE
delay_us(1);
SPV_ACTIVE
delay_us(1);
}
Потом передаем 600 строк, каждая начинается так:
Уж все безумно просто:
void start_row()
{
CPH_IDLE
}
Завершение строки очень критично, чуть что не так — и никакого изображения не будет:
Код, соответственно:
void stop_row()
{
CPH_ACTIVE
CKV_IDLE
Hclock();
CKV_ACTIVE
OE_IDLE
delay_us(2);
OE_ACTIVE
LE_ACTIVE
LE_IDLE
}
И завершаем кадр:
Ко
void end_frame()
{
GMODE_IDLE
delay_us(1);
Vclock();
}
Все вместе образует вот такое безобразие:
И, наконец, тестовый код:
Нажми, если хочешь
<code>uint8_t data;
void setup()
{
INIT_POWER
GPIOB->regs->CRH &= 0xFFFFF0FF; //pinMode(PB10, OUTPUT); 2MHz
GPIOB->regs->CRH |= 0x00000200;
// USB pin open drain
GPIOA->regs->CRH &= 0xFFFFF0FFF;
GPIOA->regs->CRH |= 0x000000600;
GPIOA->regs->BRR = 1<<10; // digitalWrite(PA10,0);
delay(100);
GPIOA->regs->BSRR = 1<<10; // digitalWrite(PA10,1);
Serial.begin();
Serial.println("E-paper test");
INIT_DATA
INIT_CL
CL_IDLE
INIT_GMODE
GMODE_IDLE
INIT_CKV
CKV_IDLE
INIT_SPV
SPV_ACTIVE
INIT_OE
OE_IDLE
INIT_CPH
CPH_ACTIVE
INIT_LE
LE_IDLE
data=0xaa;
}
void loop()
{
uint8_t tdata;
GPIOB->regs->BSRR = 1<<10; // LED on
PowerOn();
delay(100);
for (uint16_t k=0; k<6; k++)
{
static bool even=false;
start_frame();
// write frame
for (uint16_t i=0; i<600; i++)
{
// wrire row
if (even) tdata = data;
else tdata = ~data;
if((i & 0x3f)==0) even = !even;
start_row();
//data = 0;
for (uint16_t j=0; j<200; j++)
{
if((j & 0x0f)==0) tdata = ~tdata;
DATA_PORT->regs->BRR = 0xFF;
DATA_PORT->regs->BSRR = tdata;
Hclock();
}
stop_row();
}
}
data = ~data;
end_frame();
delay(10);
PowerOff();
GPIOB->regs->BRR = 1<<10; // LED off
delay(2000);
}
Извиняйте, если уж сильно тривиально все выглядит. Если бы мне все это кто-то рассказал до того, как я эту возню затеял…
Может, кому другому поможет.
А это то, что этот тест делает — рисует шахматную доску. Смотрим скорость обновления — получается более, чем достойно, судите сами:
За один цикл прорисовки черные точки получить не удастся, получаются серые. У меня для получения черного цвета нужно повторить передачу кадра раз 6 — для пущей надежности я передаю его 8 раз.
В реальном устройстве присутствует lookup table, где хранятся данные о длительностях сигналов в зависимости от температуры и интенсивности черного. Почему-то производители сделали большой секрет из этих данных, поэтому имеем то, что имеем. У реального контроллера дисплея куча памяти, где он хранит изображение и следующее формируется в зависимости от предыдущего — не нужно полностью стирать изображение и потом рисовать все по новой — обновление происходит с учетом текущего состояния, поэтому его можно выполнить быстрее. Но оперативной памяти нужно много — ведь у экрана 480 000 пикселей.
По схеме видно, что микроконтроллер у меня дохленький, у него всего 20К ОЗУ и 64К флеш.
Но я использую буфер длиной всего 200 байт, и каждую строку просчитываю перед выводом.
Что-то подобное я использовал много лет назад, когда делал полетный контроллер для игрушечного самолетика и выводил изображение поверх картинки с видеокамеры — там, если склероз не подводит, вообще у контроллера было 4К ОЗУ. И сделано было еще интереснее — пока контроллер прямого доступа выбрасывал одну строку, процессор просчитывал следующую. В итоге использовалось 4 буфера — два для белого и 2 для черного.
Это было небольшое отступление. В реальных дисплеях производители обычно используют 16 градаций серого, но у любителей получается и 32 использовать.
Но мне это не надо, двух уровней черного для моих целей достаточно и я легко это сделаю использованием количества перезаписываний кадра.
Алгоритм с многократной перезаписью кадра выглядит убого, если у кто знает, как сделать лучше — пожалуйста, напишите в комментариях. Моя благодарность не будет иметь границ (в разумных пределах).
Следующим шагом будет добыча погоды из интернета и формирование полного кадра, но для этого будет использоваться ESP32, а STM32 будет играть роль тупого драйвера. Печатную плату тоже планирую переделать — контрольные точки уже не нужны, зато надо добавить управление питанием, планируется использовать литиевый аккумулятор. Нужно добавить зарядку и позаботиться о уменьшении потребления энергии устройством.
А пока можно немного размяться и с STM32:
С ESP32 тоже не все так просто — при попытке выделить массив под кадр больше 96К, линкер отказывается работать, заявляя что все, памяти у него для вас больше нет. А где же ваши хваленые 320K Data RAM? При попытке выбросить SPI пакет, непрерывного потока не получается — после каждых 64 байта, кажется, идет разрыв несколько микросекунд. Но кому сейчас легко — будем бороться.
Небольшое скакание по исходникам показало, что посылка действительно разбивается, и это происходит в HAL — наверно, разработчики контроллера имели какую-то причину? Или они просто злобные Буратины, вся цель жизни которых — нагадить мне?
Дополнительная информация
void spiWriteNL(spi_t * spi, const void * data_in, uint32_t len){
if(!spi) {
return;
}
size_t longs = len >> 2;
if(len & 3){
longs++;
}
uint32_t * data = (uint32_t*)data_in;
size_t c_len = 0, c_longs = 0;
while(len){
c_len = (len>64)?64:len;
c_longs = (longs > 16)?16:longs;
spi->dev->mosi_dlen.usr_mosi_dbitlen = (c_len*8)-1;
#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32
spi->dev->miso_dlen.usr_miso_dbitlen = 0;
#endif
for (size_t i=0; i<c_longs; i++) {
spi->dev->data_buf[i] = data[i];
}
#if CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3
spi->dev->cmd.update = 1;
while (spi->dev->cmd.update);
#endif
spi->dev->cmd.usr = 1;
while(spi->dev->cmd.usr);
data += c_longs;
longs -= c_longs;
len -= c_len;
}
}
Библиотеку можно подправить, но при первом же обновлении мои правки накроются медным тазом. Пусть будет, как есть — не особо мешает.
Еще вариант — поставить дополнительную SPI RAM к дохленькому контоллеру. Где ее купить недорого — пока не нашел. А ставить мощный контроллер в качестве драйвера не особо хочется — у них и цена кусается, и слишком много ног, одни проблемы с пайкой.
RP2040 с его 264KB SRAM и программируемыми выводами выглядит хорошо, только там SRAM сегментирована по 64KB — опяь могут быть проблемы с буфером кадра. И кушать много изволит в спящем режиме. Что-то душа к нему не лежит. Короче, куда не кинь — везде клин, нет в жизни счастья :)
Гда брать погоду — еще одна проблема. Меньше всего ограничений у open-meteo.com, но они, как настоящие джентельмены, меняют правила по ходу игры. А поначалу смотрелось неплохо — регистрация не нужна, информацию можно брать по максимуму и безо всяких ограничений на запросы. Прогноз, надо сказать, не особо точный и еще и глюки имеются — как-то за окном шел дождь, а они на осадки на текущий день прогнозировали отрицательную величину. Интересно, это как?
Наверно, самый популярный сайт — это openweathermap.org, но они очень хотят денег и всячески затрудняют жизнь халявщиков. И необходимость регистрации и ограничение на запросы не радуют, хотя ограничения на запросы вполне разумные. Но информации open-meteo дает больше, хоть и неправильной.
Dark Sky куплена Apple, так что ловить там уже нечего.
Первые тесты выглядят так (прогноз с open-meteo):
Пока статья писалась — и новая схема поспела, можете покритиковать при желании, только не сильно:
Антенна оказалась рядом с металлом дисплея. Он весь покрыт металлом, а плата будет к нему приклеена.
Когда коту делать нечего — он платы разводит. Переделываем все так, чтобы антенна выступала из-за экрана:
Почему эта статья не на Хабре? Причин много — во-первых, там все рисуют какого-то бегемота в колпачке, а я даже не знаю, откуда он взялся, неудобно как-то (это про картинку слева, а про котенка с улицы Лизюкова я знаю).
Кроме того, там какие-то страшные джуны, мидлы и тимлиды проходят интервью и получают оферы. Может, это больно?
На английском, было дело, я наваял кучку сайтов, доверившись Гуглу и его репутации — через какое-то время их прихлопнули. Больше не хочется время терять.
А здесь хоть плюсик поставят :) — уже видно, что не зря старался.
В комментариях часто здравую идею подскажут — тоже польза.
Ну и писать на английском — это все-таки труд, а на русском — развлечение. Графоманы подтвердят.
Кстати, анонс — Марио таки ограбил банк, так что впереди много интересного.
Что это и с чем это едят — можно посмотреть здесь и здесь.
Самые обсуждаемые обзоры
+77 |
3959
147
|
+58 |
4112
73
|
Лучше напишите конечный ценник на эти игрушки, вкл. все затраты и обслуживание и всё само собой прояснится!
Да, а сама статья про драйвера прекрасна — СПАСИБО ВАМ!
Статья про цифровые ценники лежит в черновиках, будет опубликована в начале следующего месяца. Там будет малая часть информации, в основном с чем я сам игрался.
А что со всем.этим делать — я и сам толком пока не знаю, там более, что у меня их больше полусотни. Бывшие в употреблении можно купить начиная с одного евро — правда, партия в 500 штук :)
Ждем статью про ценники!
С улицы им. генерала Александра Ильича Лизюкова в г. Воронеже же! ;)
Был когда-то там завсегдатаем, но злобные олдфаги постоянно норовили слить карму за безобидные комментарии только потому, что придерживались иного мнения.
P.S.
Для второй ссылки нужен VPN, хотя итак можно догадаться, что там.
Ссылку поменял на другую, вроде должна работать.
А платы вы в чем разводите?
И какой формат видео шел с камеры?
Те кто подключают LCD дисплеи высокого разрешения используют модули с PSRAM
Интересно, ESP32S3 по параллельному интерфейсу будет работать с этим дисплеем?
Идеально подружить это все с Adafruit GFX через Framebuffer. Там всего то нужно свою функцию обновления экрана из FB прикрутить. Тогда и с обновлениями будет полегче
И получают кучу минусов )))
К счастью, там попадаются статьи вроде вашей (правда на 90% переводы), поэтому и есть пока еще что почитать
А во времена WinME я баловался изучением алгоритма работы I2C шины монитора, которая в VGA/DVI кабеле. Через VESA функции BIOS видеокарты находил адреса всех I2C портов, а потом уже из Виндовса, запрещал прерывания и читал/писал в тот порт.
Программ, которые умеют крутить яркость/контрастность и прочее для ЭЛТ мониторов Samsung ещё не было. Была только сервисная программа Samsung, работавшая через специальную LPT-плату. А у меня то же самое через видеокарту получилось! Эх хорошие времена были для программирования.
Разработчики времен MS-DOS читают с недоумением. У них тоже были сегменты по 64К, и жили — не тужили.
Возможно чуть полегче жилось пользователям других расширителей памяти типа DOS4GW, но ни разу не видел, чтоб это использовалось в обычных программах (не играх).
А в WinME + Delphi7 можно было объявлять массивы хоть 10 Мб, и не парится насчёт того, как туда обращаться!
Это 32-битная ось, тут у процесса 4 ГБ виртуального адресного пространства. Естественно, 10 МБ — не вопрос для неё, даже 256 МБ и 1 ГБ (при определенных условиях) можно было выделять непрерывным блоком.
С ESP32 глубоко разбираться лениво, тем более, что там многое не описано, а доступно в виде библиотек. По крайней мере документации с точностью до каждого бита я не видел.
Да и не особо мешает — потеря скорости передачи процент-другой, а на изображение не влияет.
Затык по скорости получается у SPI приемника STM32 — он обрабатывает прерывания и формирует сигналы не так быстро, как хотелось бы. Вот там можно было увеличить скорость уже раза в 2.
я было начал писать статью но забил
Пару лет назад такую писал под Linux. Там, кстати, намного проще доступ до I2C. Даже прерывания отключать не надо.
Чисто интересно: а примерно с какой частотой у вас получилось I2C передачу данных проводить, тем более с параллельно работающими чужими процессами?
DDC вроде как до 400 кГц должен тянуть, а 100 уж точно может. Да там это не так критично.
А то, что частота процов сейчас плавает, кстати, на rdtsc никак не влияет — поскольку её изначально абьюзили для измерения времени, производителям пришлось делать заплатку, чтобы TSC продолжал измерять время и на современных многоядерных процессорах с плавающей частотой.
Добавлю от себя тот самый плюс.
А серьезно — нужно значительно больше ног, чем есть у ESP32. Народ в аналогичных случаях ставит несколько сдвиговых регистров. Меня больше второй процессор устраивает — гибче получается и при необходимости с минимальное переделкой программы можно использовать там, где не нужен WiFi.
Один процессор с WiFi и много ног дешево и доступно уже не получается.
Довольно интересный проект. Там принцип схожий, динамический диапазон яркости реализуется за счет преобразования веса разрядности цвета в количество повторов свечения пикселей в двоичном коде по степени двойки. У вас можно реализовать похожий алгоритм только наизнанку — взять 3-5 битный серый и чем больше «черноты», тем больше вес BCM.
Кадровый буфер при этом строится в виде связанного списка, что делает ненужным аллокацию больших сплошных блоков памяти и экономит на повторяющихся строках. Вывод там реализован через параллельный i2s dma, но, думаю, вполне можно адаптировать под SPI или RMT при желании. Вообще у есп32 есть неплохие возможности если не полениться покурить IDF. Ну и плат с PSRAM чипом на борту навалом.