Разгон подсветки монитора

Оверклокинг процессора или памяти — это понятно, но зачем разгонять подсветку монитора?

j9-xtd1vnzydcain6_yk9lq6u7k.png

Речь пойдёт о стареньком 23-дюймовом Samsung SyncMaster BX2340 (выпущен в январе 2011) со светодиодной подсветкой. Со временем стал замечать, что работать за ним утомительно, а сосредоточиться всё сложнее. И даже не только работать, просто читать, например. Сам монитор остался тот же, но мне стало труднее. А за другими экранами работалось вполне нормально.
Как-то в интернетах читал про субъективные ощущения пользователей телефонов с OLED дисплеями с частотой обновления 240 Гц. Жаловались на утомляемость и головную боль. И были упоминания (без пруфов) исследований по влиянию частоты диммирования подсветки на организм: хотя глаз не видит мерцания в 240 Гц, мозг на него реагирует. А постоянное свечение или с частотой более 3 кГц не нагружает мозг таким образом.

Затем на ютубе попался ролик про переделку подсветки монитора на постоянный ток. Вмешательство в схему было кардинальным, и размеры деталей этого блока не вписались в габариты копуса монитора (ЕМНИП). Под роликом были комментарии о смещении цветов при низких токах на сведиодах. А у меня подсветка работает на значениях 10–25%, т. к. помещение довольно тёмное.

Так было решено оставить управление яркостью с помощью ШИМ, но увеличить частоту. Я даже не стал мерять мерцание неинвазивным методом с помощью фоторезистора или фотодиода, сразу разобрал монитор.

vhxogvdagy1igeuolvfj8pnaqpq.jpeg

Контроллер подсветки — OZ9993CN. Нормального даташита не оказалось, только групповой драйверов подсветки производства O2Micro. Выяснилось, что драйвер занимается также и повышением напряжения (согласно измерениям с 14,4 В до 54,6 В) с использованием мощного внешнего полевого транзистора и индуктивности.

Одна из схем похожего по смыслу драйвера, номера выводов не совпадают:

cmz015ibazr_t1kscsgzsi1u8aw.png

На плате дорожка сигнала ШИМ на драйвер подписана как B-Dim (Backlight dimming?), искать не пришлось. Далее в дело вступил клон цифрового USB-осцилографа USBee AX в сочетании с sigrok на стороне ПК. Замер показал, что частота подсветки 180 Гц (маловато будет!). Высокий уровень сигнала — 5 В.

sacwehre4ijik_-yuuwyqscppfs.png

Теперь нужно как-то поднять частоту ШИМ до килогерцовых значений, раз в 16. Первое, что пришло в голову влепить в разрыв дорожки ШИМ микроконтроллер для приёма сигнала и воспроизведения его в 16 раз ускоренном варианте. Нужны 2 таймера, один будет измерять длительность низкого и высокого уровней, другой — выдавать сигнал ШИМ. Подобрав коэффициенты предделителя, обойдёмся вообще без арифметики, просто копированием. Нет, Ардуино не будет. Ассемблера тоже не будет, будет GCС. Мелким МК с минимум двумя таймерами (из имеющихся в запасе) оказался ATtiny15. Но WinAVR не хочет с ним работать, поэтому пришлось взять более старшую версию — ATtiny45 (ATtiny25/85 так же подойдут).

Схема:

             100n
      ┌───────┤├───────┐
      │ ┌────────────┐ │
      │ │ 1        8 ├─┴─ VCC
      │ │ 2        7 ├─ PB2 (INT0)  INPUT     
      │ │ 3        6 ├─ PB1 (OC1A)  OUTPUT
 GND ─┴─┤ 4        5 │
        └────────────┘
           ATtiny45


Подбираем множители предделителей таймеров. Частоту CPU возьмём примерно 8 МГц, от встроенного RC-генератора.

  • Измерительный таймер. Сколько тактов в периоде диммирования? $8000000 / 180 \approx 44444$. Чтобы это влезло в восьмибитный регистр таймера с минимальной потерей точности, предделитель возьмём 256, максимальное значение счётчика будет $8000000 / 180 / 256 \approx 173,6$.
  • Таймер ШИМ. Частоту сделаем в 16 раз больше: $180 \cdot 16 = 2880 Гц$, тогда предделитель во столько же раз меньше: $256 / 16 = 16$.


Входной сигнал заведён на ножку внешнего прерывания. Обработчик оного:

