То что предлагаете вы - это похоже на эмуляцию протокола.
Вы меня неправильно поняли. Я просто указал какие ноги должны быть у дисплея для подключения по 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 указанный вами чип умеет без проблем работать с фцмс, пример (выше на два поста) без проблем заведётся на данном чипе...
@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.
@eduard собственно об RA8875, а остались ли у вас проверочная прошивка под этот дисплей на FSMC?



