Например TDA7294

Форум РадиоКот • Просмотр темы - ili9341 и STM32F4Discovery
Форум РадиоКот
Здесь можно немножко помяукать :)





Текущее время: Вт апр 16, 2024 15:50:25

Часовой пояс: UTC + 3 часа


ПРЯМО СЕЙЧАС:



Начать новую тему Ответить на тему  [ Сообщений: 7 ] 
Автор Сообщение
Не в сети
 Заголовок сообщения: ili9341 и STM32F4Discovery
СообщениеДобавлено: Ср ноя 22, 2017 12:15:25 
Родился

Зарегистрирован: Ср ноя 22, 2017 11:34:47
Сообщений: 6
Рейтинг сообщения: 0
Добрый день. Пытаюсь подключить экран с контроллером 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?


Вложения:
Комментарий к файлу: Проект в Keil5
TFT_22_ili9341.rar [736.14 KiB]
Скачиваний: 269
Вернуться наверх
 
Не в сети
 Заголовок сообщения: Re: ili9341 и STM32F4Discovery
СообщениеДобавлено: Ср ноя 22, 2017 14:40:49 
Сверлит текстолит когтями

Карма: -10
Рейтинг сообщений: 93
Зарегистрирован: Вт авг 15, 2017 10:51:13
Сообщений: 1150
Рейтинг сообщения: 0
Добрый день. Пытаюсь подключить экран с контроллером ili9341 к stm32f4-discovery.
Для проверки работы, пытаюсь прочитать из экрана его ID. Согласно datasheet, надо отправить команду 0x4, и 4 раза прочитать из экрана. В последних трех ответах будет ID (стр. 91 даташита). Команду шлю и читаю ответ в бесконечном цикле.

Те LCD на ILI934x, что у меня есть, ни один не отвечает на команды чтения. И сколько я читал в форумах - и у других людей аналогично. Так что - забейте на чтение.
Инициализируйте и не будет белого экрана. Примеров инициализации в инете можно найти массу.
И на моей последней плате, на которой использую ILI934x, он подключен по совмещённому MOSI/MISO. И режим SPI тогда нужно программировать соответствующий. Хотя и на обычный SPI можно подключить.
В качестве примера подключения поищите даташит на отладочную плату STM32F429-DISCOVERY - на ней как раз стоит этот самый ILI9341 на SPI.

Можно перенести в ARM?

А какое отношение чип контроллера LCD имеет к ARM? Если его подключить к другому МК, его работа разве как-то изменится?


Вернуться наверх
 
Не в сети
 Заголовок сообщения: Re: ili9341 и STM32F4Discovery
СообщениеДобавлено: Ср ноя 22, 2017 20:39:28 
Грызет канифоль
Аватар пользователя

Карма: 6
Рейтинг сообщений: 202
Зарегистрирован: Пт ноя 13, 2009 10:39:32
Сообщений: 272
Откуда: Москва
Рейтинг сообщения: 3
После инициализации надо что то записать в экран - иначе ничего не происходит. Например очистить.
У меня на 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. Я запускал с дискавери, но код не сохранился.


Вернуться наверх
 
PCBWay - всего $5 за 10 печатных плат, первый заказ для новых клиентов БЕСПЛАТЕН

Сборка печатных плат от $30 + БЕСПЛАТНАЯ доставка по всему миру + трафарет

Онлайн просмотровщик Gerber-файлов от PCBWay + Услуги 3D печати
Не в сети
 Заголовок сообщения: Re: ili9341 и STM32F4Discovery
СообщениеДобавлено: Пт ноя 24, 2017 13:41:47 
Родился

Зарегистрирован: Ср ноя 22, 2017 11:34:47
Сообщений: 6
Рейтинг сообщения: 0
Вроде удалось победить дисплей, вывод работает. Подключил 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, а на регистрах я не видел.


Вложения:
Комментарий к файлу: Проект в Keil5
TFT_22_ili9341.rar [990.6 KiB]
Скачиваний: 309
Вернуться наверх
 
