Перейти к содержанию
    

Контроллер дисплея ILI9341: (4-проводный SPI-II): работает только с паузой между байтами ~1 мкс

Здравствуйте!

Столкнулся со странной проблемой:

Есть QVGA дисплей с набортной ILI9341. Используется интерфейс "4-wire SPI Interface II".

Все работает замечательно, если между байтами есть пауза около 1 мкс. Перестает работать если пауза уменьшается до примерно 0.8 мкс.

Пробовал на разных скоростях SPI: от 10 до 25 МГц, результат одинаков: с паузой работает, без паузы нет.

Никто не сталкивался?

 

Эффект стабильный, не единичный брак.

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

использую в STM32F429б 168 MHz ядра

мой код установки бита экрана ниже.

Работает только если "delay_after_byte()" содержит задержку примерно 1 us.

void display_send_byte2(uint8_t byte)
{
  while (!SPI_I2S_GetFlagStatus(DISPLAY_SPI, SPI_I2S_FLAG_TXE));
  *(uint8_t*)&(DISPLAY_SPI->DR) = byte;
  delay_after_byte();
}

void display_draw_pixel2(uint16_t x, uint16_t y, uint16_t color)
{
	display_cs_low();					//CS is enabled (set to LOW)
	// display_set_active_area(x, y, x, y);
	{
		//display_send_command(ILI9341_COLUMN_ADDR);
		display_dc_low();                       	//command mode for next bytes
		display_send_byte2(ILI9341_COLUMN_ADDR); 
		display_dc_high();				// data mode for next bytes
		display_send_byte2(x >> 8);
		display_send_byte2(x & 0xFF);
		display_send_byte2(x >> 8);
		display_send_byte2(x & 0xFF);
		display_dc_low();                       	//command mode for next bytes
		display_send_byte2(ILI9341_PAGE_ADDR);
		display_dc_high();				// data mode for next bytes
		display_send_byte2(y >> 8);
		display_send_byte2(y & 0xFF);
		display_send_byte2(y >> 8);
		display_send_byte2(y & 0xFF);
	}
	//display_send_command(ILI9341_GRAM);
	display_dc_low();                       	//command mode for next bytes
	display_send_byte2(ILI9341_GRAM);
	display_dc_high();							// data mode for next bytes
	display_send_byte2(color >> 8);
	display_send_byte2(color & 0xFF);

	while (!SPI_I2S_GetFlagStatus(DISPLAY_SPI, SPI_I2S_FLAG_TXE));
	while (SPI_I2S_GetFlagStatus(DISPLAY_SPI, SPI_I2S_FLAG_BSY));
	display_cs_high();					//CS is disabled (set to HIGH)
}

У меня на обход экрана примерно секунда тратится, что явно не есть гут. Да, работает. Но как-то уж очень меееедленноооооо....

Изменено пользователем Ruslan1
ошибка в названии "IL9341", должно быть "ILI9341"

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Как часто бывает- пока спрашивал что-то начало доходить.

Кажется понял.

Бит C/CX защелкивается в конце передачи байта. То есть нужно сначала передать, а потом менять режим с комаанды на данные и обратно. А время 1 мкс- это просто время до конца передачи байта. Получается, нужно ждять окончания передачи до переключения режима как и до деактивации CS. Попробую.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

1 hour ago, Ruslan1 said:

Бит C/CX защелкивается в конце передачи байта. То есть нужно сначала передать, а потом менять режим с комаанды на данные и обратно. А время 1 мкс- это просто время до конца передачи байта. Получается, нужно ждять окончания передачи до переключения режима как и до деактивации CS. Попробую.

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

То-то я не мог понять, почему в исходниках интернетовских всегда ждут окончания передачи байта прямо в функции передачи- просто это универсальный путь, гарантирующий отсутствие такой проблемы как у меня. Но неоптимальный по скорости.

И еще для скорости дефайны рулят. "INLINE" - это только просьба компилятору, а не требование. Набегает много, когда в кадре сотни тысяч вызовов.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