/* External Interrupt 0 */
ISR(INT0_vect, ISR_NAKED) {
    uint8_t timer = TCNT0; // Значение таймера измерения интервалов
    if (PINB & 1<


Что за ISR_NAKED?

«ISR_NAKED» означает, что выкинуто сохранение/восстановление регистров и флагов процессора, это сделано для ускорения. Это можно сделать, удостоверившись, что в главном цикле они не затрагиваются (у нас там просто бесконечный цикл while(1) {}), и что не будет вызовов из подпрограмм. Ну и в конце прописывам возврат из функции с взведением флага разрешения прерываний reti().


Спаял, прошил — и оно заработало!

bbate0_liq4thqfjsibldj4yd-w.jpeg

Но дроссель стал пищать. Смотрим, что там на затворе полевика, управляющим током через силовой дроссель:

njiaphmjgkj_23joxovlut5-afm.png

С дросселем всё в порядке, он продолжает работать на частоте 320 кГц, но если раньше частота ШИМ была 180 Гц и почти не слышна (только если поднести ухо), то 2,9 кГц очень хорошо слышно. И комфорта явно не прибавилось. А что если вывести частоту за верхнюю границу слышимости? Например, $180 Гц \cdot 128 = 23040 Гц$? Меняем множитель предделителя таймера ШИМ с 16 на 2, прошиваем. Оказалось, что всё в порядке. Почти.

Восьмибитных таймеров в данном случае недостаточно, нужно больше минералов. Проявляется это в виде низкочастотных флуктуаций яркости, с плавным нарастанием и исчезновением периодичностью в несколько секунд. Чтобы справиться с этой напастью, можно взять кристалл пожирнее, но это не наш путь. Будем наращивать разрядность измеряющего таймера программным путём и введём порог (гистерезис) для надёжного обнаружения переключения яркости пользователем (0–100 с дискретностью 1). Точность измерительного таймера поднимем в 256 раз, и множитель предделителя становится равным 1.

Обработчик переполнения измерительного таймера с вариантом «что-то пошло не так и длительность уровня затянулась»:

/* Timer/Counter0 Overflow */
ISR(TIM0_OVF_vect, ISR_NAKED) {

    #define TIME_H_LIM (UCHAR_MAX-1)

    if (time_h < TIME_H_LIM) { // Normal way
        time_h += 1;
    }
    else { // High part overflowed
        if (PINB & 1<


Внешнее прерывание теперь обрабатывается тоже несколько сложнее:

/* External Interrupt 0 */
ISR(INT0_vect, ISR_NAKED) {

    // F_CPU / Timer1 prescaler / F_PWM_IN / grades / 4
    #define THRESHOLD (F_CPU / 1 / 180 / 100 / 4)

    uint16_t time;
    uint8_t time_l = TCNT0;

    if ((TIFR & 1< THRESHOLD) {
            time_cycle = time;
            OCR1C = time_h;
        }
        TCNT0 = 0;
        time_h = 0;
        if (TIFR & 1< THRESHOLD) {
            time_on = time;
            OCR1A = time_h;
        }
    }
    reti(); // Because ISR_NAKED
}


Появились глобальные переменные, которые я загнал в регистры, у нас же оверклокинг как-никак. SRAM используется только для сохранения адреса возврата при входе в обработчики прерываний. Старшая часть счётчика измерения интервалов находится в переменной time_h, а величины измеренной длины цикла ШИМ и скважности — в time_cycle и time_on соответственно. THRESHOLD — порог детекции изменения яркости.

Вот теперь всё заработало, как и задумывалось.

Полный код
/*
 PWM frequency multiplier x128

             100n
      ┌───────┤├───────┐
      │ ┌────────────┐ │
      │ │ 1        8 ├─┴─ VCC
      │ │ 2        7 ├─ PB2 (INT0)  INPUT     
      │ │ 3        6 ├─ PB1 (OC1A)  OUTPUT
 GND ─┴─┤ 4        5 │
        └────────────┘
           ATtiny45

fuses: lfuse=0xe2 hfuse=0xdf
*/
#include 
#include 
#include 
#include 

#define F_CPU 8000000UL
#define F_PWM_IN 180U

register uint8_t time_h asm("r4"); // High part of time counter
register uint16_t time_cycle asm("r12"); // Period 
register uint16_t time_on asm("r14"); // H level duration

__attribute__((naked)) int main(void) {

    time_h = 0;
    time_cycle = 0;
    time_on = 0;

    ACSR |= 1< THRESHOLD) {
            time_cycle = time;
            OCR1C = time_h;
        }
        TCNT0 = 0;
        time_h = 0;
        if (TIFR & 1< THRESHOLD) {
            time_on = time;
            OCR1A = time_h;
        }
    }
    reti(); // Because ISR_NAKED

}

/* Timer/Counter0 Overflow */
ISR(TIM0_OVF_vect, ISR_NAKED) {

    #define TIME_H_LIM (UCHAR_MAX-1)

    if (time_h < TIME_H_LIM) { // Normal way
        time_h += 1;
    }
    else { // High part overflowed
        if (PINB & 1<


Можете называть это самовнушением, но результат такой: жить стало лучше, жить стало веселей! Даже сдвинулись давно зависшие проекты.

Если в вашем случае частота подсветки никак не влияет на самочувствие и продуктивность — считайте, что вам повезло. Наверное. Как и людям, уверяющим, что им абсолютно комфортно при содержании CO2 в помещении более 0,2% (2000 м. д.).

© Habrahabr.ru