Организация питания на основе надежных литиевых аккумуляторов EVE и микросхем азиатского производства

Качественное и безопасное устройство, работающее от аккумулятора, должно учитывать его физические и химические свойства, профили заряда и разряда, их изменение во времени и под влиянием различных условий, таких как температура и ток нагрузки. Мы расскажем о литий-ионных аккумуляторных батареях EVE и нескольких решениях от различных китайских компаний, рекомендуемых для разработок приложений с использованием этих АКБ. Представленные в статье китайские аналоги помогут заменить продукцию западных брендов с оптимизацией цены без потери качества.

Подробнее>>
Не в сети
 Заголовок сообщения: Re: ili9341 и STM32F4Discovery
СообщениеДобавлено: Пт ноя 24, 2017 23:31:06 
Грызет канифоль
Аватар пользователя

Карма: 6
Рейтинг сообщений: 202
Зарегистрирован: Пт ноя 13, 2009 10:39:32
Сообщений: 272
Откуда: Москва
Рейтинг сообщения: 0
По DMA не проверял, но если просто цветом заливать и больше ничего не делать то получается примерно 29 fps (заливок экрана в секунду).
Скорость SPI 36 мГц.
36 000 000 / 320 / 240 / 16 ~ 29.3 Герц


Вернуться наверх
 
Новый аккумулятор EVE серии PLM для GSM-трекеров, работающих в жёстких условиях (до -40°С)

Компания EVE выпустила новый аккумулятор серии PLM, сочетающий в себе высокую безопасность, длительный срок службы, широкий температурный диапазон и высокую токоотдачу даже при отрицательной температуре. Эти аккумуляторы поддерживают заряд при температуре от -40/-20°С (сниженным значением тока), безопасны (не воспламеняются и не взрываются) при механическом повреждении (протыкание и сдавливание), устойчивы к вибрации. Они могут применяться как для автотранспорта (трекеры, маячки, сигнализация), так и для промышленных устройств мониторинга, IoT-устройств.

Подробнее>>
Не в сети
 Заголовок сообщения: Re: ili9341 и STM32F4Discovery
СообщениеДобавлено: Сб ноя 25, 2017 00:17:24 
Сверлит текстолит когтями

Карма: -10
Рейтинг сообщений: 93
Зарегистрирован: Вт авг 15, 2017 10:51:13
Сообщений: 1150
Рейтинг сообщения: 0
Вроде удалось победить дисплей, вывод работает. Подключил DMA, получилось примерно так: заливка экрана с DMA - 6 раз в секунду

Очень медленно. У меня без проблем работает на SCLK=45МГц.

Добавлено after 5 minutes 7 seconds:
Скорость SPI 36 мГц

У Вас видимо CLK периферийной шины ==72МГц, как и частота ядра? И видимо STM32? И видимо SPI в режиме 16бит/слово?
И FIFO на SPI у STM32 нету.
При 2 тактах шины на 1 бит SPI на диаграмме SCLK нет пауз?


Вернуться наверх
 
Не в сети
 Заголовок сообщения: Re: ili9341 и STM32F4Discovery
СообщениеДобавлено: Вт ноя 28, 2017 15:46:44 
Родился

Зарегистрирован: Ср ноя 22, 2017 11:34:47
Сообщений: 6
Рейтинг сообщения: 0
Да, действительно, работало медленно, потому что тактирование было оставлено по умолчанию.
Вышеприведенный пример удалось "разогнать" до 34 в режиме DMA и 32 в SPI.
Так что вроде экран не такой и тормоз :)


Вернуться наверх
 
Показать сообщения за:  Сортировать по:  Вернуться наверх
Начать новую тему Ответить на тему  [ Сообщений: 7 ] 

Часовой пояс: UTC + 3 часа


Кто сейчас на форуме

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 17


Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете добавлять вложения

Найти:
Перейти:  


Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group
Русская поддержка phpBB
Extended by Karma MOD © 2007—2012 m157y
Extended by Topic Tags MOD © 2012 m157y