Волею судеб в моих руках оказался лишний дисплей 4.3" 480х272 точки, шлейф 40 pin. Китайцы часто используют его в видеорегистраторах, навигаторах. Нашёл в сети описание, прозвонил. Выяснил, что это RGB дисплей, памяти на борту не имеет, требует импульсы строчной и кадровой развёртки. В сети присутствует несколько статей по запуску таких дисплеев. Это подвигло меня написать программку на широко распространённый микроконтроллер stm32f103cbt6, благо он обладает 4 таймерами и 20кБ ОЗУ. Использую среду Keil v5.27, библиотеки CMSIS. Если взять по одному проводу на каждый байт цвета (можно и по два), и принять размер пикселя 3х3, то потребуется 160х91=14560 байт ОЗУ. Восемь цветов мне вполне хватит для отображения информации.
Таймер 4 будет мастером, его частота должна составлять около 10МГц по описанию дисплея. Однако на практике можно понизить её до 1 МГц без заметного ухудшения качества картинки. Остальные таймеры тактируются от TIM4.
TIM2CH1 выдаёт импульсы синхронизации горизонтальной развёртки (PA15 ремапированный 1 канал таймера 2). TIM1CH1 выдаёт импульсы синхронизации вертикальной развёртки (PA8). TIM3 делит частоту TIM4 на три и стробирует выгрузку данных в порт PB ( используется 3 бита PB0,PB1,PB2 ) с помощью DMA .
Конфигурация таймеров:
//master dotclk
TIM4->CR1 = 0;
TIM4->CR2 |= TIM_CR2_MMS_2;
TIM4->PSC = 0;
TIM4->ARR = 32;
TIM4->EGR |=TIM_EGR_UG; //(1 << TIM_EGR_UG);
TIM4->CCMR1 |= TIM_CCMR1_OC1M_2 |TIM_CCMR1_OC1M_1 | TIM_CCMR1_OC1M_0 ;//pwm
TIM4->CCER |= TIM_CCER_CC1E ;//Выход канала вкл
TIM4->CCR1 = 3;//PB6 dotCLK
TIM2->CR1 = 0;//HCLK
TIM2->PSC=0;
TIM2->ARR = 547;//Период
TIM2->EGR |=TIM_EGR_UG;
TIM2->CCMR1 |= TIM_CCMR1_OC2M_2 |TIM_CCMR1_OC2M_1 | TIM_CCMR1_OC2M_0 |TIM_CCMR1_OC1M_2 |TIM_CCMR1_OC1M_1 | TIM_CCMR1_OC1M_0;
TIM2->CCMR2 |= TIM_CCMR2_OC3M_2 |TIM_CCMR2_OC3M_1 | TIM_CCMR2_OC3M_0 ;//ist itr
TIM2->CCER |= TIM_CCER_CC1E;//Выход канала 1 включен pa0(remap pa15)
TIM2->SMCR|= TIM_SMCR_SMS_2 | TIM_SMCR_SMS_1 | TIM_SMCR_SMS_0 | TIM_SMCR_TS_1 | TIM_SMCR_TS_0;//extern clock mode1 tim4
TIM2->CCR1 = 30;//PA0 HCLK
TIM2->CCR2 = 41;
TIM_ITConfig(TIM2, TIM_IT_CC2, ENABLE);
NVIC_EnableIRQ(TIM2_IRQn);
//VCLK
TIM1->CR1 = 0;
TIM1->PSC=547;
TIM1->ARR = 290;
TIM1->CCMR1 |= TIM_CCMR1_OC2M_2 |TIM_CCMR1_OC2M_1 | TIM_CCMR1_OC2M_0 |TIM_CCMR1_OC1M_2 |TIM_CCMR1_OC1M_1 | TIM_CCMR1_OC1M_0;
TIM1->CCER |= TIM_CCER_CC1E;//Выход канала 1 включен pa8
TIM1->SMCR|= TIM_SMCR_SMS_2 | TIM_SMCR_SMS_1 | TIM_SMCR_SMS_0 | TIM_SMCR_TS_1 | TIM_SMCR_TS_0;//extern clock mode1 tim4
TIM1->CCR1 = 4;//PA8 VCLK
TIM1->BDTR |=TIM_BDTR_MOE;
TIM1->DIER |=TIM_DIER_CC2IE ;
NVIC_EnableIRQ(TIM1_CC_IRQn);
//for takt DMA
TIM3->CR1 = 0;
TIM3->SMCR|= TIM_SMCR_SMS_2 | TIM_SMCR_SMS_1 | TIM_SMCR_SMS_0 | TIM_SMCR_TS_1 | TIM_SMCR_TS_0;
TIM3->CCMR1 |= TIM_CCMR1_OC1M_2 |TIM_CCMR1_OC1M_1 | TIM_CCMR1_OC1M_0;
TIM3->PSC=0;
TIM3->ARR = 2;
TIM3->CCR1 =1;
TIM3->EGR |=TIM_EGR_UG;
TIM3->DIER |=TIM_DIER_UDE ;//по переполнению DMA 3 канал
void TIM2_IRQHandler(void)
{
if (TIM_GetITStatus(TIM2, TIM_IT_CC2) != RESET)
{
TIM4->CR1 &= ~TIM_CR1_CEN;
TIM_ClearITPendingBit(TIM2, TIM_IT_CC2);
DMA1_Channel3->CCR &= ~DMA_CCR3_EN;
DMA1_Channel3->CNDTR = 160;
DMA1_Channel3->CMAR = (uint32_t)& (lcd[stroka][0]);
DMA1_Channel3->CCR |= DMA_CCR3_EN;
dobavka++;
Дисплей RGB24, запуск от BluePill (stm32f103cbt6).
if(dobavka>2){dobavka=0;stroka++;}//по 3 строки вместо одной
if(stroka==92){stroka=91;}
TIM3->EGR |=TIM_EGR_UG;//сброс счетчика cnt
TIM4->EGR |=TIM_EGR_UG;
TIM4->CR1 |= TIM_CR1_CEN;
}
TIM2->SR=~TIM_SR_UIF;
}
void TIM1_CC_IRQHandler(void){
stroka=0;//кадровый синхроимпульс, сброс счёта строк
dobavka=0;
TIM1->SR=~TIM_SR_CC2IF;
}
void DMA_init(void)
{
RCC->AHBENR |= RCC_AHBENR_DMA1EN; //Разрешаем тактирование первого DMA модуля
DMA1_Channel3->CCR &= ~DMA_CCR3_EN;
DMA1_Channel3->CPAR = (uint32_t)&(GPIOB->ODR); //Указываем адрес периферии - регистр результата преобразования АЦП для регулярных каналов
DMA1_Channel3->CMAR = (uint32_t)& (lcd[stroka][0]); //Задаем адрес памяти - базовый адрес массива в RAM
DMA1_Channel3->CCR |= DMA_CCR3_DIR; //Указываем направление передачи данных, из память в периферии
DMA1_Channel3->CNDTR = 160; //Количество пересылаемых значений
DMA1_Channel3->CCR &= ~DMA_CCR3_PINC; //Адрес периферии не инкрементируем после каждой пересылки
DMA1_Channel3->CCR |= DMA_CCR3_MINC; //Адрес памяти инкрементируем после каждой пересылки.
DMA1_Channel3->CCR &= ~DMA_CCR3_PSIZE_0; //Размерность данных периферии -0-8bit, 1-16 бит,2-32bit
DMA1_Channel3->CCR &= ~DMA_CCR3_MSIZE_0; //Размерность данных памяти - 8 бит
DMA1_Channel3->CCR |= DMA_CCR3_PL_0; //Приоритет - высокий
DMA1_Channel3->CCR &= ~DMA_CCR3_CIRC; //не Разрешаем работу DMA в циклическом режиме
DMA1_Channel3->CCR |= DMA_CCR3_EN; //Разрешаем работу 3-го канала DMA
}
Подсветка требует повышенного напряжения около 22 В.
Сделал повышающий DC-DC преобразователь со стабилизацией по току.
Требуется примерно 10мА, ток определяется резистором R1.
Чтобы преобразователь не сгорел при обрыве контакта в разъёме дисплея, установлен защитный стабилитрон на 24 В.
Плюсы:
1. Большой экран, крупные символы.
2. Всего восемь проводников в шине дисплея. Питание 3.3 В, земля и шесть сигнальных проводов.
3. Использование DMA разгружает процессор.
Минусы:
1. Расходуется четыре таймера.
2. Расходуется много оперативной памяти (14.5 кБ).