LED PWM Controller (сокращенно контроллер LEDC) это периферийное устройство, разработанное для генерации ШИМ сигналов (Pulse Width Modulation, PWM), управляющих яркостью светодиодов (LED). Контроллер LEDC снабжен также функцией автоматического фейдинга - плавного управления яркостью. Кроме управления светодиодами, LEDC может использоваться и для других целей - например для ЦАП лабораторных блоков питания, генерации звуковых сигналов и т. п.
Примечание: в этой статье приведен перевод главы 30 документации [1], посвященной аппаратуре контроллера LEDC. Описание API-функций ESP-IDF для управления LEDC см. в [2].
У контроллера LEDC имеются следующие функциональные возможности:
• 6 независимых генераторов PWM (т. е. 6 каналов). • 4 независимых таймера с делителями тактовой частоты, поддерживающими дробное деление. • Автоматическое управление плавным изменением скважности (фейдинг, т. е. увеличение/уменьшение скважности периода ШИМ с заданной скоростью). Эта функция работает аппаратно (без участия CPU), не внося помехи в формируемый сигнал. • Настраиваемая фаза вывода сигнала PWM. • Вывод сигнала PWM в режиме пониженного энергопотребления (Light-sleep mode). • Максимальная разрешающая способность PWM 14 бит.
Обратите внимания, что 4 таймера идентичны в контексте их функций и работоспособности. В следующих секциях таймеры обозначаются как Timerx (где x это число в диапазоне от 0 до 3). Подобным образом шесть генераторов (каналов) PWM также идентичны в контексте их функционирования, и они в этом описании обозначаются как PWMn (n в диапазоне от 0 до 5).
Рис. 30-1. Архитектура LED PWM.
4 таймера могут быть сконфигурированы независимо (т. е. у них по отдельности конфигурируется делитель тактовой частоты и значение переполнения счетчика), и в каждом таймере есть свой отдельный счетчик базы времени (т. е. счетчик, который считает такты опорной частоты). Для генератора PWM выбирается один из таймеров, счетчик которого используется для генерации сигнала PWM. Рис. 30-2 показывает основные функциональные блоки таймера и генератора PWM.
Рис. 30-2. Блок схема генератора LED PWM.
[Таймеры LEDC]
Каждый таймер LEDC содержит индивидуальный счетчик для отсчета базы времени. Тактовый сигнал счетчика обозначается как ref_pulsex (см. рис. 30-2). Все таймеры используются один и тот же источник тактов LEDC_CLKx, который проходит через делитель для формирования тактов ref_pulsex счетчика.
Источник тактов. Для тактирования регистров конфигурации LEDC используется тактовая частота шины APB_CLK (для дополнительной информации о частоте APB_CLK см. главу 6 "Reset and Clock" [1]. Чтобы можно было использовать периферийное устройство LED PWM, для него должен быть разрешен сигнал APB_CLK. Сигнал APB_CLK для LED PWM может быть разрешен установкой поля SYSTEM_LEDC_CLK_EN в регистре SYSTEM_PERIP_CLK_EN0_REG, и сброшен программно путем установки поля SYSTEM_LEDC_RST в регистре SYSTEM_PERIP_RST_EN0_REG. Для дополнительной информации см. таблицу 14-1 главы 14 "System Registers (SYSREG)" [1].
Для таймеров в контроллере LEDC выбирается общий тактовый сигнал LEDC_CLKx, который может быть одним из следующих источников: APB_CLK, FOSC_CLK и XTAL_CLK (подробности по каждому из этих сигналов тактов см. в главе 6 "Reset and Clock" [1]). Процедура для выбора источника тактов для LEDC_CLKx следующая:
APB_CLK: выбирается установкой LEDC_APB_CLK_SEL[1:0] в 1. FOSC_CLK: выбирается установкой LEDC_APB_CLK_SEL[1:0] в 2. XTAL_CLK: выбирается установкой LEDC_APB_CLK_SEL[1:0] в 3.
После этого сигнал LEDC_CLKx поступает на индивидуальные делители тактов каждого таймера LEDC.
Конфигурация делителя тактов. Сигнал тактов LEDC_CLKx, проходя через делитель, формирует сигнал ref_pulsex для счетчика. Частота ref_pulsex равна частоте LEDC_CLKx, поделенной на значение делителя LEDC_CLK_DIV_TIMERx (см. рис. 30-2).
Значение делителя LEDC_CLK_DIV_TIMERx дробное, т. е. делитель поддерживает не целые значения коэффициентов деления. LEDC_CLK_DIV_TIMERx конфигурируется через поле LEDC_CLK_DIV_TIMERx в соответствии со следующей формулой.
LEDC_CLK_DIV_TIMERx = A + (B/256)
Здесь A соответствует старшим 10 битам LEDC_CLK_DIV_TIMERx (т. е. LEDC_TIMERx_CONF_REG[21:12]). Числитель дроби B соответствует 8 младшим битам LEDC_CLK_DIV_TIMERx (т. е. LEDC_TIMERx_CONF_REG[11:4]).
Когда дробная часть B равна 0, коэффициент LEDC_CLK_DIV_TIMERx эквивалентен целому значению коэффициента делителя частоты (т. е. используется целочисленный прескалер). Другими словами, импульс частоты ref_pulsex генерируется на каждом A-том импульсе частоты LEDC_CLKx (частота ref_pulsex в A раз меньше частоты LEDC_CLKx).
Однако если B != 0, то коэффициент деления LEDC_CLK_DIV_TIMERx становится не целым. Делитель частоты тактов в этом случае реализует дробный коэффициент деления частоты тактов LEDC_CLKx путем чередования между A и (A+1) тактовых импульсов LEDC_CLKx для формирования импульса ref_pulsex. В результате есть возможность более точно подстроить среднюю частоту ref_pulsex импульсов для счетчика. Для каждого 256-го импульса ref_pulsex:
• Количество B импульсов ref_pulsex будет содержать (A+1) импульсов LEDC_CLKx. • Количество (256-B) импульсов ref_pulsex будет содержать A импульсов LEDC_CLKx. • Импульсы ref_pulsex, состоящие из (A+1) импульсов, равномерно распределяются между импульсами A.
Рис. 30-3 иллюстрирует взаимосвязь импульсов тактов LEDC_CLKx и импульсов ref_pulsex, когда используется дробный коэффициент деления LEDC_CLK_DIV_TIMERx (когда B != 0).
Рис. 30-3. Деление частоты LEDC_CLK_DIV_TIMERx на дробное значение.
Для изменения коэффициента деления таймера во время выполнения программы (runtime) сначала установите поле LEDC_CLK_DIV_TIMERx, и затем установите поле LEDC_TIMERx_PARA_UP для применения новой конфигурации. Эти действия приведут к тому, что новые сконфигурированные значения вступят в действие на следующем переполнении счетчика таймера. При этом поле LEDC_TIMERx_PARA_UP будет автоматически очищено аппаратурой.
14-разрядный счетчик. Каждый таймер содержит 14-битный счетчик базы времени, который использует ref_pulsex в качестве своей опорной частоты (см. выше рис. 30-2). Поле LEDC_TIMERx_DUTY_RES конфигурирует значение переполнения для этого 14-битного счетчика. Таким образом максимальная разрешающая способность сигнала PWM может быть 14 бит. Счетчик считает до значения 2^(LEDC_TIM ERx_DUTY_RES - 1), переполняется и снова начинает счет от 0. Значение счетчика может быть программно прочитано, сброшено, а также счетчик может быть программно приостановлен.
Счетчик может генерировать прерывание LEDC_TIMERx_OVF_INT (генерируется автоматически аппаратурой без конфигурирования) каждый раз при переполнении счетчика. Можно также сконфигурировать прерывание LEDC_OVF_CNT_CHn_INT после переполнения счетчика LEDC_OVF_NUM_CHn + 1 раз. Для конфигурирования прерывания LEDC_OVF_CNT_CHn_INT выполните следующее:
1. Сконфигурируйте LEDC_TIMER_SEL_CHn в качестве счетчика для генератора PWM. 2. Разрешите счетчик установкой LEDC_OVF_CNT_EN_CHn. 3. Установите LEDC_OVF_NUM_CHn в количество переполнений счетчика для генерации прерывания минус 1. 4. Разрешите прерывание переполнения установкой LEDC_OVF_CNT_CHn_INT_ENA. 5. Установите LEDC_TIMERx_DUTY_RES для разрешения таймера и ждите наступления прерывания LEDC_OVF_CNT_CHn_INT.
Как можно увидеть на рис. 30-2, частота сигнала на выходе генератора PWM (sig_outn) зависит от частоты источника тактов (LEDC_CLKx), значения делителя тактов (LEDC_CLK_DIV_TIMERx) и диапазона значений счетчика (LEDC_TIMERx_DUTY_RES):
Для изменения значения переполнения runtime, сначала установите поле LEDC_TIMERx_DUTY_RES, и затем установите поле LEDC_TIMERx_PARA_UP. Это приведет к тому, что новое значение вступит в силу на следующем переполнении счетчика. Если поле LEDC_OVF_CNT_EN_CHn было переконфигурировано, должно быть установлено LEDC_PARA_UP_CHn для применения новой конфигурации. Таким образом, эти значения конфигурации должны быть обновлены установкой LEDC_TIMERx_PARA_UP или LEDC_PARA_UP_CHn. LEDC_TIMERx_PARA_UP и LEDC_PARA_UP_CHn будут автоматически очищены аппаратурой.
[Генераторы PWM]
Для генерации сигнала PWM (PWMn) выбирается таймер (Timerx). Каждый генератор PWM может быть сконфигурирован отдельно от других путем установки LEDC_TIMER_SEL_CHn, чтобы использовать один из 4 таймеров для генерации PWM-сигнала на выходе.
Как показано на рис. 30-2, каждый генератор PWM имеет на борту компаратор и 2 мультиплексора. Генератор PWM сравнивает значение 14-битного счетчика таймера (Timerx_cnt) с двумя значениями порога Hpointn и Lpointn. Когда значение счетчика равно Hpointn или Lpointn, сигнал PWM становится в уровни лог. 1 и лог. 0 соответственно:
• Если Timerx_cnt == Hpointn, на выходе sig_outn появляется 1. • Если Timerx_cnt == Lpointn, на выходе sig_outn появляется 0.
Рис. 30-4 иллюстрирует, как Hpointn или Lpointn используются для генерации выходного сигнала PWM фиксированной скважности.
Рис. 30-4. Диаграмма выходного сигнала LED_PWM.
Для определенного генератора PWMn его Hpointn анализируется в поле LEDC_HPOINT_CHn каждый раз при переполнении счетчика. Подобным образом Lpointn также анализируется на каждом переполнении счетчика, и вычисляется из суммы полей LEDC_DUTY_CHn[18:4] и LEDC_HPOINT_CHn. Путем установки Hpointn и Lpointn в полях LEDC_HPOINT_CHn и LEDC_DUTY_CHn[18:4], может быть установлена относительная фаза и скважность выходного сигнала PWM.
Выходной сигнал PWM (sig_outn) разрешается установкой LEDC_SIG_OUT_EN_CHn. Когда очищен LEDC_SIG_OUT_EN_CHn, вывод сигнала PWM запрещен, и выходной сигнал (sig_outn) остается на постоянном уровне, указанном LEDC_IDLE_LV_CHn.
Биты LEDC_DUTY_CHn[3:0] используются для дизеринга (сглаживания) периодов скважности выходного сигнала PWM (sig_outn) путем периодического изменения скважности sig_outn. Когда LEDC_DUTY_CHn[3:0] установлены в ненулевое значение, то для каждых 16 периодов sig_outn значение LEDC_DUTY_CHn[3:0] этих периодов получат импульсы PWM на один тик таймера длиннее, чем другие (16-LEDC_DUTY_CHn[3:0]) импульсы. Например, если LEDC_DUTY_CHn[18:4] установлены в 10, и LEDC_DUTY_CHn[3:0] установлены в 5, то 5 из 16 периодов будут иметь импульсы PWM со значением скважности 11, и остальные 16 периодов будут иметь импульс PWM со скважностью 10. Средняя скважность после 16 периодов получится 10.3125.
Если переконфигурированы поля LEDC_TIMER_SEL_CHn, LEDC_HPOINT_CHn, LEDC_DUTY_CHn[18:4] и LEDC_SIG_OUT_EN_CHn, то нужно установить LEDC_PARA_UP_CHn для применения новой конфигурации. Это приведет к тому, что новые сконфигурированные значения вступят в силу на следующем прерывании счетчика. Поле LEDC_PARA_UP_CHn автоматически очищается аппаратурой.
[Duty Cycle Fading (фейдинг ШИМ)]
Аппаратная функция Duty Cycle Fading означает, что генераторы PWM могут делать фейдинг периода скважности выходного сигнала PWM (т. е. постепенно менять скважность сигнала от одного значения до другого). Если разрешена Duty Cycle Fading, то значение Lpointn будет инкрементироваться/декрементироваться после фиксированного количества переполнений счетчика. Рис. 30-5 показывает работу Duty Cycle Fading.
Рис. 30-5. Диаграмма выходного сигнала при фейдинге.
LEDC_DUTY_CHn используется для установки начального значения Lpointn. LEDC_DUTY_START_CHn разрешит (если 1) или запретит (если 0) фейдинг. LEDC_DUTY_CYCLE_CHn установит количество переполнений счетчика для каждого инкремента или декремента Lpointn. Другими словами, Lpointn будет инкрементироваться/декрементироваться после LEDC_DUTY_CYCLE_CHn переполнений счетчика. LEDC_DUTY_INC_CHn конфигурирует, будет Lpointn инкрементироваться (если 1) или декрементироваться (если 0). LEDC_DUTY_SCALE_CHn установит количество, на которое произойдет инкремент/декремент Lpointn. LEDC_DUTY_NUM_CHn установит максимальное количество инкрементов / декрементов до остановки фейдинга.
Если поля LEDC_DUTY_CHn, LEDC_DUTY_START_CHn, LEDC_DUTY_CYCLE_CHn, LEDC_DUTY_INC_CHn, LEDC_DUTY_SCALE_CHn и LEDC_DUTY_NUM_CHn были переконфигурированы, то нужно установить LEDC_PARA_UP_CHn, чтобы новая конфигурация вступила в силу. После того, как это поле было установлено, одновременно вступят в силу значения для фейдинга. Поле LEDC_PARA_UP_CHn автоматически очищается аппаратурой.
[Прерывания LEDC]
LEDC_OVF_CNT_CHn_INT: сработает, когда счетчик таймера переполнится (LEDC_OVF_NUM_CHn + 1) раз, и регистр LEDC_OVF_CNT_EN_CHn установлен в 1.
LEDC_DUTY_CHNG_END_CHn_INT: сработает, когда завершится фейдинг генератора PWM.
LEDC_TIMERx_OVF_INT: сработает, когда таймер PWM достигнет максимального значения счетчика (в момент его переполнения).
[Описание регистров LEDC]
Адреса в этой секции указаны относительно базового адреса LED PWM Controller, указанного в таблице 3-4 главы 3 "System and Memory" [1].
Имя
Описание
Адрес
Доступ(*)
Configuration Register (регистр конфигурации)
LEDC_CH0_CONF0_REG
Регистр конфигурации 0 канала 0
0x0000
*
LEDC_CH0_CONF1_REG
Регистр конфигурации 1 канала 0
0x000C
*
LEDC_CH1_CONF0_REG
Регистр конфигурации 0 канала 1
0x0014
*
LEDC_CH1_CONF1_REG
Регистр конфигурации 1 канала 1
0x0020
*
LEDC_CH2_CONF0_REG
Регистр конфигурации 0 канала 2
0x0028
*
LEDC_CH2_CONF1_REG
Регистр конфигурации 1 канала 2
0x0034
*
LEDC_CH3_CONF0_REG
Регистр конфигурации 0 канала 3
0x003C
*
LEDC_CH3_CONF1_REG
Регистр конфигурации 1 канала 3
0x0048
*
LEDC_CH4_CONF0_REG
Регистр конфигурации 0 канала 4
0x0050
*
LEDC_CH4_CONF1_REG
Регистр конфигурации 1 канала 4
0x005C
*
LEDC_CH5_CONF0_REG
Регистр конфигурации 0 канала 5
0x0064
*
LEDC_CH5_CONF1_REG
Регистр конфигурации 1 канала 5
0x0070
*
LEDC_CONF_REG
Регистр глобальной конфигурации LEDC
0x0030
R/W
Hpoint Register (регистр верхнего предела)
LEDC_CH0_HPOINT_REG
Регистр верхнего предела канала 0
0x0004
R/W
LEDC_CH1_HPOINT_REG
Регистр верхнего предела канала 1
0x0018
R/W
LEDC_CH2_HPOINT_REG
Регистр верхнего предела канала 2
0x002C
R/W
LEDC_CH3_HPOINT_REG
Регистр верхнего предела канала 3
0x0040
R/W
LEDC_CH4_HPOINT_REG
Регистр верхнего предела канала 4
0x0054
R/W
LEDC_CH5_HPOINT_REG
Регистр верхнего предела канала 5
0x0068
R/W
Duty Cycle Registers (регистры скважности периода ШИМ)
LEDC_CH0_DUTY_REG
Начальная скважность канала 0
0x0008
R/W
LEDC_CH0_DUTY_R_REG
Текущая скважность канала 0
0x0010
RO
LEDC_CH1_DUTY_REG
Начальная скважность канала 1
0x001C
R/W
LEDC_CH1_DUTY_R_REG
Текущая скважность канала 1
0x0024
RO
LEDC_CH2_DUTY_REG
Начальная скважность канала 2
0x0030
R/W
LEDC_CH2_DUTY_R_REG
Текущая скважность канала 2
0x0038
RO
LEDC_CH3_DUTY_REG
Начальная скважность канала 3
0x0044
R/W
LEDC_CH3_DUTY_R_REG
Текущая скважность канала 3
0x004C
RO
LEDC_CH4_DUTY_REG
Начальная скважность канала 4
0x0058
R/W
LEDC_CH4_DUTY_R_REG
Текущая скважность канала 4
0x0060
RO
LEDC_CH5_DUTY_REG
Начальная скважность канала 5
0x006C
R/W
LEDC_CH5_DUTY_R_REG
Текущая скважность канала 5
0x0074
RO
Timer Registers (регистры таймеров)
LEDC_TIMER0_CONF_REG
Конфигурация таймера 0
0x00A0
*
LEDC_TIMER0_VALUE_REG
Текущее значение счетчика таймера 0
0x00A4
RO
LEDC_TIMER1_CONF_REG
Конфигурация таймера 1
0x00A8
*
LEDC_TIMER1_VALUE_REG
Текущее значение счетчика таймера 1
0x00AC
RO
LEDC_TIMER2_CONF_REG
Конфигурация таймера 2
0x00B0
*
LEDC_TIMER2_VALUE_REG
Текущее значение счетчика таймера 2
0x00B4
RO
LEDC_TIMER3_CONF_REG
Конфигурация таймера 3
0x00B8
*
LEDC_TIMER3_VALUE_REG
Текущее значение счетчика таймера 3
0x00BC
RO
Interrupt Registers (регистры прерывания)
LEDC_INT_RAW_REG
Сырой статус прерываний
0x00C0
R/WTC/SS
LEDC_INT_ST_REG
Маскируемый статус прерываний
0x00C4
RO
LEDC_INT_ENA_REG
Биты разрешения прерываний
0x00C8
R/W
LEDC_INT_CLR_REG
Биты очистки прерываний
0x00CC
WT
Version Register (регистр версии)
LEDC_DATE_REG
Регистр управления версией
0x00FC
R/W
Примечание (*): * доступ может меняться в зависимости от поля регистра. R/W доступ и на чтение, и на запись. RO доступ только на чтение.
LEDC_TIMER_SEL_CHn Это поле используется для выбора одного из таймеров для канала n. 0: выбран Timer0, 1: выбран Timer1, 2: выбран Timer2, 3: выбран Timer3 (R/W).
LEDC_SIG_OUT_EN_CHn Установите этот бит, чтобы разрешить вывод сигнала на канале n (R/W).
LEDC_IDLE_LV_CHn Этот бит используется для управления выходным значением, когда канал n не активен (когда LEDC_SIG_OUT_EN_CHn = 0) (R/W).
LEDC_PARA_UP_CHn Этот бит используется для обновления перечисленных ниже полей канала n, после чего бит LEDC_PARA_UP_CHn будет автоматически очищен аппаратурой (WT).
LEDC_OVF_NUM_CHn Это поле используется для конфигурации максимального количества переполнений минус 1. Сработает прерывание LEDC_OVF_CNT_CHn_INT, когда канал n переполнится (LEDC_OVF_NUM_CHn + 1) раз (R/W).
LEDC_OVF_CNT_EN_CHn Этот бит используется подсчета количества переполнений счетчика таймера канала n (R/W).
LEDC_OVF_CNT_RESET_CHn Установите этот бит, чтобы сбросить переполнение счетчика таймера канала n (WT).
LEDC_DUTY_SCALE_CHn Это поле конфигурирует размер шага изменения скважности при фейдинге (R/W).
LEDC_DUTY_CYCLE_CHn Скважность будет меняться каждые LEDC_DUTY_CYCLE_CHn периодов канала n (R/W).
LEDC_DUTY_NUM_CHn Это поле управляет количеством изменений скважности фейдинга (R/W).
LEDC_DUTY_INC_CHn Этот бит определяет, будет ли скважность выходного сигнала канала n увеличиваться или уменьшаться. 1: увеличение скважности, 0: уменьшение скважности (R/W).
LEDC_DUTY_START_CHn Если этот бит установлен в 1, то другие сконфигурированные поля в LEDC_CHn_CONF1_REG вступят в силу на следующем переполнении таймера (R/W/SC).
LEDC_APB_CLK_SEL Это поле используется для выбора общего источника тактов для всех 4 таймеров. 1: APB_CLK, 2: FOSC_CLK, 3: XTAL_CLK (R/W).
LEDC_CLK_EN Этот бит используется для управления тактами. 1: такты применены постоянно. 0: такты предоставляются только когда приложение записывает в регистры (R/W).
LEDC_HPOINT_CHn Выходное значение меняется в лог. 1, когда счетчик выбранного таймера для этого канала достигнет значения, указанного в этом поле (R/W).
LEDC_DUTY_CHn Это поле используется для изменения выходной скважности путем управления Lpoint. Выходное значение меняется в лог. 0, когда счетчик выбранного таймера для этого канала достигнет Lpoint (R/W).
LEDC_TIMERx_DUTY_RES Это поле используется для управления диапазоном счетчика таймера x (R/W).
LEDC_CLK_DIV_TIMERx Это поле используется для конфигурирования делителя тактов таймера x. Младшие 8 битов представляют дробную часть коэффициента деления (R/W).
LEDC_TIMERx_PAUSE Этот бит используется для приостановки счетчика таймера x (R/W).
LEDC_TIMERx_RST Этот бит используется для сброса таймера x. После сброса счетчик покажет 0 (R/W).
LEDC_TIMERx_PARA_UP Установите этот бит для обновления LEDC_CLK_DIV_TIMERx и LEDC_TIMERx_DUTY_RES (WT).