То что предлагаете вы - это похоже на эмуляцию протокола.
Вы меня неправильно поняли. Я просто указал какие ноги должны быть у дисплея для подключения по FSMC.
по FSMC куб предусматривает несколько предопределенных вариантов подключения
И Вы правы. Подключать нужно к тем ногам, которые предлагает CubeIDE.
К STM32F407xxx подключается к таким ногам (FSMC впервые я завёл на нём):
// FSMC GPIO Конфигурация // PE7 ------> FSMC_D4 // PE8 ------> FSMC_D5 // PE9 ------> FSMC_D6 // PE10 ------> FSMC_D7 // PE11 ------> FSMC_D8 // PE12 ------> FSMC_D9 // PE13 ------> FSMC_D10 // PE14 ------> FSMC_D11 // PE15 ------> FSMC_D12 // PD0 ------> FSMC_D2 // PD1 ------> FSMC_D3 // PD4 ------> FSMC_NOE // RD - чтение. Активный 0 // PD5 ------> FSMC_NWE // WR - запись. Активный 0 // PD7 ------> FSMC_NE1 // CS - выбор. Активный 0 // PG9 ------> FSMC_NE2 // CS - выбор. Активный 0 // PG10 ------> FSMC_NE3 // CS - выбор. Активный 0 // PG12 ------> FSMC_NE4 // CS - выбор. Активный 0 // PD8 ------> FSMC_D13 // PD9 ------> FSMC_D14 // PD10 ------> FSMC_D15 // PF0 ------> FSMC_A0 // RS - выбор данные/команда // PF1 ------> FSMC_A1 // RS - выбор данные/команда // PF2 ------> FSMC_A2 // RS - выбор данные/команда // PF3 ------> FSMC_A3 // RS - выбор данные/команда // PF4 ------> FSMC_A4 // RS - выбор данные/команда // PF5 ------> FSMC_A5 // RS - выбор данные/команда // PF12 ------> FSMC_A6 // RS - выбор данные/команда // PF13 ------> FSMC_A7 // RS - выбор данные/команда // PF14 ------> FSMC_A8 // RS - выбор данные/команда // PF15 ------> FSMC_A9 // RS - выбор данные/команда // PG0 ------> FSMC_A10 // RS - выбор данные/команда // PG1 ------> FSMC_A11 // RS - выбор данные/команда // PG2 ------> FSMC_A12 // RS - выбор данные/команда // PG3 ------> FSMC_A13 // RS - выбор данные/команда // PG4 ------> FSMC_A14 // RS - выбор данные/команда // PG5 ------> FSMC_A15 // RS - выбор данные/команда // PD11 ------> FSMC_A16 // RS - выбор данные/команда // PD12 ------> FSMC_A17 // RS - выбор данные/команда // PD13 ------> FSMC_A18 // RS - выбор данные/команда // PD14 ------> FSMC_D0 // PD15 ------> FSMC_D1
Следует учесть, что сигнал RS может оказаться инверсным. У меня такое было у дисплея RA8875.
Это статьи, которыми я пользовался.
В моих статьях есть ссылка на яндекс диск (Ссылка). Там есть драйвера на С++ для ILI9341. Можно написать по образу и подобию. Правда я пробовал его на F407. Для других нужно править. Я его не дописал ещё. Нужды не было. И есть статья, где я начал рассматривать подключение дисплеев
@matrex указанный вами чип умеет без проблем работать с фцмс, пример (выше на два поста) без проблем заведётся на данном чипе...
@matrex Вот схема подключения без сигнала RD. На этом дисплее у меня его не было.
@eduard у меня нет вашего дисплея, и я не знаю варианта кода инициализации драйвера дисплея без данных контактов... Вариант по которому я подключал написан в файлах, попробуйте "докинуть" недостающие - может прокатит инициализация и заведётся дисплей...
@andrej-8 Не совсем Вас понял. Какие файлы докинуть? У меня всё работает.
Спасибо за советы. Вот что удалось сделать за несколько дней.
Примеры, приведенные выше, разумеется, с первого раза не запустились. Оно и понятно – наверняка проблема в несовместимости драйверов. Мой драйвер, судя по упаковке LCD - NT35510. Скопировал последовательность инициализации с примера в ваш код – поучил «шум» (рис. 1). Адаптировал китайский пример программы под свой STM на Keil uVision5 – поучил «шум». Переделал инициализацию под SW4STM32 + Cube – результат «шум». Проверил схему подключения, обрывы, КЗ – результат тот же. Попробовал запустить проект, под который собственно это все и затевалось ( https://habr.com/ru/post/524498/), получил нечто похожее на результат (рис. 2), но опять же далекий от идеала.
Посему, мне кажется, что попался какой то экзотический драйвер дисплея, не NT35510 и не OTM8009A – ну или брак... Пока в раздумьях.
То, что у вас после инициализации появился шум, это просто отлично. Значит дисплей подключен правильно и понимает команды.
А шум просто случайные числа записанные в ОЗУ контроллера. Так всегда бывает при первом включении питания.
А то, что считаете за результат, он скорее и есть. Просто пример рассчитан на другой размер (количество пикселей по горизонтали и вертикали) экрана.
Если я не путаю, у вас дисплей должен быть 480х864, а в драйвере дисплея задаётся 480х800
Я связывался с автором проекта, как он говорит, это код по дисплей 800x480, правда под OTM8009A (у меня такой же 800х480 только драйвер NT35510). Я думаю что пока рано с ним разговаривать на эту тему, я хочу убедиться в том, что дисплей работает в принципе, поэтому хочу его хотя бы его просто запустить…
Вот вы говорите что в принципе хорошо что шум, типа LCD инициализируется, а в чем может быть проблема что дальше заливка не получается. Я и вашу функцию пробовал, и из примера… Странно как то… Может проблема в этих константах
// для записи данных #define LCD_DATA ((uint32_t)0x60020000) // для записи команд #define LCD_REG ((uint32_t)0x60000000)
Хотя я пробовал их менять, дисплей перестает работать вообще, а в китайском примере я ничего такого вообще не нашел.
@matrex Почитайте файлы, что я оставлял здесь на форуме. Там подробно расписано, что это за константы. Естественно не будет работать, если местами поменять.
Попробуйте сделать заливку одним цветом и не в цикле и покажите результат.
Да извините, почитал подробнее - теперь ясно на счет констант. По поводу заливки - собственно результата никакого - просто шум.
Вот код на всякий случай, инициализацию дисплея выпилил. Ну и функции для работы с памятью пришлось унифицировать, т.к. нужно было совместить ваш и китайский код. Цветом крашу при инициализации в initLCD().
#include "lcd.h" #include <stdint.h> // Простенькая функция задержки void delay(unsigned int delayTime) { uint32_t i; for(i = 0; i < delayTime; i++); } void LCD_WR_DATA(unsigned int data) { *(uint16_t *) (LCD_DATA)= data; } void LCD_WR_REG(unsigned int reg) { *(uint16_t *) (LCD_REG) = reg; } void LCD_WriteReg(unsigned int reg,unsigned int value) { *(uint16_t *) (LCD_REG) = reg; *(uint16_t *) (LCD_DATA) = value; } void LCD_WriteRAM_Prepare(void) { unsigned int wramcmd=0x2C00; LCD_WR_REG(wramcmd); } void LCD_SetWindows(unsigned int xStar, unsigned int yStar,unsigned int xEnd,unsigned int yEnd) { unsigned int setxcmd=0x2A00; unsigned int setycmd=0x2B00; LCD_WR_REG(setxcmd);LCD_WR_DATA(xStar>>8); LCD_WR_REG(setxcmd+1);LCD_WR_DATA(xStar&0XFF); LCD_WR_REG(setxcmd+2);LCD_WR_DATA(xEnd>>8); LCD_WR_REG(setxcmd+3);LCD_WR_DATA(xEnd&0XFF); LCD_WR_REG(setycmd);LCD_WR_DATA(yStar>>8); LCD_WR_REG(setycmd+1);LCD_WR_DATA(yStar&0XFF); LCD_WR_REG(setycmd+2);LCD_WR_DATA(yEnd>>8); LCD_WR_REG(setycmd+3);LCD_WR_DATA(yEnd&0XFF); LCD_WriteRAM_Prepare(); // GRAM } void LCD_Clear(unsigned int Color) { unsigned int i; LCD_SetWindows(0,0,LCD_W,LCD_H); for(i=0;i<LCD_W*LCD_H;i++) { LCD_WR_DATA(Color); } } void LCD_ClearA(unsigned int Color) { // Начальный и конечный адреса по горизонтали LCD_WriteReg(0x0050, 0); LCD_WriteReg(0x0051, 239); // Начальный и конечный адреса по вертикали LCD_WriteReg(0x0052, 0); LCD_WriteReg(0x0053, 319); LCD_WriteReg(32, 0); LCD_WriteReg(33, 0); LCD_WR_REG (34); // Красный for (int i = 0; i < 76800; i++) LCD_WR_DATA(Color); } void LCD_direction(char direction) { switch(direction){ case 0: LCD_WriteReg(0x3600,0x00); break; case 1: LCD_WriteReg(0x3600,(1<<5)|(1<<6)); break; case 2: LCD_WriteReg(0x3600,(1<<7)|(1<<6)); break; case 3: LCD_WriteReg(0x3600,(1<<7)|(1<<5)); break; default:break; } } /*******************************************************************/ void initLCD() { delay(1500); // инициализация из китайского примера delay(1500); // После этих команд появляется шум // Часть кода инициализация из китайского примера LCD_WR_REG(0x2900); LCD_WR_REG(0x2c00); // КИТАЙСКИЙ ПРИМЕР LCD_direction(USE_HORIZONTAL);// LCD_Clear(RED);// // ВАШ ПРИМЕР // LCD_ClearA( 0xF800); // красный }
Слушайте, а может какой то косяк при инициализации FSMC - я то пользовался кубом - для меня этот контроллер пока новинка - может какой чекбокс пропустил...
Или такой вопрос: необходимо ли явно настраивать порты STM32 к которым подключен LCD на "выход", или включение FSMC делает это автоматически. Я посмотрел, код который генирит куб. Настройки портов для связи с LCD в коде не прописываются (правда, может инициализация идет где-то глубже, например в HAL_SRAM_Init), в вашем же примере это сделано явно.
/** * @brief GPIO Initialization Function * @param None * @retval None */ static void MX_GPIO_Init(void) { GPIO_InitTypeDef GPIO_InitStruct = {0}; /* GPIO Ports Clock Enable */ __HAL_RCC_GPIOH_CLK_ENABLE(); __HAL_RCC_GPIOA_CLK_ENABLE(); __HAL_RCC_GPIOE_CLK_ENABLE(); __HAL_RCC_GPIOD_CLK_ENABLE(); /*Configure GPIO pin Output Level */ HAL_GPIO_WritePin(Led_GPIO_Port, Led_Pin, GPIO_PIN_RESET); /*Configure GPIO pin : Led_Pin */ GPIO_InitStruct.Pin = Led_Pin; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; HAL_GPIO_Init(Led_GPIO_Port, &GPIO_InitStruct); } /* FSMC initialization function */ static void MX_FSMC_Init(void) { FSMC_NORSRAM_TimingTypeDef Timing; /** Perform the SRAM1 memory initialization sequence */ hsram1.Instance = FSMC_NORSRAM_DEVICE; hsram1.Extended = FSMC_NORSRAM_EXTENDED_DEVICE; /* hsram1.Init */ hsram1.Init.NSBank = FSMC_NORSRAM_BANK1; hsram1.Init.DataAddressMux = FSMC_DATA_ADDRESS_MUX_DISABLE; hsram1.Init.MemoryType = FSMC_MEMORY_TYPE_SRAM; hsram1.Init.MemoryDataWidth = FSMC_NORSRAM_MEM_BUS_WIDTH_16; hsram1.Init.BurstAccessMode = FSMC_BURST_ACCESS_MODE_DISABLE; hsram1.Init.WaitSignalPolarity = FSMC_WAIT_SIGNAL_POLARITY_LOW; hsram1.Init.WrapMode = FSMC_WRAP_MODE_DISABLE; hsram1.Init.WaitSignalActive = FSMC_WAIT_TIMING_BEFORE_WS; hsram1.Init.WriteOperation = FSMC_WRITE_OPERATION_ENABLE; hsram1.Init.WaitSignal = FSMC_WAIT_SIGNAL_DISABLE; hsram1.Init.ExtendedMode = FSMC_EXTENDED_MODE_DISABLE; hsram1.Init.AsynchronousWait = FSMC_ASYNCHRONOUS_WAIT_DISABLE; hsram1.Init.WriteBurst = FSMC_WRITE_BURST_DISABLE; hsram1.Init.PageSize = FSMC_PAGE_SIZE_NONE; /* Timing */ Timing.AddressSetupTime = 15; Timing.AddressHoldTime = 15; Timing.DataSetupTime = 255; Timing.BusTurnAroundDuration = 15; Timing.CLKDivision = 16; Timing.DataLatency = 17; Timing.AccessMode = FSMC_ACCESS_MODE_A; /* ExtTiming */ if (HAL_SRAM_Init(&hsram1, &Timing, NULL) != HAL_OK) { Error_Handler( ); } }
Или такой вопрос: необходимо ли явно настраивать порты STM32 к которым подключен LCD на "выход", или включение FSMC делает это автоматически. Я посмотрел, код который генирит куб. Настройки портов для связи с LCD в коде не прописываются (правда, может инициализация идет где-то глубже, например в HAL_SRAM_Init), в вашем же примере это сделано явно.
Должен инициализировать автоматически в сгенерированном коде, может где-то в stm32xx_hal_msp.c.