2 часа назад, Ruslan1 сказал:

У меня на обход экрана примерно секунда тратится, что явно не есть гут. Да, работает. Но как-то уж очень меееедленноооооо....

Потому что нужно использовать DMA + событийное программирование, а не суперцикл. И такого

2 часа назад, Ruslan1 сказал:

while (!SPI_I2S_GetFlagStatus(DISPLAY_SPI, SPI_I2S_FLAG_TXE)); while (SPI_I2S_GetFlagStatus(DISPLAY_SPI, SPI_I2S_FLAG_BSY));

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

1 hour ago, jcxz said:

Потому что нужно использовать DMA + событийное программирование, а не суперцикл. И такого

....

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

Вы смешали мух с котлетами.

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

 

Ваш путь с DMA- применительно к обслуживанию пикселя- бесполезен. Даже нагрузку на МК не снизит и скорость не поменяет, так как передаются группы от 1 до 4 байт. Тут нужно сначала подход менять (переход от попиксельной обработки к пообъектной), а уж потом можно и DMA к большим объемам применять.

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Ну, в-общем, ускорил практически до максимума, получил вполне приемлемые для меня времянки около 65 мс на полную перерисовку дисплея (стирание+новый текст). DMA, ожидание по семафору, принудительное переключение задач...

Но осадочек остался: из этого времени стирание (заполнение QVGA дисплея одним цветом) занимает около 40 мс при тактовой SPI 20 MHz, и тут ничего не сделать (240*320*2 = 153600 байт).

Очень жаль, что у этого контроллера ILI9341 нет специальной команда "заполнить CGRAM указанной величиной". Понимаю, что можно вводить хитрые алгоритмы и перерисовывать только необходимое для ускорения, но это буду делать только когда понадобится мультики в реалтайме рисовать.

Или если бы ILI9341 в псевдотекстовый режим перевести, с заливкой в него шрифта. Или хотя бы в 8-битный режим кодировки цвета пикселя. Но это так, мысли вслух. Хороший контроллер, но не хватает подобных мелочей.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

On 2/14/2020 at 11:18 AM, Ruslan1 said:

void display_send_byte2(uint8_t byte) { while (!SPI_I2S_GetFlagStatus(DISPLAY_SPI, SPI_I2S_FLAG_TXE)); *(uint8_t*)&(DISPLAY_SPI->DR) = byte; delay_after_byte(); }

Поставить volatile:

*(volatile uint8_t*)&(DISPLAY_SPI->DR) = byte;

Кстати, на spi этот дисплей по паспорту 10 МГц по паспорту кажется.

Если можете себе позволить держать видео буфер в памяти - меняйте в растре в памяти и выводите без стирания просто новое изображение. Или в прямоугольной области если изменения локальны.

Изменено пользователем GenaSPB

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

56 minutes ago, GenaSPB said:

Поставить volatile:

*(volatile uint8_t*)&(DISPLAY_SPI->DR) = byte;

Кстати, на spi этот дисплей по паспорту 10 МГц по паспорту кажется.

Если можете себе позволить держать видео буфер в памяти - меняйте в растре в памяти и выводите без стирания просто новое изображение. Или в прямоугольной области если изменения локальны.

 

volatile: Вы имеете в виду чтоб при оптимизации не исчезло? Ну так все эти регистры в дефайнах и так volatile.

Про частоту: официально 10 МГц, но реально и 20 и больше стабильно пашет в industrial grade. Да и интернет завален его "оверклокингом", кажется и 50 МГц видел. 

Думал про полный буфер. Главный плюс: в программировании универсально и красиво с точеки зрения обслуживвания. Но это чисто ублажить внутреннего перфекциониста. А так- RAM жалко, и в плане быстродействия найду не больше 25%.

Проблема в том, что запись полного экрана занимает львиную долю всего обмена, у меня- около 75%  времени. То есть как ни крутись, ускорить более чем на 25% не смогу.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Вы привели к указателю на 8 бит тип с потерей volatile. Справа там могло быть что угодно, хоть целое. 

