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

Речь пойдёт о стареньком 23-дюймовом Samsung SyncMaster BX2340 (выпущен в январе 2011) со светодиодной подсветкой. Со временем стал замечать, что работать за ним утомительно, а сосредоточиться всё сложнее. И даже не только работать, просто читать, например. Сам монитор остался тот же, но мне стало труднее. А за другими экранами работалось вполне нормально.
Как-то в интернетах читал про субъективные ощущения пользователей телефонов с OLED дисплеями с частотой обновления 240 Гц. Жаловались на утомляемость и головную боль. И были упоминания (без пруфов) исследований по влиянию частоты диммирования подсветки на организм: хотя глаз не видит мерцания в 240 Гц, мозг на него реагирует. А постоянное свечение или с частотой более 3 кГц не нагружает мозг таким образом.
Затем на ютубе попался ролик про переделку подсветки монитора на постоянный ток. Вмешательство в схему было кардинальным. Под роликом были комментарии о смещении цветов при низких токах на сведиодах. А у меня подсветка работает на значениях 10-25%, т. к. помещение довольно тёмное. UPD: В ролике у автора была только одна гирлянда светодиодов, а у меня — 4.
Было решено оставить управление яркостью с помощью ШИМ, но увеличить частоту. Я даже не стал мерять мерцание неинвазивным методом с помощью фоторезистора или фотодиода, сразу разобрал монитор.

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

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

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

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

С дросселем всё в порядке, он продолжает работать на частоте 320 кГц, но если раньше частота ШИМ была 180 Гц и почти не слышна (только если поднести ухо), то 2,9 кГц очень хорошо слышно. И комфорта явно не прибавилось. А что если вывести частоту за верхнюю границу слышимости? Например,
? Меняем множитель предделителя таймера ШИМ с 16 на 2, прошиваем. Оказалось, что всё в порядке. Почти.
Восьмибитных таймеров в данном случае недостаточно, нужно больше минералов. Проявляется это в виде низкочастотных флуктуаций яркости, с плавным нарастанием и исчезновением периодичностью в несколько секунд. Чтобы справиться с этой напастью, можно взять кристалл пожирнее, но это не наш путь. Будем наращивать разрядность измеряющего таймера программным путём и введём порог (гистерезис) для надёжного обнаружения переключения яркости пользователем (0–100 с дискретностью 1). Точность измерительного таймера поднимем в 256 раз, и множитель предделителя становится равным 1.
Обработчик переполнения измерительного таймера с вариантом «что-то пошло не так и длительность уровня затянулась»:
Внешнее прерывание теперь обрабатывается тоже несколько сложнее:
Появились глобальные переменные, которые я загнал в регистры, у нас же оверклокинг как-никак. SRAM используется только для сохранения адреса возврата при входе в обработчики прерываний. Старшая часть счётчика измерения интервалов находится в переменной time_h, а величины измеренной длины цикла ШИМ и скважности — в time_cycle и time_on соответственно. THRESHOLD — порог детекции изменения яркости.
Вот теперь всё заработало, как и задумывалось.
Можете называть это самовнушением, но результат такой: жить стало лучше, жить стало веселей! Даже сдвинулись давно зависшие проекты.
Если в вашем случае частота подсветки никак не влияет на самочувствие и продуктивность — считайте, что вам повезло. Наверное. Как и людям, уверяющим, что им абсолютно комфортно при содержании CO2 в помещении более 0,2% (2000 м. д.).

Речь пойдёт о стареньком 23-дюймовом Samsung SyncMaster BX2340 (выпущен в январе 2011) со светодиодной подсветкой. Со временем стал замечать, что работать за ним утомительно, а сосредоточиться всё сложнее. И даже не только работать, просто читать, например. Сам монитор остался тот же, но мне стало труднее. А за другими экранами работалось вполне нормально.
Как-то в интернетах читал про субъективные ощущения пользователей телефонов с OLED дисплеями с частотой обновления 240 Гц. Жаловались на утомляемость и головную боль. И были упоминания (без пруфов) исследований по влиянию частоты диммирования подсветки на организм: хотя глаз не видит мерцания в 240 Гц, мозг на него реагирует. А постоянное свечение или с частотой более 3 кГц не нагружает мозг таким образом.
Затем на ютубе попался ролик про переделку подсветки монитора на постоянный ток. Вмешательство в схему было кардинальным. Под роликом были комментарии о смещении цветов при низких токах на сведиодах. А у меня подсветка работает на значениях 10-25%, т. к. помещение довольно тёмное. UPD: В ролике у автора была только одна гирлянда светодиодов, а у меня — 4.
Было решено оставить управление яркостью с помощью ШИМ, но увеличить частоту. Я даже не стал мерять мерцание неинвазивным методом с помощью фоторезистора или фотодиода, сразу разобрал монитор.

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

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

