Форум РадиоКот https://radiokot.ru/forum/ |
|
ili9341 и STM32F4Discovery https://radiokot.ru/forum/viewtopic.php?f=59&t=150168 |
Страница 1 из 1 |
Автор: | Sergey_78r [ Ср ноя 22, 2017 12:15:25 ] | ||
Заголовок сообщения: | ili9341 и STM32F4Discovery | ||
Добрый день. Пытаюсь подключить экран с контроллером ili9341 к stm32f4-discovery. У модуля с экраном 9 ног для подключения по SPI (VCC, GND, CS, RESET, D/C, MOSI, SCK, LED, MISO) К STM подключил так: Код: TFT STM32 ---------- VCC 5v GND GND CS PB11 RESET PB12 DC PB10 MOSI PA7 SCK PA5 LED 3v MISO PA6 При включении подсветка включается, экран равномерно белый. Для проверки работы, пытаюсь прочитать из экрана его ID. Согласно datasheet, надо отправить команду 0x4, и 4 раза прочитать из экрана. В последних трех ответах будет ID (стр. 91 даташита). Команду шлю и читаю ответ в бесконечном цикле. Для отладки, полученные значения шлю в UART. В ответ приходит 0, 0x3F и дальше все ответы 0xFF. Для проверки работы SPI я слал с SPI1 на плате на SPI2 и обратно. Все работает, отправляется и принимает. Буду очень благодарен, если подскажете, что делаю не правильно. Во вложении проект из Keil5. Весь код специально написал прямо в main(), чтоб не искать по функциям. Убрал только работу с uart. Пробовал устанавливать LSBFIRST (порядок бит) и менять скорость baute rate, но результат тот же. Код: #include "main.h" /* Подключение экрана: TFT STM32 ---------- VCC 5v GND GND CS PB11 RESET PB12 DC PB10 MOSI PA7 SCK PA5 LED 3v MISO PA6 */ int main(void) { //Инициализация UART2, используется для вывода отладки uart_init(); //Включение тактирования порта B (для DC, RST, CS) RCC->AHB1ENR |= RCC_AHB1ENR_GPIOBEN; //Режим output для пинов 10, 11, 12 GPIOB->MODER |= GPIO_MODER_MODE10_0|GPIO_MODER_MODE11_0|GPIO_MODER_MODE12_0; //Скорость порта Very High speed для 10, 11, 12 GPIOB->OSPEEDR |= GPIO_OSPEEDR_OSPEED10_0|GPIO_OSPEEDR_OSPEED10_1; GPIOB->OSPEEDR |= GPIO_OSPEEDR_OSPEED11_0|GPIO_OSPEEDR_OSPEED11_1; GPIOB->OSPEEDR |= GPIO_OSPEEDR_OSPEED12_0|GPIO_OSPEEDR_OSPEED12_1; //Установка подтяжки: //Обнуление на всякий случай GPIOB->PUPDR &= ~(GPIO_PUPDR_PUPD10_0|GPIO_PUPDR_PUPD10_1); GPIOB->PUPDR &= ~(GPIO_PUPDR_PUPD11_0|GPIO_PUPDR_PUPD11_1); GPIOB->PUPDR &= ~(GPIO_PUPDR_PUPD12_0|GPIO_PUPDR_PUPD12_1); //Установка подтяжки к GND (Pull-down) GPIOB->PUPDR |= GPIO_PUPDR_PUPD10_1|GPIO_PUPDR_PUPD11_1|GPIO_PUPDR_PUPD12_1; //Перед инициализацией SPI, устанавливаю CS в HIGH, т.е. отключаю выбор (активное состояние LOW) GPIOB->BSRR |= GPIO_BSRR_BS11; //Инициализация SPI //Включить тактирование SPI1 RCC->APB2ENR |= RCC_APB2ENR_SPI1EN; //Включить тактирование порта А RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN; //Включение AF5 на пинах 5,6,7 GPIOA->AFR[0] |= GPIO_AFRL_AFSEL5_0|GPIO_AFRL_AFSEL5_2; GPIOA->AFR[0] |= GPIO_AFRL_AFSEL6_0|GPIO_AFRL_AFSEL6_2; GPIOA->AFR[0] |= GPIO_AFRL_AFSEL7_0|GPIO_AFRL_AFSEL7_2; //Режим альтернативной функция для PA5,PA6,PA7 GPIOA->MODER |= GPIO_MODER_MODE5_1|GPIO_MODER_MODE6_1|GPIO_MODER_MODE7_1; //Скорость High speed GPIOA->OSPEEDR |= GPIO_OSPEEDR_OSPEED5_0|GPIO_OSPEEDR_OSPEED5_1; GPIOA->OSPEEDR |= GPIO_OSPEEDR_OSPEED6_0|GPIO_OSPEEDR_OSPEED6_1; GPIOA->OSPEEDR |= GPIO_OSPEEDR_OSPEED7_0|GPIO_OSPEEDR_OSPEED7_1; //Режим push-pull GPIOA->OTYPER &= ~GPIO_OTYPER_OT5; GPIOA->OTYPER &= ~GPIO_OTYPER_OT6; GPIOA->OTYPER &= ~GPIO_OTYPER_OT7; //Отключение подтяжки на PA5, PA6, PA7 GPIOA->PUPDR &= ~(GPIO_PUPDR_PUPD5_0|GPIO_PUPDR_PUPD5_1); GPIOA->PUPDR &= ~(GPIO_PUPDR_PUPD6_0|GPIO_PUPDR_PUPD6_1); GPIOA->PUPDR &= ~(GPIO_PUPDR_PUPD7_0|GPIO_PUPDR_PUPD7_1); //Режим работы по двум линиям SPI1->CR1 &= ~SPI_CR1_BIDIMODE; //Отключение CRC SPI1->CR1 &= ~SPI_CR1_CRCEN; //8-bit передача SPI1->CR1 &= ~SPI_CR1_DFF; //Програмное управление SS SPI1->CR1 |= SPI_CR1_SSI|SPI_CR1_SSM; //Режим работы SPI 0 SPI1->CR1 &= ~SPI_CR1_CPHA; SPI1->CR1 &= ~SPI_CR1_CPOL; //Выбор скорости /8 SPI1->CR1 &= ~SPI_CR1_BR; SPI1->CR1 |= (SPI_CR1_BR_1); //Установка флага Master SPI1->CR1 |= SPI_CR1_MSTR; //Выбор формата фрейма, какой бит передавать первым //SPI1->CR1 |= SPI_CR1_LSBFIRST; //Включение SPI1 SPI1->CR1 |= SPI_CR1_SPE; //Установка CS в LOW, для выбора slave GPIOB->BSRR |= GPIO_BSRR_BR11; //Судя по описанию ili9341, RST активен кошда LOW. //Т.е. для работы, нужно установить в HIGH GPIOB->BSRR |= GPIO_BSRR_BS12; //Экрану буду слать только команду на чтение, поэтому DC в LOW GPIOB->BSRR |= GPIO_BSRR_BR10; //Перед началом работы надо отправить команду SOFWARE RESET (0x1) //Пока бит TXE не будет установлен, просто ждать while(!(SPI1->SR & SPI_SR_TXE)){}; //Команда для чтения из экрана SPI1->DR=0x1; //Дисплею надо 5ms, чтобы выполнить reset, тупая пауза с запасом for(int i=0; i < 10000000; i++); while(1) { uint8_t d,f,g=0; //переменные, чтобы складывать ответы экрана //Пока бит TXE не будет установлен, просто ждать while(!(SPI1->SR & SPI_SR_TXE)){}; //Команда для чтения из экрана 0x4 //В ответ вернет 4 байта. В первом мусор, остальные 3 с ID SPI1->DR=0x4; //Сразу после отправки команды, в ответ сначала придет мусор d=SPI1->DR; //Чтобы получить ответ на команду, надо продолжить тактировать //передавая 0 (NOP) while(!(SPI1->SR & SPI_SR_TXE)){}; SPI1->DR=0; // 1 из 3 байт ответа d=SPI1->DR; //Чтобы получить ответ на команду, надо продолжить тактировать //передавая 0 while(!(SPI1->SR & SPI_SR_TXE)){}; SPI1->DR=0; // 2 из 3 байт ответа f=SPI1->DR; //Чтобы получить ответ на команду, надо продолжить тактировать //передавая 0 while(!(SPI1->SR & SPI_SR_TXE)){}; SPI1->DR=0; // 3 из 3 байт ответа g=SPI1->DR; sprintf(str_buffer, "d: %02X f: %02X g: %02X \r\n",d,f,g); uart_send_string(str_buffer); }; }; Добавлено after 19 minutes 33 seconds: Извиняюсь, случайно создал тему не в том разделе. Можно перенести в ARM?
|
Автор: | jcxz [ Ср ноя 22, 2017 14:40:49 ] |
Заголовок сообщения: | Re: ili9341 и STM32F4Discovery |
Добрый день. Пытаюсь подключить экран с контроллером ili9341 к stm32f4-discovery. Для проверки работы, пытаюсь прочитать из экрана его ID. Согласно datasheet, надо отправить команду 0x4, и 4 раза прочитать из экрана. В последних трех ответах будет ID (стр. 91 даташита). Команду шлю и читаю ответ в бесконечном цикле. Те LCD на ILI934x, что у меня есть, ни один не отвечает на команды чтения. И сколько я читал в форумах - и у других людей аналогично. Так что - забейте на чтение. Инициализируйте и не будет белого экрана. Примеров инициализации в инете можно найти массу. И на моей последней плате, на которой использую ILI934x, он подключен по совмещённому MOSI/MISO. И режим SPI тогда нужно программировать соответствующий. Хотя и на обычный SPI можно подключить. В качестве примера подключения поищите даташит на отладочную плату STM32F429-DISCOVERY - на ней как раз стоит этот самый ILI9341 на SPI. Можно перенести в ARM? А какое отношение чип контроллера LCD имеет к ARM? Если его подключить к другому МК, его работа разве как-то изменится? |
Автор: | Fusion [ Ср ноя 22, 2017 20:39:28 ] |
Заголовок сообщения: | Re: ili9341 и STM32F4Discovery |
После инициализации надо что то записать в экран - иначе ничего не происходит. Например очистить. У меня на ili9341 отлично читает из дисплея. Вот код для F103: СпойлерКод: #define Orient_Book 0xE8 #define Orient_Land 0x88 #define ILI9341_RESET 0x01 #define ILI9341_SLEEP_OUT 0x11 #define ILI9341_GAMMA 0x26 #define ILI9341_DISPLAY_OFF 0x28 #define ILI9341_DISPLAY_ON 0x29 #define ILI9341_COLUMN_ADDR 0x2A #define ILI9341_PAGE_ADDR 0x2B #define ILI9341_GRAM 0x2C #define ILI9341_MAC 0x36 #define ILI9341_PIXEL_FORMAT 0x3A #define ILI9341_WDB 0x51 #define ILI9341_WCD 0x53 #define ILI9341_RGB_INTERFACE 0xB0 #define ILI9341_FRC 0xB1 #define ILI9341_BPC 0xB5 #define ILI9341_DFC 0xB6 #define ILI9341_POWER1 0xC0 #define ILI9341_POWER2 0xC1 #define ILI9341_VCOM1 0xC5 #define ILI9341_VCOM2 0xC7 #define ILI9341_POWERA 0xCB #define ILI9341_POWERB 0xCF #define ILI9341_PGAMMA 0xE0 #define ILI9341_NGAMMA 0xE1 #define ILI9341_DTCA 0xE8 #define ILI9341_DTCB 0xEA #define ILI9341_POWER_SEQ 0xED #define ILI9341_3GAMMA_EN 0xF2 #define ILI9341_INTERFACE 0xF6 #define ILI9341_PRC 0xF7 #define WHITE 0xFFFF #define BLACK 0x0000 #define BLUE 0x001F #define BRED 0XF81F #define GRED 0XFFE0 #define GBLUE 0X07FF #define RED 0xF800 #define MAGENTA 0xF81F #define GREEN 0x07E0 #define CYAN 0x7FFF #define YELLOW 0xFFE0 #define BROWN 0XBC40 #define BRRED 0XFC07 #define GRAY 0X8430 #define DGRAY 0X2104 #define DARKBLUE 0X01CF #define LIGHTBLUE 0X7D7C #define GRAYBLUE 0X5458 #define LIGHTGREEN 0X841F #define LGRAY 0XC618 #define LGRAYBLUE 0XA651 #define LBBLUE 0X2B12 void LCDinit(void) { GPIO_ResetBits(GPIOB, LCD_RESET); Delay(10000); GPIO_SetBits(GPIOB, LCD_RESET); SendCMD(ILI9341_RESET); Delay(10000); SendCMD(ILI9341_POWERA); SendDAT(0x39); SendDAT(0x2C); SendDAT(0x00); SendDAT(0x34); SendDAT(0x02); SendCMD(ILI9341_POWERB); SendDAT(0x00); SendDAT(0xC1); SendDAT(0x30); SendCMD(ILI9341_DTCA); SendDAT(0x85); SendDAT(0x00); SendDAT(0x78); SendCMD(ILI9341_DTCB); SendDAT(0x00); SendDAT(0x00); SendCMD(ILI9341_POWER_SEQ); SendDAT(0x64); SendDAT(0x03); SendDAT(0x12); SendDAT(0x81); SendCMD(ILI9341_PRC); SendDAT(0x20); SendCMD(ILI9341_POWER1); SendDAT(0x23); SendCMD(ILI9341_POWER2); SendDAT(0x10); SendCMD(ILI9341_VCOM1); SendDAT(0x3E); SendDAT(0x28); SendCMD(ILI9341_VCOM2); SendDAT(0x86); SendCMD(ILI9341_MAC); SendDAT(Orient_Book); // SendDAT(0x48); SendCMD(ILI9341_PIXEL_FORMAT); SendDAT(0x55); SendCMD(ILI9341_FRC); SendDAT(0x00); SendDAT(0x18); SendCMD(ILI9341_DFC); SendDAT(0x08); SendDAT(0x82); SendDAT(0x27); SendCMD(ILI9341_3GAMMA_EN); SendDAT(0x00); SendCMD(ILI9341_COLUMN_ADDR); SendDAT(0x00); SendDAT(0x00); SendDAT(0x01); // SendDAT(0x00); SendDAT(0x3F); // SendDAT(0xEF); SendCMD(ILI9341_PAGE_ADDR); SendDAT(0x00); SendDAT(0x00); SendDAT(0x00); // SendDAT(0x01); SendDAT(0xEF); // SendDAT(0x3F); SendCMD(ILI9341_GAMMA); SendDAT(0x01); SendCMD(ILI9341_PGAMMA); SendDAT(0x0F); SendDAT(0x31); SendDAT(0x2B); SendDAT(0x0C); SendDAT(0x0E); SendDAT(0x08); SendDAT(0x4E); SendDAT(0xF1); SendDAT(0x37); SendDAT(0x07); SendDAT(0x10); SendDAT(0x03); SendDAT(0x0E); SendDAT(0x09); SendDAT(0x00); SendCMD(ILI9341_NGAMMA); SendDAT(0x00); SendDAT(0x0E); SendDAT(0x14); SendDAT(0x03); SendDAT(0x11); SendDAT(0x07); SendDAT(0x31); SendDAT(0xC1); SendDAT(0x48); SendDAT(0x08); SendDAT(0x0F); SendDAT(0x0C); SendDAT(0x31); SendDAT(0x36); SendDAT(0x0F); SendCMD(ILI9341_SLEEP_OUT); Delay(100000); SendCMD(ILI9341_DISPLAY_ON); } void SendDAT(uint8_t byteToSend) { GPIO_SetBits(GPIOB, LCD_RS); // data while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET) {} SPI_I2S_SendData(SPI1, byteToSend); while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_BSY) == SET) {} } void SendCMD(uint8_t byteToSend) { GPIO_ResetBits(GPIOB, LCD_RS); // comand while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET) {} SPI_I2S_SendData(SPI1, byteToSend); while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_BSY) == SET) {} } void LCDclr(uint16_t X, uint8_t Y, uint16_t L, uint8_t H, uint16_t color) { SendCMD(ILI9341_MAC); SendDAT(Orient_Book); SendCMD(ILI9341_COLUMN_ADDR); SendDAT(X>>8); SendDAT(X); SendDAT((X+L-1)>>8); SendDAT(X+L-1); SendCMD(ILI9341_PAGE_ADDR); SendDAT(0); SendDAT(Y); SendDAT(0); SendDAT(Y+H-1); SendCMD(ILI9341_GRAM); GPIO_SetBits(GPIOB, LCD_RS); // data for (uint32_t i = 0; i < L*H; i++) { while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET) {} SPI_I2S_SendData(SPI1, color>>8); while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET) {} SPI_I2S_SendData(SPI1, color); } } uint8_t ReadSPI(void) { while (!(SPI1->SR & SPI_SR_TXE)) {} *((__IO uint8_t *)&SPI1->DR) = 0x00; while (!(SPI1->SR & SPI_SR_RXNE)) {} return (uint8_t)SPI1->DR; } Для F4 чуть подправить работу с SPI. Я запускал с дискавери, но код не сохранился. |
Автор: | Sergey_78r [ Пт ноя 24, 2017 13:41:47 ] | ||
Заголовок сообщения: | Re: ili9341 и STM32F4Discovery | ||
Вроде удалось победить дисплей, вывод работает. Подключил DMA, получилось примерно так: заливка экрана с DMA - 6 раз в секунду, заливка экрана просто по SPI 3 раза в секунду. Использую SPI1, BR стоит 0, т.е. /2 Делал без использования STL и HAL, вдруг кому будет пример интересен, прикладываю проект в keil5. Ну и немного кода с комментариями, буду благодарен за критику, как можно улучшить и ускорить. Инициализация SPI1 (у SPI1 частота шины больше, чем у SPI2, соответственно будет побыстрее) Код: //Инициализация SPI1 на пинах PA5, PA6, PA7 //Включить тактирование SPI1 RCC->APB2ENR |= RCC_APB2ENR_SPI1EN; //Включить тактирование порта А RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN; //Включение AF5 на пинах 5,6,7 GPIOA->AFR[0] |= GPIO_AFRL_AFSEL5_0|GPIO_AFRL_AFSEL5_2; GPIOA->AFR[0] |= GPIO_AFRL_AFSEL6_0|GPIO_AFRL_AFSEL6_2; GPIOA->AFR[0] |= GPIO_AFRL_AFSEL7_0|GPIO_AFRL_AFSEL7_2; //Режим альтернативной функция для PA5,PA6,PA7 GPIOA->MODER |= GPIO_MODER_MODE5_1|GPIO_MODER_MODE6_1|GPIO_MODER_MODE7_1; //Скорость High speed GPIOA->OSPEEDR |= GPIO_OSPEEDR_OSPEED5_0|GPIO_OSPEEDR_OSPEED5_1; GPIOA->OSPEEDR |= GPIO_OSPEEDR_OSPEED6_0|GPIO_OSPEEDR_OSPEED6_1; GPIOA->OSPEEDR |= GPIO_OSPEEDR_OSPEED7_0|GPIO_OSPEEDR_OSPEED7_1; //Режим push-pull GPIOA->OTYPER &= ~GPIO_OTYPER_OT5; GPIOA->OTYPER &= ~GPIO_OTYPER_OT6; GPIOA->OTYPER &= ~GPIO_OTYPER_OT7; //Отключение подтяжки на PA5, PA6, PA7 GPIOA->PUPDR &= ~(GPIO_PUPDR_PUPD5_0|GPIO_PUPDR_PUPD5_1); GPIOA->PUPDR &= ~(GPIO_PUPDR_PUPD6_0|GPIO_PUPDR_PUPD6_1); GPIOA->PUPDR &= ~(GPIO_PUPDR_PUPD7_0|GPIO_PUPDR_PUPD7_1); //Режим работы по двум линиям SPI1->CR1 &= ~SPI_CR1_BIDIMODE; //Отключение CRC SPI1->CR1 &= ~SPI_CR1_CRCEN; //8-bit передача SPI1->CR1 &= ~SPI_CR1_DFF; //Программное управление SS SPI1->CR1 |= SPI_CR1_SSI|SPI_CR1_SSM; //Режим работы SPI 0 SPI1->CR1 &= ~SPI_CR1_CPHA; SPI1->CR1 &= ~SPI_CR1_CPOL; //Выбор скорости /2 SPI1->CR1 &= ~SPI_CR1_BR; //Установка флага Master SPI1->CR1 |= SPI_CR1_MSTR; //DMA на TX SPI1->CR2 |= SPI_CR2_TXDMAEN; //Выбор формата фрейма, какой бит передавать первым //SPI1->CR1 |= SPI_CR1_LSBFIRST; //Включение SPI1 SPI1->CR1 |= SPI_CR1_SPE; Для управления линией DS функция: Код: void LCD_DC_set(uint8_t data){ while((SPI1->SR & SPI_SR_BSY) == 1){}; //Дождаться окончания передачи, перед изменением режима if(data == 0){ GPIOA->BSRR |= GPIO_BSRR_BR3; }else{ GPIOA->BSRR |= GPIO_BSRR_BS3; }; } Основной момент тут в том, что перед тем как сменить режим работы с Data на Command надо дождаться окончания текущей передачи. Функции отправки данных в SPI: Код: void LCD_SendCommand(uint8_t data) { LCD_DC_set(0); spi1_send(data); } void LCD_SendFastData(uint8_t data) { while((SPI1->SR & SPI_SR_TXE) == 0){}; SPI1->DR = data; } void LCD_SendData(uint8_t data) { LCD_DC_set(1); spi1_send(data); } void spi1_send(uint8_t data){ while((SPI1->SR & SPI_SR_TXE) == 0){}; SPI1->DR = data; }; В spi_send надо дождаться только флага TXE, что означает, что буфер свободен. BSY тут ждать не зачем, этот флаг проверяется только когда DC меняется, чтобы не порушить обмен. Для отправки две функции, LCD_SendData и LCD_SendFastData. Вторая появилась, когда экспериментировал со скоростью заливки всего экрана. Она вызывается 76800 раз, поэтому даже просто убрав лишний вызов LCD_DC_set(1) и перенеся запись в SPI-DR (без вызова spi1_send) удалось ускорить на заметную глазу величину. Соответственно, если перенести запись в SPI-DR прямо в функцию заливки экрана, можно еще чуть ускорить. Заливка экрана с помощью DMA: Код: void LCD_Fill_dma(uint16_t color) { LCD_SetCursorPosition(0, 0, LCD_WIDTH - 1, LCD_HEIGHT - 1); LCD_SendCommand(ILI9341_GRAM); LCD_DC_set(1); //Цвета у экрана 16 бит и передавать их удобнее тоже по 16 бит. //Для этого надо переключить SPI1 в режим 16 бит //Сначала надо выключить передачу. Я не жду тут флага BSY, поскольку перед этим устанавливал DC и там этот //флаг проверяется. SPI1->CR1 &= ~SPI_CR1_SPE; //16бит SPI1->CR1 |= SPI_CR1_DFF; //Включаем SPI SPI1->CR1 |= SPI_CR1_SPE; //NDTR 16 битный регистр и значение 76800 в него не влезет. Поэтому передаем двумя кусками по 38400 DMA2_Stream3 -> NDTR = LCD_PIXEL_COUNT/2; //Количество байт для передачи DMA2_Stream3 -> PAR = (uint32_t)&(SPI1 -> DR); //Адрес переферии DMA2_Stream3 -> M0AR = (uint32_t)&color; //Адрес в памяти DMA2_Stream3 -> CR |= DMA_SxCR_CHSEL_0|DMA_SxCR_CHSEL_1; //Канал 3 DMA2_Stream3 -> CR &= ~DMA_SxCR_MINC; //Инкремент в памяти не нужен, заливка будет одним цветом DMA2_Stream3 -> CR |=DMA_SxCR_DIR_0; //Направление, из памяти в переферию DMA2_Stream3 -> CR |=DMA_SxCR_MSIZE_0; //16 бит DMA2_Stream3 -> CR |=DMA_SxCR_PSIZE_0; //16 бит DMA2_Stream3 -> CR |= DMA_SxCR_EN; //Запустить копирование while((DMA2->LISR & DMA_LISR_TCIF3) == 0) {}; //подождать окончания копирования DMA2->LIFCR |= DMA_LIFCR_CTCIF3; //Сбросить флаг окончания //Копирование 2 половины данных DMA2_Stream3 -> NDTR = LCD_PIXEL_COUNT/2; //Количество байт для передачи DMA2_Stream3 -> CR |= DMA_SxCR_EN; //Запустить копирование while((DMA2->LISR & DMA_LISR_TCIF3) == 0) {}; //Подождать окончания копирования DMA2->LIFCR |= DMA_LIFCR_CTCIF3; //Сбросить флаг //После заливки экрана надо вернуть режим работы SPI в 8 бит //Ждем пока закончится передача while((SPI1->SR & SPI_SR_BSY) == 1){}; //Выключаю SPI, устанавливаю 8 бит, включаю SPI SPI1->CR1 &= ~SPI_CR1_SPE; SPI1->CR1 &= ~SPI_CR1_DFF; SPI1->CR1 |= SPI_CR1_SPE; } Ну и собственно как проверял скорость обновления: Код: cur_time=get_ms(); while(get_ms() - cur_time < 20000){ color=(color == 0x00F8 ? 0xF800 : 0x00F8); LCD_Fill_dma(color); j++; }; cur_time=get_ms(); while(get_ms() - cur_time < 20000){ color=(color == 0x00F8 ? 0xF800 : 0x00F8); LCD_Fill(color); l++; }; j=j/20; l=l/20; get_ms возвращает нарастающее время в ms. Посчитал количество обновлений за 20 секунд с DMA и просто spi_send. С DMA видел другой метод работы - цикличный режим и отслеживание количества запусков по прерыванию. Не думаю, что это сильно скажется на скорости, а кода больше ![]() Код инициализации дисплея я взял из чьего-то проекта (в IAR был). Оттуда же схема работы с экраном, но переделал работу с флагами SPI, поскольку она была реализована не правильно и работало медленно. Вообщем сейчас на глаз работает довольно шустро, хотя заливка экрана глазом видна. Если есть идеи как еще ускорить вывод, или есть явные ошибки в реализации, буду рад услышать. Проект во вложении, надеюсь кому-нибудь будет полезен. В сети много примеров на SPL и HAL, а на регистрах я не видел.
|
Автор: | Fusion [ Пт ноя 24, 2017 23:31:06 ] |
Заголовок сообщения: | Re: ili9341 и STM32F4Discovery |
По DMA не проверял, но если просто цветом заливать и больше ничего не делать то получается примерно 29 fps (заливок экрана в секунду). Скорость SPI 36 мГц. 36 000 000 / 320 / 240 / 16 ~ 29.3 Герц |
Автор: | jcxz [ Сб ноя 25, 2017 00:17:24 ] |
Заголовок сообщения: | Re: ili9341 и STM32F4Discovery |
Вроде удалось победить дисплей, вывод работает. Подключил DMA, получилось примерно так: заливка экрана с DMA - 6 раз в секунду Очень медленно. У меня без проблем работает на SCLK=45МГц. Добавлено after 5 minutes 7 seconds: Скорость SPI 36 мГц У Вас видимо CLK периферийной шины ==72МГц, как и частота ядра? И видимо STM32? И видимо SPI в режиме 16бит/слово? И FIFO на SPI у STM32 нету. При 2 тактах шины на 1 бит SPI на диаграмме SCLK нет пауз? |
Автор: | Sergey_78r [ Вт ноя 28, 2017 15:46:44 ] |
Заголовок сообщения: | Re: ili9341 и STM32F4Discovery |
Да, действительно, работало медленно, потому что тактирование было оставлено по умолчанию. Вышеприведенный пример удалось "разогнать" до 34 в режиме DMA и 32 в SPI. Так что вроде экран не такой и тормоз ![]() |
Страница 1 из 1 | Часовой пояс: UTC + 3 часа |
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group http://www.phpbb.com/ |