А когда такие проблемы со скоростью обновления начинаются пора задуматься об LTDC. Найти тот же ILI9341 выведенными ногами режима RGB как на Дискавери.

Изменено пользователем GenaSPB

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

9 hours ago, GenaSPB said:

Вы привели к указателю на 8 бит тип с потерей volatile. Справа там могло быть что угодно, хоть целое. 

А когда такие проблемы со скоростью обновления начинаются пора задуматься об LTDC. Найти тот же ILI9341 выведенными ногами режима RGB как на Дискавери.

 

Спасибо про замечание про volatile. Пройдусь по исходнику, может где-то еще так накосячил.

Про интерфейс: LTDC не хочу из-за количества ножек (и дорожек на плате). Скорее на 8-битный параллельный перейду если уж прижмет, чем полный LTDC использовать.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

35 minutes ago, Cereghma said:

Вы разобрались? Нашли ошибку или причина все-таки в другом?

Да, я как я писал 14 Февраля:

В режиме 4-проводного SPI бит "C/CX" защелкивается в конце передачи байта. То есть нужно сначала полностью передать байт, и только потом менять режим с команды на данные и обратно. 

Получается, нужно просто ждать окончания передачи до переключения режима, точно так же, как это делается до деактивации CS.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

В 27.02.2020 в 16:36, Ruslan1 сказал:

Но осадочек остался: из этого времени стирание (заполнение QVGA дисплея одним цветом) занимает около 40 мс при тактовой SPI 20 MHz, и тут ничего не сделать (240*320*2 = 153600 байт).

Зачем стирать, а затем рисовать поверх? Если можно нарисовать в памяти и вывести сразу весь фрейм? Вроде скорость Вам нужна, а вместо одной операции делаете 2...  :unknw:

Нормально работает SCLK 40МГц и 45МГц с этим МК + ILI.

В 02.03.2020 в 02:33, Ruslan1 сказал:

Думал про полный буфер. Главный плюс: в программировании универсально и красиво с точеки зрения обслуживвания. Но это чисто ублажить внутреннего перфекциониста. А так- RAM жалко, и в плане быстродействия найду не больше 25%.

Вроде писали, что вам достаточно 8 бит на точку (или меньше?). Так и рисуйте в памяти 8-битным цветом, а при выводе - на лету конвертируйте. Будет и скорость и экономия ОЗУ.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Там DMA не особо умеет L8 -> 565 преобразовывать

К сожалению DMA2D тут тоже не поможет...

Изменено пользователем GenaSPB

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

4 hours ago, jcxz said:

Вроде писали, что вам достаточно 8 бит на точку (или меньше?). Так и рисуйте в памяти 8-битным цветом, а при выводе - на лету конвертируйте. Будет и скорость и экономия ОЗУ.

А такое можно? Как нвстроить DMA, чтобы на каждый прочитанный из RAM байт оно посылало два байта в периферию (SPI)? Я согласен если байт будет просто повторяться, но идеально, конечно, если бы 16-битный код из таблицы брало.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

10 часов назад, Ruslan1 сказал:

А такое можно? Как нвстроить DMA, чтобы на каждый прочитанный из RAM байт оно посылало два байта в периферию (SPI)?

При чём тут DMA?

Разбиваете весь видеобуфер на N частей по M пикселей каждая. Конвертируете (процессором конечно) пиксели из первой части через таблицу преобразования цветов в промежуточный буфер отправки. Запускаете отправку из этого буфера в SPI (посредством DMA). Пока идёт передача пикселей первой части, параллельно конвертируете вторую часть во 2-й промежуточный буфер, в конце конвертирования - ожидание завершения DMA-передачи 1-й части и запуск 2-й части (естественно - на семафоре ОС). И снова - конвертируете следующую часть и так далее. В результате - конвертирование займёт времени намного меньше чем собственно передача по SPI (если конечно писать с умом).

 

PS: Ещё больше эффект от такого метода будет если цветов только 16.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

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

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...