STM32 ILI9341 SPI+DMA GRAM R/W
-
fagci
- Родился
- Сообщения: 12
- Зарегистрирован: Пн фев 29, 2016 22:04:54
- Откуда: Новосибирск
- Контактная информация:
STM32 ILI9341 SPI+DMA GRAM R/W
Здравствуйте! =)
Пишу библиотеку под дисплей, встала задача производить чтение из графического буфера для последующей обработки.
Запись производится хорошо, чтение работает, но только один раз.
После чтения не хочет работать запись (команды с данными шлются, дисплей не отображает).
Отдебажил по даташиту https://www.adafruit.com/datasheets/ILI9341.pdf - вроде всё ок, результат дебага тут:
http://pastebin.com/tGue9hkk
Сами исходники можно посмотреть тут:
https://github.com/fagcinsk/stm-ILI9341 ... LI9341_lib
graph.c - LCD_readPixels - метод чтения пикселей с экрана;
dma.c - методы для чтения из памяти.
Есть подозрения, что работа с DMA организована неправильно.
Запись заработала после реинициализации CS пина, но после этого чтение не работает, да и это грязный хак.
К сожалению, анализатра логики, осциллографа нет, только дебаг по USART...
Пишу библиотеку под дисплей, встала задача производить чтение из графического буфера для последующей обработки.
Запись производится хорошо, чтение работает, но только один раз.
После чтения не хочет работать запись (команды с данными шлются, дисплей не отображает).
Отдебажил по даташиту https://www.adafruit.com/datasheets/ILI9341.pdf - вроде всё ок, результат дебага тут:
http://pastebin.com/tGue9hkk
Сами исходники можно посмотреть тут:
https://github.com/fagcinsk/stm-ILI9341 ... LI9341_lib
graph.c - LCD_readPixels - метод чтения пикселей с экрана;
dma.c - методы для чтения из памяти.
Есть подозрения, что работа с DMA организована неправильно.
Запись заработала после реинициализации CS пина, но после этого чтение не работает, да и это грязный хак.
К сожалению, анализатра логики, осциллографа нет, только дебаг по USART...
Помучались, отладили, работает. Переписываем!
- Реклама
- Oxford
- Опытный кот
- Сообщения: 819
- Зарегистрирован: Вт окт 23, 2012 13:17:25
- Откуда: Прокопьевск
- Контактная информация:
Re: STM32 ILI9341 SPI+DMA GRAM R/W
CS дергать не нужно. При отправке команды выставляется DC, и при отправке данных наоборот. Этого хватает.
Еще у вас слишком запутана работа DMA, размазана по коду слишком тяжело отслеживать настройки периферии.
Отправку данных и команд с помощью DMA для служебной настройки пользы дают ноль, быстрее через SPI сливать.
DMA имеет резон на потоках. Лучше всего это иметь фреймбуфер в памяти ОЗУ, строить всю графику и сливать одним разом.
В общем случае чтение вообще не требуется.
Драйвер никуда не годиться, переписывать однозначно.
Посмотрите сравните работу заливки области, как это сделано у меня одной функцией.
Шрифт я у себя тоже ускорил, шрифт рисуется в буфере, а потом буфер сливается в нужный квадрат.
Шрифты у меня пропорциональные. Для генерации виндовых шрифтов написал утилиту для генерации подключаемого файла шрифта.
Так же можно и строки буферизировать, это дает хороший выигрыш в скорости.
Еще у вас слишком запутана работа DMA, размазана по коду слишком тяжело отслеживать настройки периферии.
Отправку данных и команд с помощью DMA для служебной настройки пользы дают ноль, быстрее через SPI сливать.
DMA имеет резон на потоках. Лучше всего это иметь фреймбуфер в памяти ОЗУ, строить всю графику и сливать одним разом.
В общем случае чтение вообще не требуется.
Драйвер никуда не годиться, переписывать однозначно.
Посмотрите сравните работу заливки области, как это сделано у меня одной функцией.
Шрифт я у себя тоже ускорил, шрифт рисуется в буфере, а потом буфер сливается в нужный квадрат.
Шрифты у меня пропорциональные. Для генерации виндовых шрифтов написал утилиту для генерации подключаемого файла шрифта.
Так же можно и строки буферизировать, это дает хороший выигрыш в скорости.
Код: Выделить всё
void GUI_FILL_RECT(uint16_t X1, uint16_t X2, uint16_t Y1, uint16_t Y2, uint16_t COLOR)
{
uint32_t COUNT_PIXEL = 0;
DMA_InitTypeDef DMA_INI;
DMA_DeInit(DMA1_Channel3);
DMA_INI.DMA_PeripheralBaseAddr = (uint32_t)&(SPI1->DR); //Адрес регистра записи для периферии SPI1
DMA_INI.DMA_MemoryBaseAddr = (uint32_t)&COLOR; //Указатель на буфер с цветом
DMA_INI.DMA_DIR = DMA_DIR_PeripheralDST; //Направление: Периферия принимает.
COUNT_PIXEL = (X2 - X1 + 1) * (Y2 - Y1 + 1);
if (COUNT_PIXEL > 65535)
DMA_INI.DMA_BufferSize = 65535; //Количество байт для передачи
else
DMA_INI.DMA_BufferSize = COUNT_PIXEL; //Количество байт для передачи
DMA_INI.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //Автоинкремент периферии выключен, у нас фиксированный адрес
DMA_INI.DMA_MemoryInc = DMA_MemoryInc_Disable; //Аналогично предыдущему.
DMA_INI.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; //Ширина SPI 16 бит
DMA_INI.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; //Ширина буфера 16 бит
DMA_INI.DMA_Mode = DMA_Mode_Normal; //Нормальный режим DMA
DMA_INI.DMA_Priority = DMA_Priority_VeryHigh; //Приоритет
DMA_INI.DMA_M2M = DMA_M2M_Disable; //Память-память выключено.
DMA_Init(DMA1_Channel3, &DMA_INI);
TFT_AREA(X1, X2, Y1, Y2); //Установка области заливки
TFT_DC_HIGH; //Погнали данные
SPI_I2S_DMACmd(SPI1, SPI_I2S_DMAReq_Tx, ENABLE); //Разрешаем запросы DMA от SPI1
SPI_DataSizeConfig(SPI1, SPI_DataSize_16b); //Переводим SPI в 16 бит
DMA_Cmd(DMA1_Channel3, ENABLE); // СТАРТ ЗАЛИВКИ
//С использованием программного опроса флага
while(!DMA_GetFlagStatus(DMA1_FLAG_TC3)); //Первая половина экрана окрашена
DMA1->IFCR = DMA1_FLAG_TC3;
if (COUNT_PIXEL > 65535)
{
DMA_Cmd(DMA1_Channel3, DISABLE);
DMA1_Channel3->CNDTR = COUNT_PIXEL - 65535;
DMA_Cmd(DMA1_Channel3, ENABLE);
while(!DMA_GetFlagStatus(DMA1_FLAG_TC3)); //Остальная часть экрана окрашена
DMA1->IFCR = DMA1_FLAG_TC3;
};
DMA_Cmd(DMA1_Channel3, DISABLE); //Выключаем все.
SPI_I2S_DMACmd(SPI1, SPI_I2S_DMAReq_Tx, DISABLE);
SPI_DataSizeConfig(SPI1, SPI_DataSize_8b);
}
#define TFT_WIDTH 239
#define TFT_HEIGHT 319
GUI_FILL_RECT(0, TFT_WIDTH, 0, TFT_HEIGHT, color);
Инженер R@D
Telegram чат: https://t.me/radiowolf или в поиске приложения @radiowolf. Личка:@cncoxford
Telegram чат: https://t.me/radiowolf или в поиске приложения @radiowolf. Личка:@cncoxford
-
fagci
- Родился
- Сообщения: 12
- Зарегистрирован: Пн фев 29, 2016 22:04:54
- Откуда: Новосибирск
- Контактная информация:
Re: STM32 ILI9341 SPI+DMA GRAM R/W
CS нет необходимости дёргать, когда нет другой переферии на SPI. Зачем нужна библиотека, если работать будет только дисплей?
Хотя если работать с прерываниями, например от тача - CS передёргивается на него, пока читаем только.
DMA инициализируется в dma.c, пины для SPI и его параметры устанавливаются в core.c. - тут должно быть всё прозрачно, лучше - только через классы, но c++ = жир, пробовал =)
Да, есть одно потенциальное место, где можно не понять, что происходит с настройками DMA - это процедуры передачи/приёма.
Сначала при инициализации применяется функция определения параметров DMA по умолчанию, затем при передаче на 16бит данных например устанавливается битность, направление работы DMA и остальные параметры, меняющиеся в пределах работы библиотеки.
Сделано это таким образом, чтобы не делать при каждой транзакции повторную инициализацию - лишние такты процессора на дёргание полей структуры, а при DMA_DeInit() - не только это.
Про отправку команд согласен, через DMA делать - нет смысла, но отправка данных начиная с > 1 единицы уже должна давать прирост в скорости (инициализацию тоже ускорит).
Про буферизацию:
хранить весь фрейм не получится, RAMы не хватит.
Да и оно не особо нужно, по кускам отправляется вполне быстро.
Шрифт да, тоже планирую буферизовать построчно, отображать, если получится, максимально большими регионами.
Для чего нужно использованить чтение:
* отрисовка сложных и затратных примитивов - круг. Можно взять регион, на котором нужно будет сделать отрисовку, затем забить в нуужном месте буфер нужными пикселями, а потом пачкой отдать дисплею
* отрисовка PNGшек например с прозрачностью, полупрозрачностью
* отрисовка шрифта поверх сложного фона (без заливки фоном).
Ну и в итоге получаем, что переписывать нужно только отправку команд, а инициализацию режимов DMA отладить.
Ну и да, для отладки попробовать использовать SPI без DMA, чтобы исключить неправильность работы с DMA.
Хотя если работать с прерываниями, например от тача - CS передёргивается на него, пока читаем только.
DMA инициализируется в dma.c, пины для SPI и его параметры устанавливаются в core.c. - тут должно быть всё прозрачно, лучше - только через классы, но c++ = жир, пробовал =)
Да, есть одно потенциальное место, где можно не понять, что происходит с настройками DMA - это процедуры передачи/приёма.
Сначала при инициализации применяется функция определения параметров DMA по умолчанию, затем при передаче на 16бит данных например устанавливается битность, направление работы DMA и остальные параметры, меняющиеся в пределах работы библиотеки.
Сделано это таким образом, чтобы не делать при каждой транзакции повторную инициализацию - лишние такты процессора на дёргание полей структуры, а при DMA_DeInit() - не только это.
Про отправку команд согласен, через DMA делать - нет смысла, но отправка данных начиная с > 1 единицы уже должна давать прирост в скорости (инициализацию тоже ускорит).
Про буферизацию:
хранить весь фрейм не получится, RAMы не хватит.
Да и оно не особо нужно, по кускам отправляется вполне быстро.
Шрифт да, тоже планирую буферизовать построчно, отображать, если получится, максимально большими регионами.
Для чего нужно использованить чтение:
* отрисовка сложных и затратных примитивов - круг. Можно взять регион, на котором нужно будет сделать отрисовку, затем забить в нуужном месте буфер нужными пикселями, а потом пачкой отдать дисплею
* отрисовка PNGшек например с прозрачностью, полупрозрачностью
* отрисовка шрифта поверх сложного фона (без заливки фоном).
Ну и в итоге получаем, что переписывать нужно только отправку команд, а инициализацию режимов DMA отладить.
Ну и да, для отладки попробовать использовать SPI без DMA, чтобы исключить неправильность работы с DMA.
Помучались, отладили, работает. Переписываем!
- Oxford
- Опытный кот
- Сообщения: 819
- Зарегистрирован: Вт окт 23, 2012 13:17:25
- Откуда: Прокопьевск
- Контактная информация:
Re: STM32 ILI9341 SPI+DMA GRAM R/W
Тут дело еще в том что сильно не разбежишся с фантазиями, типо PNG, прозрачность и прочее. Упретесь в быстродействие, ОЗУ, ФЛЕШ микроконтроллера. Это не компьютер.
Ставить STM32F4 с 1мб?
Так там уже дисплеи другие, параллельные и с аппаратным ускорением.
Поэтому на этом дисплее нужен как можно меньше размером драйвер, высоким быстродействием и самым необходимым API.
Самый танец пойдет когда нужно будет связывать с ОС все это в параллельных задачах.
Ставить STM32F4 с 1мб?
Поэтому на этом дисплее нужен как можно меньше размером драйвер, высоким быстродействием и самым необходимым API.
Самый танец пойдет когда нужно будет связывать с ОС все это в параллельных задачах.
Инженер R@D
Telegram чат: https://t.me/radiowolf или в поиске приложения @radiowolf. Личка:@cncoxford
Telegram чат: https://t.me/radiowolf или в поиске приложения @radiowolf. Личка:@cncoxford
-
fagci
- Родился
- Сообщения: 12
- Зарегистрирован: Пн фев 29, 2016 22:04:54
- Откуда: Новосибирск
- Контактная информация:
Re: STM32 ILI9341 SPI+DMA GRAM R/W
Да, оптимизировать неперевыоптимизировать =)
С PNG вроде как проблем не должно быть, если там не рисовать картины, так, иконки..
Формат PNG как раз предполагает построчное чтение. Даже отображение, если например схемы отображать, можно фигачить прям поцветно - быстро, правда не так эффективно =)
ОЗУ мониторить придётся, с инлайнами играться тоже..
Пока с включённой оптимизацией -O3 "ничего не работает" =)
Ещё вопрос: почему может не проходить инициализация дисплея на больших прескалерах?
На прескалере 2 всё норм, на прескалере 16 инициализация не проходит, а если врубить дебаг по USART - заводится
Может флаги обрабатываю не так? Или отправку делать нужно с проверкой флага до неё самой?
С PNG вроде как проблем не должно быть, если там не рисовать картины, так, иконки..
Формат PNG как раз предполагает построчное чтение. Даже отображение, если например схемы отображать, можно фигачить прям поцветно - быстро, правда не так эффективно =)
ОЗУ мониторить придётся, с инлайнами играться тоже..
Пока с включённой оптимизацией -O3 "ничего не работает" =)
Ещё вопрос: почему может не проходить инициализация дисплея на больших прескалерах?
На прескалере 2 всё норм, на прескалере 16 инициализация не проходит, а если врубить дебаг по USART - заводится
Может флаги обрабатываю не так? Или отправку делать нужно с проверкой флага до неё самой?
Помучались, отладили, работает. Переписываем!
- Реклама
- Oxford
- Опытный кот
- Сообщения: 819
- Зарегистрирован: Вт окт 23, 2012 13:17:25
- Откуда: Прокопьевск
- Контактная информация:
Re: STM32 ILI9341 SPI+DMA GRAM R/W
Т.е. инит не проходит на прексалере 16? На всех не работает? Только прескалер 2 работает?
Не правильный обмен с дисплеем.
Не правильный обмен с дисплеем.
Инженер R@D
Telegram чат: https://t.me/radiowolf или в поиске приложения @radiowolf. Личка:@cncoxford
Telegram чат: https://t.me/radiowolf или в поиске приложения @radiowolf. Личка:@cncoxford
-
fagci
- Родился
- Сообщения: 12
- Зарегистрирован: Пн фев 29, 2016 22:04:54
- Откуда: Новосибирск
- Контактная информация:
Re: STM32 ILI9341 SPI+DMA GRAM R/W
- Прескалер 2: всё отлично
- Прескалер 4: заливка более медленная
- Прескалер 8 : заливка ещё медленнее, иногда инициализация не проходит
- Прескалер 16 и дальше: инициализация не проходит.
Помучались, отладили, работает. Переписываем!
- Oxford
- Опытный кот
- Сообщения: 819
- Зарегистрирован: Вт окт 23, 2012 13:17:25
- Откуда: Прокопьевск
- Контактная информация:
Re: STM32 ILI9341 SPI+DMA GRAM R/W
У меня такая же ботва с дисплеем, повышаю прескалер гонит.
2 и 4 работает, 8 инит проходит, но DMA пургу рисует, 16 ничего не работает.
Оформил тест для STM32F103
2 и 4 работает, 8 инит проходит, но DMA пургу рисует, 16 ничего не работает.
Оформил тест для STM32F103
Инженер R@D
Telegram чат: https://t.me/radiowolf или в поиске приложения @radiowolf. Личка:@cncoxford
Telegram чат: https://t.me/radiowolf или в поиске приложения @radiowolf. Личка:@cncoxford
-
fagci
- Родился
- Сообщения: 12
- Зарегистрирован: Пн фев 29, 2016 22:04:54
- Откуда: Новосибирск
- Контактная информация:
Re: STM32 ILI9341 SPI+DMA GRAM R/W
2: всё ок, жёлтый фон, абвгд...
4: жёлтый фон, затем перекрывается белым
8: после 65535 где-то мусор идёт
16: инициализация не проходит..
Всё так же=)
4: жёлтый фон, затем перекрывается белым
8: после 65535 где-то мусор идёт
16: инициализация не проходит..
Всё так же=)
Помучались, отладили, работает. Переписываем!
- Oxford
- Опытный кот
- Сообщения: 819
- Зарегистрирован: Вт окт 23, 2012 13:17:25
- Откуда: Прокопьевск
- Контактная информация:
Re: STM32 ILI9341 SPI+DMA GRAM R/W
И почему так есть идеи?
Инженер R@D
Telegram чат: https://t.me/radiowolf или в поиске приложения @radiowolf. Личка:@cncoxford
Telegram чат: https://t.me/radiowolf или в поиске приложения @radiowolf. Личка:@cncoxford
-
fagci
- Родился
- Сообщения: 12
- Зарегистрирован: Пн фев 29, 2016 22:04:54
- Откуда: Новосибирск
- Контактная информация:
Re: STM32 ILI9341 SPI+DMA GRAM R/W
Думается, что надо ждать отправки/приёма по-другому...
Сейчас переделываю на чисто SPI, посмотрим, что из этого выйдет
Вот инфа по spi с прерываниями
http://we.easyelectronics.ru/STM32/hak- ... aster.html
Сейчас переделываю на чисто SPI, посмотрим, что из этого выйдет
Вот инфа по spi с прерываниями
http://we.easyelectronics.ru/STM32/hak- ... aster.html
Помучались, отладили, работает. Переписываем!
- Oxford
- Опытный кот
- Сообщения: 819
- Зарегистрирован: Вт окт 23, 2012 13:17:25
- Откуда: Прокопьевск
- Контактная информация:
Re: STM32 ILI9341 SPI+DMA GRAM R/W
После дебага выяснилась не правильная работа SPI.
Правильная работа выглядит так:
Все проблемы ушли, работает стабильно на всех прескалерах.
Правильная работа выглядит так:
Код: Выделить всё
uint16_t TFT_SPI_SEND(uint16_t Data)
{
SPI_I2S_SendData(SPI1, data);
while(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET);
while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_BSY) != RESET);
if (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == SET)
{ return SPI_I2S_ReceiveData(SPI1); } else return 0;
}
Последний раз редактировалось Oxford Чт мар 03, 2016 18:41:45, всего редактировалось 3 раза.
Инженер R@D
Telegram чат: https://t.me/radiowolf или в поиске приложения @radiowolf. Личка:@cncoxford
Telegram чат: https://t.me/radiowolf или в поиске приложения @radiowolf. Личка:@cncoxford
-
fagci
- Родился
- Сообщения: 12
- Зарегистрирован: Пн фев 29, 2016 22:04:54
- Откуда: Новосибирск
- Контактная информация:
Re: STM32 ILI9341 SPI+DMA GRAM R/W
Только конструкция с if не будет полезна -> что-то здесь не так=)
Помучались, отладили, работает. Переписываем!
- Oxford
- Опытный кот
- Сообщения: 819
- Зарегистрирован: Вт окт 23, 2012 13:17:25
- Откуда: Прокопьевск
- Контактная информация:
Re: STM32 ILI9341 SPI+DMA GRAM R/W
Исправил, ";" забыл убрать.fagci писал(а):Только конструкция с if не будет полезна -> что-то здесь не так=)
Инженер R@D
Telegram чат: https://t.me/radiowolf или в поиске приложения @radiowolf. Личка:@cncoxford
Telegram чат: https://t.me/radiowolf или в поиске приложения @radiowolf. Личка:@cncoxford
-
fagci
- Родился
- Сообщения: 12
- Зарегистрирован: Пн фев 29, 2016 22:04:54
- Откуда: Новосибирск
- Контактная информация:
Re: STM32 ILI9341 SPI+DMA GRAM R/W
Hardware NSS некорректно работает с чтением. Нужно использовать software.
Для DMA вместо ожидания сброса переменной из прерывания нужно до сброса CS ждать, пока SPI воркает =)
Тогда будет работать на всех прескалерах.
Для DMA вместо ожидания сброса переменной из прерывания нужно до сброса CS ждать, пока SPI воркает =)
Код: Выделить всё
#define dmaWait() while(SPI_I2S_GetFlagStatus(SPI_MASTER,SPI_I2S_FLAG_BSY) == SET);Помучались, отладили, работает. Переписываем!
-
fagci
- Родился
- Сообщения: 12
- Зарегистрирован: Пн фев 29, 2016 22:04:54
- Откуда: Новосибирск
- Контактная информация:
Re: STM32 ILI9341 SPI+DMA GRAM R/W
Понекропостим =)
Долго возился с подключением DMA на STM32f103, в итоге удалось завести следующим образом:
https://mikhail-yudin.ru/hardware/stm32 ... -with-dma/
Долго возился с подключением DMA на STM32f103, в итоге удалось завести следующим образом:
https://mikhail-yudin.ru/hardware/stm32 ... -with-dma/
Помучались, отладили, работает. Переписываем!
- Oxford
- Опытный кот
- Сообщения: 819
- Зарегистрирован: Вт окт 23, 2012 13:17:25
- Откуда: Прокопьевск
- Контактная информация:
Re: STM32 ILI9341 SPI+DMA GRAM R/W
Норм либа, более менее нормально все написано.
Инженер R@D
Telegram чат: https://t.me/radiowolf или в поиске приложения @radiowolf. Личка:@cncoxford
Telegram чат: https://t.me/radiowolf или в поиске приложения @radiowolf. Личка:@cncoxford
-
fagci
- Родился
- Сообщения: 12
- Зарегистрирован: Пн фев 29, 2016 22:04:54
- Откуда: Новосибирск
- Контактная информация:
Re: STM32 ILI9341 SPI+DMA GRAM R/W
Помучались, отладили, работает. Переписываем!