Теперь нужно как-то поднять частоту ШИМ до килогерцовых значений, раз в 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-генератора.
- Измерительный таймер. Сколько тактов в периоде диммирования?
. Чтобы это влезло в восьмибитный регистр таймера с минимальной потерей точности, предделитель возьмём 256, максимальное значение счётчика будет
.
- Таймер ШИМ. Частоту сделаем в 16 раз больше:
, тогда предделитель во столько же раз меньше:
.
Входной сигнал заведён на ножку внешнего прерывания. Обработчик оного:
/* External Interrupt 0 */ ISR(INT0_vect, ISR_NAKED) { uint8_t timer = TCNT0; // Значение таймера измерения интервалов if (PINB & 1<<PB2) { // Входящий сигнал. Высокий уровень - окончание цикла измерения OCR1C = timer; // Период ШИМ TCNT0 = 0; // Обнуление таймера измерения интервалов } else { // Низкий уровень - скважность OCR1A = timer; // Скважность ШИМ } reti(); }
Что за ISR_NAKED?
«ISR_NAKED» означает, что выкинуто сохранение/восстановление регистров и флагов процессора, это сделано для ускорения. Это можно сделать, удостоверившись, что в главном цикле они не затрагиваются (у нас там просто бесконечный цикл
while(1) {}), и что не будет вызовов из подпрограмм. Ну и в конце прописывам возврат из функции с взведением флага разрешения прерываний reti().Спаял, прошил — и оно заработало!

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

С дросселем всё в порядке, он продолжает работать на частоте 320 кГц, но если раньше частота ШИМ была 180 Гц и почти не слышна (только если поднести ухо), то 2,9 кГц очень хорошо слышно. И комфорта явно не прибавилось. А что если вывести частоту за верхнюю границу слышимости? Например,
Восьмибитных таймеров в данном случае недостаточно
Обработчик переполнения измерительного таймера с вариантом «что-то пошло не так и длительность уровня затянулась»:
/* 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<<PB2) { OCR1A = TIME_H_LIM; // Always on } else { OCR1A = 0; // Always off } OCR1C = TIME_H_LIM; time_h = 0; time_cycle = 0; time_on = 0; } reti(); // Because ISR_NAKED }
Внешнее прерывание теперь обрабатывается тоже несколько сложнее:
/* External Interrupt 0 */ ISR(INT0_vect, ISR_NAKED) { // F_CPU / Timer1 prescaler / F_PWM_IN / grades / 4 #define THRESHOLD (F_CPU / 1 / F_PWM_IN / 100 / 4) uint16_t time; uint8_t time_l = TCNT0; if ((TIFR & 1<<TOV0) && (time_l <= UCHAR_MAX/2)) { // Overflow occured right now time_l = UCHAR_MAX; // 0xff } time = (time_h << 8) + time_l; if (PINB & 1<<PB2) { // Risen if (abs(time - time_cycle) > THRESHOLD) { time_cycle = time; OCR1C = time_h; } TCNT0 = 0; time_h = 0; if (TIFR & 1<<TOV0) { TIFR = 1<<TOV0; // Clear Timer0 overflow flag } } else { // Falled if (abs(time - time_on) > 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 <avr/interrupt.h> #include <avr/wdt.h> #include <stdlib.h> #include <limits.h> #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<<ACD; // Comparator disable // Timer0 TCCR0A = 0; // CK/1 TCCR0B = 1<<CS00; // Timer1 DDRB |= 1<<PB1; // PWM output // CK/2, Clear the OC1A output line TCCR1 = 1<<CTC1|1<<PWM1A|2<<COM1A0|2<<CS10; TIMSK |= 1<<TOIE0; // Timer0 overflow // Ext int 0 MCUCR |= 1<<ISC00; // Any logical change on INT0 generates an interrupt request GIMSK |= 1<<INT0; // External Interrupt Request 0 Enable PORTB |= 1<<PB2; // Input wdt_enable(WDTO_120MS); // Watchdog on sei(); // Interrupts enable while (1) { // Do not use flags or registers wdt_reset(); // Watchdog reset } } /* External Interrupt 0 */ ISR(INT0_vect, ISR_NAKED) { // F_CPU / Timer1 prescaler / F_PWM_IN / grades / 4 #define THRESHOLD (F_CPU / 1 / F_PWM_IN / 100 / 4) uint16_t time; uint8_t time_l = TCNT0; if ((TIFR & 1<<TOV0) && (time_l <= UCHAR_MAX/2)) { // Overflow occured right now time_l = UCHAR_MAX; // 0xff } time = (time_h << 8) + time_l; if (PINB & 1<<PB2) { // Risen if (abs(time - time_cycle) > THRESHOLD) { time_cycle = time; OCR1C = time_h; } TCNT0 = 0; time_h = 0; if (TIFR & 1<<TOV0) { TIFR = 1<<TOV0; // Clear Timer0 overflow flag } } else { // Falled if (abs(time - time_on) > 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<<PB2) { OCR1A = TIME_H_LIM; // Always on } else { OCR1A = 0; // Always off } OCR1C = TIME_H_LIM; time_h = 0; time_cycle = 0; time_on = 0; } reti(); // Because ISR_NAKED }
Можете называть это самовнушением, но результат такой: жить стало лучше, жить стало веселей! Даже сдвинулись давно зависшие проекты.
Если в вашем случае частота подсветки никак не влияет на самочувствие и продуктивность — считайте, что вам повезло. Наверное. Как и людям, уверяющим, что им абсолютно комфортно при содержании CO2 в помещении более 0,2% (2000 м. д.).
А как же ссылка на гитхаб?
Только зарегистрированные пользователи могут участвовать в опросе. Войдите, пожалуйста.
Как вы относитесь к гаджетам с AMOLED-экранами?
24.33%Покупаю, доволен, улучшается самочувствие и отменный аппетит!91
24.6%Абсолютно всё равно.92
9.36%Пользовался, замечал что-то неладное.35
33.96%Только IPS!127
4.55%Чёрно-белый экран — наш кандидат!17
21.12%Когда уже будет массовый быстрый цветной e-ink?79
1.07%Другое, напишу в комментариях.4
Проголосовали 374 пользователя. Воздержались 107 пользователей.
