13в. 16-канальный ШИМ PCA9685 по I2C: сервоприводы и светодиоды без таймеров микроконтроллера
В разделе 13а таймер TIM2 вёл четыре сервопривода, а пятому нужен уже второй таймер (13а.3). В 13б таймер играл ноты. Когда приводов или светодиодов десятки, а таймеры заняты, ШИМ выносят во внешнюю микросхему. PCA9685 — самая ходовая: 16 каналов по 12 бит, свой генератор и I2C, то есть два провода на все каналы. Здесь — что у неё внутри, как подключить её к F103 и разбудить, как задать частоту и почему генератор надо проверять, как перевести импульс привода в отсчёты, как сделать яркость светодиода ровной на глаз и как обновлять все 16 каналов разом.
Опоры: RM0008 (DocID13902 Rev 17): после сброса выводы — вход без
подтяжки, с. 160; I2C — до 100 кГц в стандартном режиме и до 400 кГц в
быстром, с. 752; приём одного байта ведущим, с. 764; I2C_CCR,
с. 783–784; I2C_TRISE, с. 784. DocID13587 Rev 17 (STM32F103x8/xB):
PA8 с допуском 5 В, с. 31; PB6 — I2C1_SCL, PB7 — I2C1_SDA, оба FT,
с. 32; FT — допуск 5 В, с. 33. Документа на PCA9685 в проекте нет:
регистры, биты, значения после включения, адреса, поведение SLEEP,
RESTART и ALLCALL взяты из документации производителя и заложены в
модель. Адреса регистров и биты MODE1 и MODE2 одинаковы в трёх
открытых драйверах на диске — Zephyr 4.4.2, rusEFI и Klipper, но это
не документ. Поэтому всё ниже проверяет согласие драйвера с моделью, а
не с микросхемой. Все числа — прогон драйвера _verify/pca13d/pca13d.c
на компьютере (gcc 12.2.0) со своей моделью PCA9685 как ведомого I2C на
Python 3.11; прошивка собрана armclang 6.24 под Cortex-M3.
Как это называется в документации
Оригинал Перевод LED controller драйвер светодиодов — так PCA9685 называет производитель prescaler ( PRE_SCALE)предделитель: делит генератор до частоты ШИМ auto-increment ( AI)автоинкремент: номер регистра растёт после каждого байта LEDn_ON,LEDn_OFFотсчёт, на котором канал n включается и выключается full ON / full OFF бит 12: канал всегда включён / всегда выключен totem pole / open-drain ( OUTDRV)двухтактный выход / открытый сток output invert ( INVRT)инверсия выходов ALL CALL address общий адрес: на него отвечают все PCA9685 на шине output enable ( OE)разрешение выходов, активен нулём sleep, restart сон — генератор выключен; перезапуск каналов после сна phase shift сдвиг фазы: импульсы каналов начинаются не в один момент
13в.1 Микросхема: 16 каналов, 12 бит, свой генератор
По документации производителя внутри PCA9685 — генератор на 25 МГц,
предделитель и один 12-битный счётчик на все каналы: он идёт от 0 до
4095 и начинает сначала. У каждого из 16 каналов два числа: ON —
на каком отсчёте выход включить, OFF — на каком выключить. Если OFF
меньше ON, импульс идёт через конец периода. Число 12-битное, а
тринадцатый бит (бит 4 старшего байта) — «всегда включён» в ON и
«всегда выключен» в OFF.
Отсюда главное отличие от таймера F103: частота одна на все 16
каналов, её задаёт PRE_SCALE. Приводам нужно 50 Гц, светодиодам —
сотни герц, чтобы не мигали. Приводы и светодиоды на одной микросхеме
будут на одной частоте; если это мешает — вторая микросхема с другим
адресом.
| Регистр | Номер | Что в нём |
|---|---|---|
MODE1 |
0x00 | RESTART (бит 7), AI (бит 5), SLEEP (бит 4), ALLCALL (бит 0) |
MODE2 |
0x01 | INVRT (бит 4), OCH (бит 3), OUTDRV (бит 2) |
LEDn_ON_L … LEDn_OFF_H |
0x06 + 4n | ON и OFF канала n, младший байт первым |
ALL_LED_ON_L … |
0xFA…0xFD | запись сразу во все 16 каналов |
PRE_SCALE |
0xFE | предделитель, от 3 до 255 |
После включения в модели — по документации производителя — MODE1 =
0x11: микросхема спит, общий адрес включён, автоинкремента нет.
MODE2 = 0x04 — двухтактные выходы. PRE_SCALE = 0x1E — это
196,89 Гц, у каждого канала OFF_H = 0x10 — «всегда выключен».
ALLCALLADR = 0xE0 — общий адрес 0x70, сдвинутый на бит.
13в.2 Подключение к F103 и инициализация
| Вывод PCA9685 | STM32F103 и прочее | Назначение |
|---|---|---|
| SCL | PB6 | такт I2C1 |
| SDA | PB7 | данные I2C1 |
| VDD, GND | 3,3 В и земля | питание логики |
| V+ | отдельный источник 5 В | плюс приводов, к логике не идёт |
| A5…A0 | GND | адрес 0x40 |
| OE | GND | выходы разрешены |
| LED15 | PA8 через перемычку | замер периода для калибровки (13в.3) |
PB6 и PB7 — выводы I2C1, оба FT, то есть терпят 5 В (DocID13587,
с. 32): плата, у которой подтяжки к 5 В, их не сожжёт. Но проще питать
логику PCA9685 от 3,3 В — тогда и выходы каналов 3,3 В. Приводы берут ток
рывками, и их питание V+ с логикой не смешивают: отдельный источник,
общая земля, конденсатор у разъёма — как в 13а.6.
Адрес по документации производителя — 0x40 плюс код на перемычках
A5…A0. В модели перемычки 000000 дали 0x40 (байт в линии 0x80, 17.2),
000001 — 0x41, 111111 — 0x7F; по чужому адресу pca_init вернула отказ
PCA_E_NACK. I2C1 — как в 15б.2: 400 кГц, CCR = F/S | 30,
TRISE = 11; больше F103 не умеет — до 400 кГц в быстром режиме
(RM0008, с. 752).
Инициализация — частота, режим выходов и выключенный общий адрес:
int pca_init(pca_t *d, uint8_t addr7, uint32_t freq_hz, uint8_t mode2)
{
int rc;
d->addr = addr7;
d->xfers = d->errors = 0;
if (d->osc_hz == 0u)
d->osc_hz = PCA_OSC_HZ;
if ((rc = pca_reg(d, PCA_MODE2, mode2)) != PCA_OK) /* заодно: отвечает ли кто-то по адресу */
return rc;
return pca_set_freq(d, freq_hz);
}
Частоту задаёт pca_set_freq, и порядок в ней обязательный (по
документации производителя): PRE_SCALE пишется только во сне, после
пробуждения генератору нужно 500 мкс, а если каналы работали до сна,
их перезапускает запись 1 в RESTART:
/* PRE_SCALE пишется только во сне; после пробуждения — 500 мкс генератору и RESTART, если он взведён */
int pca_set_freq(pca_t *d, uint32_t freq_hz)
{
uint8_t m, pre = pca_prescale(d->osc_hz, freq_hz);
int rc;
if ((rc = pca_get(d, PCA_MODE1, &m)) != PCA_OK)
return rc;
m &= (uint8_t)~(PCA_RESTART | PCA_SLEEP | PCA_ALLCALL); /* общий адрес 0x70 — выключить */
if ((rc = pca_reg(d, PCA_MODE1, m | PCA_AI | PCA_SLEEP)) != PCA_OK)
return rc;
if ((rc = pca_reg(d, PCA_PRE_SCALE, pre)) != PCA_OK)
return rc;
if ((rc = pca_reg(d, PCA_MODE1, m | PCA_AI)) != PCA_OK) /* проснуться */
return rc;
pca_port_delay_us(PCA_WAKE_US);
if ((rc = pca_get(d, PCA_MODE1, &m)) != PCA_OK)
return rc;
if (m & PCA_RESTART) /* каналы работали до сна: запустить их снова */
rc = pca_reg(d, PCA_MODE1, m);
if (rc == PCA_OK)
d->prescale = pre;
return rc;
}
В модели pca_init(&pca, 0x40, 50, PCA_OUTDRV) после включения — 6
обменов: 80 01 04 (MODE2), чтение MODE1, 80 00 30 (сон и
автоинкремент), 80 FE 79 (PRE_SCALE = 121), 80 00 20 (проснуться),
чтение MODE1. На шине 485 мкс, вместе с паузой — 985 мкс. После этого
MODE1 = 0x20, частота 50,029 Гц. Чтение одного байта на F103 идёт по
особому порядку (RM0008, с. 764): снять ACK до сброса ADDR, потом
STOP, потом ждать RXNE — так сделан pca_port_read в прошивке.
13в.3 Частота ШИМ: предделитель и генератор
Период — 4096 отсчётов, отсчёт — (PRE_SCALE + 1) тактов генератора.
Отсюда предделитель по документации производителя: PRE_SCALE =
round(osc / (4096 × f)) − 1, в пределах от 3 до 255.
/* PRE_SCALE = round(osc / (4096 × f)) − 1, в пределах 3…255 */
uint8_t pca_prescale(uint32_t osc_hz, uint32_t freq_hz)
{
uint64_t div = (uint64_t)PCA_STEPS * (freq_hz ? freq_hz : 1u);
uint64_t p = ((uint64_t)osc_hz + div / 2u) / div; /* с округлением */
if (p < PCA_PRE_MIN + 1u)
p = PCA_PRE_MIN + 1u;
if (p > PCA_PRE_MAX + 1u)
p = PCA_PRE_MAX + 1u;
return (uint8_t)(p - 1u);
}
Делитель целый, поэтому частота выходит не та, что просили. В модели при 25 МГц:
| Просили | PRE_SCALE |
Вышло | Ошибка | Без «− 1» |
|---|---|---|---|---|
| 24 Гц | 253 | 24,030 Гц | +0,123 % | 23,935 Гц |
| 50 Гц | 121 | 50,029 Гц | +0,058 % | 49,622 Гц |
| 200 Гц | 30 | 196,888 Гц | −1,556 % | 190,735 Гц |
| 1000 Гц | 5 | 1017,253 Гц | +1,725 % | 871,931 Гц |
| 1526 Гц | 3 | 1525,879 Гц | −0,008 % | 1220,703 Гц |
Пределы — 23,842 Гц при 255 и 1525,879 Гц при 3: просьба о 10 Гц дала
255, о 2000 Гц — 3. На высоких частотах шаг делителя грубый: 1000 Гц
не получить точнее 1,7 %. Для привода это неважно — ему нужна ширина
импульса, а не частота (13а.1), — но ширину драйвер считает по
фактическому PRE_SCALE, а не по заказанной частоте.
Генератор. Внутренний генератор работает без кварца, и насколько его частота отличается от 25 МГц у конкретной микросхемы, при какой температуре и питании, — здесь не проверено: документа нет. Модель берёт отклонение 3 % в обе стороны (допущение). Ошибка генератора входит в ширину импульса один к одному: драйвер считает отсчёты для 25 МГц, а они короче или длиннее.
Лечится замером. Выход LED15 с заполнением 50 % заведён на PA8, и прошивка один раз меряет восемь периодов счётчиком тактов DWT. PA8 после сброса — вход без подтяжки (RM0008, с. 160) и терпит 5 В (DocID13587, с. 31):
/* период выхода LED15 в наносекундах: восемь периодов по счётчику тактов DWT */
static uint32_t period_ns(void)
{
uint32_t a, b = 0;
if (!edge(&a))
return 0;
for (int i = 0; i < 8; i++)
if (!edge(&b))
return 0;
return (uint32_t)((uint64_t)(b - a) * 1000u / (72u * 8u));
}
Из периода — настоящая частота генератора, и PRE_SCALE заново:
/* по измеренному периоду выхода: osc = 4096 × (PRE_SCALE + 1) / T */
uint32_t pca_calibrate(pca_t *d, uint32_t period_ns)
{
uint64_t n = (uint64_t)PCA_STEPS * (d->prescale + 1u) * 1000000000u;
if (period_ns)
d->osc_hz = (uint32_t)((n + period_ns / 2u) / period_ns);
return d->osc_hz;
}
| Генератор в модели | До калибровки: частота | 1500 мкс стали | Угол | Период | После: PRE_SCALE |
Частота | Импульс | Угол |
|---|---|---|---|---|---|---|---|---|
| 25,75 МГц (+3 %) | 51,530 Гц | 1454,5 мкс | 81,8° | 19 406 291 нс | 125 | 49,894 Гц | 1502,2 мкс | 90,4° |
| 24,25 МГц (−3 %) | 48,528 Гц | 1544,5 мкс | 98,0° | 20 606 680 нс | 117 | 50,173 Гц | 1498,7 мкс | 89,8° |
Угол — по модели привода из 13а.1: 1000 мкс — 0°, 2000 мкс — 180°. До калибровки привод промахивается на 8°, после — меньше чем на полградуса; частоту генератора замер дал до герца: 25 750 000 и 24 250 000 Гц. Остаток — шаг делителя и шаг отсчёта, а не генератор.
13в.4 Сервоприводы: импульс в отсчётах и разнесение фаз
При 50 Гц и PRE_SCALE = 121 отсчёт — 122 / 25 МГц = 4,88 мкс. Драйвер
переводит микросекунды в отсчёты с округлением, по той частоте
генератора, которой верит:
/* микросекунды → отсчёты при текущих PRE_SCALE и частоте генератора, с округлением */
uint16_t pca_us_ticks(const pca_t *d, uint32_t us)
{
uint64_t div = 1000000ull * (d->prescale + 1u);
uint64_t t = ((uint64_t)us * d->osc_hz + div / 2u) / div;
return (uint16_t)(t > PCA_STEPS - 1u ? PCA_STEPS - 1u : t);
}
| Импульс | 500 мкс | 1000 мкс | 1500 мкс | 2000 мкс | 2500 мкс |
|---|---|---|---|---|---|
| Отсчётов | 102 | 205 | 307 | 410 | 512 |
| На выходе в модели | 497,76 мкс | 1000,4 мкс | 1498,16 мкс | 2000,8 мкс | 2498,56 мкс |
На ход 1000…2000 мкс приходится 205 отсчётов — 0,878° на отсчёт, на широкий ход 500…2500 мкс — 410 отсчётов, 0,439°. У TIM2 в 13а.2 шаг был 1 мкс, 0,18°: PCA9685 грубее впятеро, но мёртвая зона модели привода — 1° (13а.1), и шага 0,878° ей хватает.
Разнесение фаз. Если у всех каналов ON = 0, все 16 выходов
включаются на одном отсчёте. Приводу всё равно, где начинается импульс,
— важна ширина. Поэтому драйвер сдвигает начало на 256 отсчётов на
канал, и фронты расходятся по периоду:
/* заполнение 0…4096 → ON и OFF; spread — сдвиг начала на 256 отсчётов на канал */
void pca_duty(uint32_t ch, uint32_t duty, int spread, uint16_t *on, uint16_t *off)
{
if (duty == 0u) {
*on = 0;
*off = PCA_FULL; /* всегда выключен */
} else if (duty >= PCA_STEPS) {
*on = PCA_FULL; /* всегда включён */
*off = 0;
} else {
*on = (uint16_t)(spread ? (ch % PCA_CHANNELS) * (PCA_STEPS / PCA_CHANNELS) : 0u);
*off = (uint16_t)((*on + duty) % PCA_STEPS); /* OFF < ON — импульс через конец периода */
}
}
Канал 3 при 1500 мкс — ON = 768, OFF = 1075; канал 15 при 2000 мкс
— ON = 3840, OFF = 154, импульс через конец периода, и в модели он
всё равно 2000,8 мкс. Что даёт сдвиг, модель считает по форме всех 16
выходов; ток — допущение: 20 мА на выход, пока он включён, как у
светодиода. Сколько берёт сигнальный вход привода, не проверено.
| 16 каналов | Без сдвига: включено разом | фронтов на одном отсчёте | пик тока | Со сдвигом: включено разом | фронтов | пик тока | Средний ток |
|---|---|---|---|---|---|---|---|
| привод, 1500 мкс | 16 | 16 | 320 мА | 2 | 1 | 40 мА | 24 мА |
| заполнение 25 % | 16 | 16 | 320 мА | 4 | 2 | 80 мА | 80 мА |
| заполнение 50 % | 16 | 16 | 320 мА | 8 | 2 | 160 мА | 160 мА |
Средний ток один и тот же, а пик со сдвигом меньше в 2–8 раз, и вместо
16 фронтов разом — один-два. Для приводов главный ток — двигатели на
V+, их рывки сдвиг не убирает: тут помогают отдельный источник и пуск
по очереди (13а.6).
13в.5 Светодиоды: яркость, гамма, полное вкл/выкл, выходы
Яркость — заполнение от 0 до 4096. Глаз видит яркость не линейно: половина заполнения кажется много ярче половины. Поэтому уровень пересчитывают по гамме — здесь 2,2, это допущение о восприятии, а не данные документа. В драйвере таблица на 17 точек и линейная вставка между ними:
/* уровень 0…1024 → заполнение 0…4096 по гамме 2,2: таблица и линейная вставка между точками */
uint16_t pca_gamma(uint32_t level)
{
if (level >= 1024u)
return PCA_STEPS;
uint32_t i = level >> 6, f = level & 63u;
uint32_t a = gamma22[i], b = gamma22[i + 1u];
return (uint16_t)(a + ((b - a) * f + 32u) / 64u);
}
| Уровень | 0 | 16 | 32 | 64 | 128 | 256 | 512 | 768 | 1000 | 1024 |
|---|---|---|---|---|---|---|---|---|---|---|
| Заполнение | 0 | 2 | 5 | 9 | 42 | 194 | 891 | 2175 | 3893 | 4096 |
От точной кривой 4096 × (уровень / 1024)^2,2 вставка отходит не больше чем на 5,8 отсчёта. Первый светящийся уровень — 4-й; из 1025 уровней различных заполнений 936. Вот где нужны 12 бит: если то же заполнение округлить до 8 бит, первые 53 уровня — полная темнота, свет появляется только с 54-го.
Полное вкл и выкл. Обычным импульсом 100 % не получить: ON = 0,
OFF = 4095 — выход включён 0,999756 периода, на один отсчёт меньше.
Поэтому pca_duty для 4096 ставит бит 12 в ON («всегда включён»), а
для 0 — бит 12 в OFF. Если стоят оба, по документации производителя
главнее «выключен» — в модели выход 0.
Двухтактный выход или открытый сток. OUTDRV в MODE2: 1 —
выход сам даёт и 0, и 1, 0 — открытый сток: он только тянет к земле, а
вместо единицы отпускает вывод. INVRT переворачивает выход. Светодиод
бывает подключён от вывода на землю (горит при 1) или от плюса к выводу
(горит при 0). В модели при заполнении 25 %:
MODE2 |
Выход | Светодиод на землю | Светодиод от плюса |
|---|---|---|---|
| 0x04 | двухтактный | 0,25 | 0,75 |
| 0x14 | двухтактный, INVRT |
0,75 | 0,25 |
| 0x00 | открытый сток | 0 | 0,75 |
| 0x10 | открытый сток, INVRT |
0 | 0,25 |
Открытый сток светодиод на землю не зажжёт вовсе. Светодиод от плюса —
это «наоборот»: без INVRT 25 % дают 75 % света. Его включают с
INVRT — или считают заполнение как 4096 − яркость. Ток выхода и
резистор — по документации производителя на микросхему и светодиод,
здесь не считались.
13в.6 Все 16 каналов одной транзакцией
С автоинкрементом номер регистра растёт после каждого байта, и 16 каналов — это одна запись: номер 0x06 и 64 байта.
/* все 16 каналов одной транзакцией: 1 + 64 байта, выходы меняются вместе по STOP */
int pca_write_all(pca_t *d, const uint16_t on[16], const uint16_t off[16])
{
uint8_t b[1 + 4 * PCA_CHANNELS];
b[0] = PCA_LED0_ON_L;
for (uint32_t i = 0; i < PCA_CHANNELS; i++) {
b[1 + 4 * i] = (uint8_t)on[i];
b[2 + 4 * i] = (uint8_t)(on[i] >> 8);
b[3 + 4 * i] = (uint8_t)off[i];
b[4 + 4 * i] = (uint8_t)(off[i] >> 8);
}
return xfer_done(d, pca_port_write(d->addr, b, sizeof b));
}
По документации производителя выходы берут новые значения по STOP
(или по ACK каждого байта, если OCH = 1). Значит, одна транзакция —
все 16 каналов меняются разом. Время на шине в модели:
| Запись | Тактов SCL | 100 кГц | 400 кГц | Доля кадра 20 мс, 100 / 400 кГц |
|---|---|---|---|---|
| 16 каналов одной транзакцией | 596 | 5960 мкс | 1490 мкс | 29,8 % / 7,45 % |
| 16 каналов по одному | 16 × 56 | 8960 мкс | 2240 мкс | 44,8 % / 11,2 % |
| один канал | 56 | 560 мкс | 140 мкс | |
ALL_LED — все разом одним значением |
56 | 560 мкс | 140 мкс | |
| чтение одного регистра | 39 | 390 мкс | 97,5 мкс |
Синхронность. Каналы, записанные по одному, получают новые значения
в разные моменты, и часть из них — уже в следующем периоде. В модели
новое значение действует со следующего периода после STOP
(допущение); 400 кадров со случайной фазой счётчика:
| Как писали | 100 кГц | 400 кГц |
|---|---|---|
| одной транзакцией | 0 из 400 | 0 из 400 |
| 16 транзакциями | 159 из 400 (39,8 %) | 48 из 400 (12 %) |
В двух кадрах из пяти на 100 кГц часть приводов сдвинулась на период позже остальных. Одна транзакция этого не допускает.
Плавное движение — как в 13а.4, только шаг делает не прерывание таймера, а кадр раз в 20 мс: прошивка считает 16 импульсов и пишет их одной транзакцией. Ход 1000 → 2000 мкс по 20 мкс за кадр — 50 кадров, 1 с; отсчёты идут от 209 до 410 шагами по 4–5 (20 мкс — это 4,1 отсчёта). На 400 кГц кадр занимает шину на 1490 мкс — 7,45 % времени, и на той же шине остаётся место для датчиков.
13в.7 Грабли
PRE_SCALE «не записался». Записали его, не усыпив микросхему, —
по документации производителя запись пропадает. В модели PRE_SCALE
остался 30 (0x1E, после включения), период — 5079 мкс вместо 20 мс, а
драйвер, уверенный в 121, дал 307 отсчётов — импульс 380,7 мкс вместо
1500. Привод упирается в край. Только pca_set_freq: сон, PRE_SCALE,
пробуждение.
Записали канал — выход молчит. Нет AI: после включения
автоинкремент выключен, и все четыре байта ложатся в один регистр
LED0_ON_L. В модели после записи 1500 мкс регистры канала —
01 00 00 10: бит «всегда выключен» на месте, импульсов за 100 мс — 0.
pca_set_freq ставит AI в MODE1.
Чужое устройство на 0x70 переписывает PCA9685. После включения
ALLCALL = 1, и микросхема отвечает на 0x70. В модели запись двух байт
00 01 устройству с адресом 0x70 сменила MODE1 у PCA9685 с 0x11 на
0x01 — она проснулась. После pca_init (ALLCALL снят) та же запись
MODE1 = 0x20 не тронула. Два ответа на один адрес — ещё и спор на
линии при чтении.
После сна каналы стоят. Уснули при работающих каналах — взводится
RESTART. В модели привод выдавал 5 импульсов за 100 мс; после сна
MODE1 = 0xB0, после пробуждения — 0xA0 и 0 импульсов. Запись 1 в
RESTART из pca_set_freq вернула 0x20 и 5 импульсов. Запись 0 в
RESTART ничего не меняет — его снимает только единица, и только
через 500 мкс после пробуждения.
Забыли «− 1». PRE_SCALE = 122 вместо 121 — 49,622 Гц, а импульс,
посчитанный для 121, вышел 1510,4 мкс вместо 1500. Мелочь для привода,
но на 1000 Гц то же «− 1» даёт 871,931 Гц вместо 1017,253 (13в.3).
Контроллер сбрасывается, когда едут приводы. V+ взят от тех же
5 В или 3,3 В, что логика. Отдельный источник для V+, общая земля,
конденсатор у разъёма (13а.6).
5 В и подтяжки. Плата PCA9685 от 5 В с подтяжками к 5 В: PB6 и PB7 — FT (с. 32), PA8 — тоже (с. 31), а PA0…PA3 — нет (13а.6), выход канала на них заводить нельзя. Проще всего — логика от 3,3 В.
Светодиод горит наоборот. Подключён от плюса к выводу, а INVRT
нет: 25 % дают 75 % света (13в.5).
13в.8 Итоги
- PCA9685: 16 каналов по 12 бит, генератор 25 МГц, одна частота на всех —
PRE_SCALE= round(osc / (4096 × f)) − 1, от 3 до 255: от 23,842 до 1525,879 Гц; 50 Гц — 121, 50,029 Гц. - F103: I2C1 на PB6 и PB7 (FT), 400 кГц; адрес 0x40 плюс перемычки A5…A0; инициализация — 6 обменов, 985 мкс.
PRE_SCALE— только во сне; после пробуждения 500 мкс иRESTART;AI— для записи нескольких байт;ALLCALLснять.- Привод на 50 Гц: отсчёт 4,88 мкс, 1500 мкс — 307 отсчётов, 0,878° на
отсчёт; сдвиг
ONна 256 — пик тока 40 мА вместо 320 мА в модели. - Генератор на 3 % в сторону — привод мимо на 8°; замер периода по
LED15 и
pca_calibrate— меньше полградуса. - Светодиоды: гамма 2,2 таблицей на 17 точек, 936 различимых заполнений; 4096 и 0 — битом 12; открытый сток не зажжёт светодиод на землю.
- 16 каналов одной транзакцией — 1490 мкс на 400 кГц и 5960 мкс на
100 кГц, все меняются по одному
STOP; по одному — 2240 мкс и рассинхрон в 12 % кадров.
Полные исходники
pca13d.h — регистры, биты MODE1 и MODE2, порт и функции драйвера.
/* pca13d.h — раздел 13в: драйвер PCA9685 (16 каналов ШИМ по I2C) без регистров микроконтроллера.
* Драйвер говорит с микросхемой только через три функции порта (pca_port_*): в прошивке fw13d.c их
* делает I2C1 STM32F103, в стенде host13d.c — модель model13d.py.
* Карта регистров и биты — по документации производителя; документа в проекте нет, адреса регистров
* и биты совпадают с открытыми драйверами Zephyr, rusEFI и Klipper; с микросхемой не сверено. */
#ifndef PCA13D_H
#define PCA13D_H
#include <stdint.h>
/* ── регистры ─────────────────────────────────────────────────────────── */
#define PCA_MODE1 0x00u
#define PCA_MODE2 0x01u
#define PCA_LED0_ON_L 0x06u /* канал n: 0x06 + 4n — ON_L, ON_H, OFF_L, OFF_H */
#define PCA_ALL_LED_ON_L 0xFAu /* запись сразу во все 16 каналов */
#define PCA_PRE_SCALE 0xFEu /* пишется только при SLEEP = 1 */
/* ── MODE1 ────────────────────────────────────────────────────────────── */
#define PCA_RESTART 0x80u /* 1 — каналы остановлены сном; запись 1 перезапускает */
#define PCA_AI 0x20u /* автоинкремент номера регистра */
#define PCA_SLEEP 0x10u /* генератор выключен */
#define PCA_ALLCALL 0x01u /* отвечать и на общий адрес 0x70 */
/* ── MODE2 ────────────────────────────────────────────────────────────── */
#define PCA_INVRT 0x10u /* инверсия выходов */
#define PCA_OCH 0x08u /* 0 — выходы меняются по STOP, 1 — по ACK */
#define PCA_OUTDRV 0x04u /* 1 — двухтактный выход, 0 — открытый сток */
#define PCA_FULL 0x1000u /* бит 12 в ON или OFF: канал всегда включён или всегда выключен */
#define PCA_STEPS 4096u /* 12 бит: отсчётов на период */
#define PCA_CHANNELS 16u
#define PCA_OSC_HZ 25000000u /* внутренний генератор */
#define PCA_ADDR_BASE 0x40u /* A5…A0 на GND */
#define PCA_ADDR_ALLCALL 0x70u
#define PCA_PRE_MIN 3u
#define PCA_PRE_MAX 255u
#define PCA_WAKE_US 500u /* генератору после SLEEP = 0 */
enum { PCA_OK = 0, PCA_E_NACK = -1, PCA_E_BUS = -2 };
typedef struct {
uint8_t addr; /* семибитный адрес: 0x40 + перемычки */
uint8_t prescale; /* что драйвер записал в PRE_SCALE */
uint32_t osc_hz; /* частота генератора, которой верит драйвер: 25 МГц или после калибровки */
uint32_t xfers, errors; /* обменов по I2C и ошибок */
} pca_t;
/* ── порт: в прошивке — I2C1, в стенде — строки к модели ──────────────── */
/* записать n байт одной транзакцией: START, адрес, байты, STOP; 0, PCA_E_NACK или PCA_E_BUS */
int pca_port_write(uint8_t addr7, const uint8_t *tx, uint32_t n);
/* прочитать один байт регистра reg: запись номера, повторный старт, чтение */
int pca_port_read(uint8_t addr7, uint8_t reg, uint8_t *v);
void pca_port_delay_us(uint32_t us);
/* ── драйвер ──────────────────────────────────────────────────────────── */
uint8_t pca_prescale(uint32_t osc_hz, uint32_t freq_hz);
uint32_t pca_freq_mhz(uint32_t osc_hz, uint8_t prescale);
int pca_reg(pca_t *d, uint8_t reg, uint8_t v);
int pca_get(pca_t *d, uint8_t reg, uint8_t *v);
int pca_init(pca_t *d, uint8_t addr7, uint32_t freq_hz, uint8_t mode2);
int pca_set_freq(pca_t *d, uint32_t freq_hz);
uint32_t pca_calibrate(pca_t *d, uint32_t period_ns);
uint16_t pca_us_ticks(const pca_t *d, uint32_t us);
void pca_duty(uint32_t ch, uint32_t duty, int spread, uint16_t *on, uint16_t *off);
void pca_servo(const pca_t *d, uint32_t ch, uint32_t us, int spread, uint16_t *on, uint16_t *off);
uint16_t pca_gamma(uint32_t level);
int pca_channel(pca_t *d, uint32_t ch, uint16_t on, uint16_t off);
int pca_write_all(pca_t *d, const uint16_t on[16], const uint16_t off[16]);
int pca_all_off(pca_t *d);
#endif
pca13d.c — драйвер: частота, калибровка, отсчёты, фазы, гамма, запись всех каналов.
/* pca13d.c — раздел 13в: драйвер PCA9685 по I2C. Один и тот же файл собирается в прошивку (armclang,
* Cortex-M3) и в стенд на компьютере (gcc): микроконтроллера он не знает, только порт pca_port_*. */
#include "pca13d.h"
/* 4096 × (i/16)^2,2 — гамма 2,2 по 17 точкам */
static const uint16_t gamma22[17] = {0, 9, 42, 103, 194, 317, 473, 665, 891, 1155, 1456, 1796, 2175, 2594, 3053, 3554, 4096};
/* PRE_SCALE = round(osc / (4096 × f)) − 1, в пределах 3…255 */
uint8_t pca_prescale(uint32_t osc_hz, uint32_t freq_hz)
{
uint64_t div = (uint64_t)PCA_STEPS * (freq_hz ? freq_hz : 1u);
uint64_t p = ((uint64_t)osc_hz + div / 2u) / div; /* с округлением */
if (p < PCA_PRE_MIN + 1u)
p = PCA_PRE_MIN + 1u;
if (p > PCA_PRE_MAX + 1u)
p = PCA_PRE_MAX + 1u;
return (uint8_t)(p - 1u);
}
/* фактическая частота в миллигерцах: osc / (4096 × (PRE_SCALE + 1)) */
uint32_t pca_freq_mhz(uint32_t osc_hz, uint8_t prescale)
{
uint64_t div = (uint64_t)PCA_STEPS * (prescale + 1u);
return (uint32_t)(((uint64_t)osc_hz * 1000u + div / 2u) / div);
}
static int xfer_done(pca_t *d, int rc)
{
d->xfers++;
if (rc)
d->errors++;
return rc;
}
int pca_reg(pca_t *d, uint8_t reg, uint8_t v)
{
uint8_t b[2] = {reg, v};
return xfer_done(d, pca_port_write(d->addr, b, 2));
}
int pca_get(pca_t *d, uint8_t reg, uint8_t *v)
{
return xfer_done(d, pca_port_read(d->addr, reg, v));
}
/* PRE_SCALE пишется только во сне; после пробуждения — 500 мкс генератору и RESTART, если он взведён */
int pca_set_freq(pca_t *d, uint32_t freq_hz)
{
uint8_t m, pre = pca_prescale(d->osc_hz, freq_hz);
int rc;
if ((rc = pca_get(d, PCA_MODE1, &m)) != PCA_OK)
return rc;
m &= (uint8_t)~(PCA_RESTART | PCA_SLEEP | PCA_ALLCALL); /* общий адрес 0x70 — выключить */
if ((rc = pca_reg(d, PCA_MODE1, m | PCA_AI | PCA_SLEEP)) != PCA_OK)
return rc;
if ((rc = pca_reg(d, PCA_PRE_SCALE, pre)) != PCA_OK)
return rc;
if ((rc = pca_reg(d, PCA_MODE1, m | PCA_AI)) != PCA_OK) /* проснуться */
return rc;
pca_port_delay_us(PCA_WAKE_US);
if ((rc = pca_get(d, PCA_MODE1, &m)) != PCA_OK)
return rc;
if (m & PCA_RESTART) /* каналы работали до сна: запустить их снова */
rc = pca_reg(d, PCA_MODE1, m);
if (rc == PCA_OK)
d->prescale = pre;
return rc;
}
int pca_init(pca_t *d, uint8_t addr7, uint32_t freq_hz, uint8_t mode2)
{
int rc;
d->addr = addr7;
d->xfers = d->errors = 0;
if (d->osc_hz == 0u)
d->osc_hz = PCA_OSC_HZ;
if ((rc = pca_reg(d, PCA_MODE2, mode2)) != PCA_OK) /* заодно: отвечает ли кто-то по адресу */
return rc;
return pca_set_freq(d, freq_hz);
}
/* по измеренному периоду выхода: osc = 4096 × (PRE_SCALE + 1) / T */
uint32_t pca_calibrate(pca_t *d, uint32_t period_ns)
{
uint64_t n = (uint64_t)PCA_STEPS * (d->prescale + 1u) * 1000000000u;
if (period_ns)
d->osc_hz = (uint32_t)((n + period_ns / 2u) / period_ns);
return d->osc_hz;
}
/* микросекунды → отсчёты при текущих PRE_SCALE и частоте генератора, с округлением */
uint16_t pca_us_ticks(const pca_t *d, uint32_t us)
{
uint64_t div = 1000000ull * (d->prescale + 1u);
uint64_t t = ((uint64_t)us * d->osc_hz + div / 2u) / div;
return (uint16_t)(t > PCA_STEPS - 1u ? PCA_STEPS - 1u : t);
}
/* заполнение 0…4096 → ON и OFF; spread — сдвиг начала на 256 отсчётов на канал */
void pca_duty(uint32_t ch, uint32_t duty, int spread, uint16_t *on, uint16_t *off)
{
if (duty == 0u) {
*on = 0;
*off = PCA_FULL; /* всегда выключен */
} else if (duty >= PCA_STEPS) {
*on = PCA_FULL; /* всегда включён */
*off = 0;
} else {
*on = (uint16_t)(spread ? (ch % PCA_CHANNELS) * (PCA_STEPS / PCA_CHANNELS) : 0u);
*off = (uint16_t)((*on + duty) % PCA_STEPS); /* OFF < ON — импульс через конец периода */
}
}
void pca_servo(const pca_t *d, uint32_t ch, uint32_t us, int spread, uint16_t *on, uint16_t *off)
{
pca_duty(ch, pca_us_ticks(d, us), spread, on, off);
}
/* уровень 0…1024 → заполнение 0…4096 по гамме 2,2: таблица и линейная вставка между точками */
uint16_t pca_gamma(uint32_t level)
{
if (level >= 1024u)
return PCA_STEPS;
uint32_t i = level >> 6, f = level & 63u;
uint32_t a = gamma22[i], b = gamma22[i + 1u];
return (uint16_t)(a + ((b - a) * f + 32u) / 64u);
}
/* один канал: номер регистра и четыре байта, младший первым; нужен автоинкремент (AI) */
int pca_channel(pca_t *d, uint32_t ch, uint16_t on, uint16_t off)
{
uint8_t b[5] = {(uint8_t)(PCA_LED0_ON_L + 4u * (ch % PCA_CHANNELS)), (uint8_t)on, (uint8_t)(on >> 8),
(uint8_t)off, (uint8_t)(off >> 8)};
return xfer_done(d, pca_port_write(d->addr, b, 5));
}
/* все 16 каналов одной транзакцией: 1 + 64 байта, выходы меняются вместе по STOP */
int pca_write_all(pca_t *d, const uint16_t on[16], const uint16_t off[16])
{
uint8_t b[1 + 4 * PCA_CHANNELS];
b[0] = PCA_LED0_ON_L;
for (uint32_t i = 0; i < PCA_CHANNELS; i++) {
b[1 + 4 * i] = (uint8_t)on[i];
b[2 + 4 * i] = (uint8_t)(on[i] >> 8);
b[3 + 4 * i] = (uint8_t)off[i];
b[4 + 4 * i] = (uint8_t)(off[i] >> 8);
}
return xfer_done(d, pca_port_write(d->addr, b, sizeof b));
}
int pca_all_off(pca_t *d)
{
uint8_t b[5] = {PCA_ALL_LED_ON_L, 0, 0, 0, PCA_FULL >> 8};
return xfer_done(d, pca_port_write(d->addr, b, 5));
}
fw13d.c — прошивка STM32F103: I2C1 на 400 кГц, замер периода на PA8, 16 приводов кадрами по 20 мс.
/* fw13d.c — раздел 13в: PCA9685 на STM32F103 (BluePill), 72 МГц, APB1 = 36 МГц.
* I2C1: PB6 — SCL, PB7 — SDA (открытый сток, 400 кГц). Перемычки A5…A0 на GND — адрес 0x40, OE на GND.
* Выход LED15 перемычкой на PA8 (вход, допуск 5 В): по нему один раз меряется период и калибруется частота
* генератора. Потом 16 приводов раз в 20 мс ходят 1000 ↔ 2000 мкс по 20 мкс за кадр, кадр — одна транзакция.
* Тактирование до 72 МГц — как в разделе 6. */
#include "stm32f10x.h"
#include "pca13d.h"
#define CPU_HZ 72000000u
#define APB1_MHZ 36u
#define I2C_TIMEOUT_US 1000u /* 65 байт на 400 кГц — 1490 мкс, но ждём каждый флаг отдельно */
#define FRAME_US 20000u
static pca_t pca;
volatile uint32_t bus_errors, period_ns_meas;
static int expired(uint32_t t0, uint32_t us)
{
return DWT->CYCCNT - t0 >= us * (CPU_HZ / 1000000u);
}
void pca_port_delay_us(uint32_t us)
{
uint32_t t0 = DWT->CYCCNT;
while (!expired(t0, us)) {
}
}
static void i2c1_init(void)
{
RCC->APB2ENR |= RCC_APB2ENR_IOPAEN | RCC_APB2ENR_IOPBEN | RCC_APB2ENR_AFIOEN;
RCC->APB1ENR |= RCC_APB1ENR_I2C1EN;
/* PB6, PB7 — альтернативная функция, открытый сток, 50 МГц (1111); PA8 — вход без подтяжки (0100, как после сброса) */
GPIOB->CRL = (GPIOB->CRL & 0x00FFFFFFu) | 0xFF000000u;
GPIOA->CRH = (GPIOA->CRH & ~0xFu) | 0x4u;
I2C1->CR1 = 0; /* настраивать при PE = 0 */
I2C1->CR2 = APB1_MHZ;
I2C1->CCR = I2C_CCR_FS | 30u; /* DUTY = 0: 36 МГц / (3 × 30) = 400 кГц */
I2C1->TRISE = APB1_MHZ * 300u / 1000u + 1u; /* 300 нс × 36 МГц = 10,8 → 10 + 1 = 11 */
I2C1->CR1 = I2C_CR1_PE;
}
static int sr1_wait(uint16_t mask)
{
uint32_t t0 = DWT->CYCCNT;
while (!(I2C1->SR1 & mask)) {
if (I2C1->SR1 & I2C_SR1_AF)
return PCA_E_NACK; /* адрес или байт не подтверждён */
if (expired(t0, I2C_TIMEOUT_US))
return PCA_E_BUS;
}
return PCA_OK;
}
static int fail(int rc)
{
I2C1->CR1 |= I2C_CR1_STOP;
I2C1->SR1 = (uint16_t)~I2C_SR1_AF; /* AF снимается записью нуля */
return rc;
}
/* START и байт адреса; ADDR не снят — его снимает вызывающий чтением SR2 */
static int start(uint8_t addr_byte)
{
int rc;
uint32_t t0 = DWT->CYCCNT;
while (I2C1->SR2 & I2C_SR2_BUSY) { /* SDA держит ведомый — раздел 17.6 */
if (expired(t0, I2C_TIMEOUT_US))
return PCA_E_BUS;
}
I2C1->CR1 |= I2C_CR1_START;
if ((rc = sr1_wait(I2C_SR1_SB)) != PCA_OK)
return rc;
I2C1->DR = addr_byte;
return sr1_wait(I2C_SR1_ADDR);
}
int pca_port_write(uint8_t addr7, const uint8_t *tx, uint32_t n)
{
int rc;
if ((rc = start((uint8_t)(addr7 << 1))) != PCA_OK)
return fail(rc);
(void)I2C1->SR2;
for (uint32_t i = 0; i < n; i++) {
if ((rc = sr1_wait(I2C_SR1_TXE)) != PCA_OK)
return fail(rc);
I2C1->DR = tx[i];
}
if ((rc = sr1_wait(I2C_SR1_BTF)) != PCA_OK)
return fail(rc);
I2C1->CR1 |= I2C_CR1_STOP; /* по STOP выходы PCA9685 берут новые значения */
return PCA_OK;
}
int pca_port_read(uint8_t addr7, uint8_t reg, uint8_t *v)
{
int rc;
if ((rc = start((uint8_t)(addr7 << 1))) != PCA_OK)
return fail(rc);
(void)I2C1->SR2;
if ((rc = sr1_wait(I2C_SR1_TXE)) != PCA_OK)
return fail(rc);
I2C1->DR = reg;
if ((rc = sr1_wait(I2C_SR1_BTF)) != PCA_OK)
return fail(rc);
I2C1->CR1 |= I2C_CR1_START; /* повторный старт: SR2.BUSY ещё 1, start() не годится */
if ((rc = sr1_wait(I2C_SR1_SB)) != PCA_OK)
return fail(rc);
I2C1->DR = (uint8_t)(addr7 << 1 | 1u);
if ((rc = sr1_wait(I2C_SR1_ADDR)) != PCA_OK)
return fail(rc);
I2C1->CR1 &= (uint16_t)~I2C_CR1_ACK; /* один байт: RM0008, с. 764 — ACK снять до ADDR */
(void)I2C1->SR2;
I2C1->CR1 |= I2C_CR1_STOP;
if ((rc = sr1_wait(I2C_SR1_RXNE)) != PCA_OK)
return fail(rc);
*v = (uint8_t)I2C1->DR;
return PCA_OK;
}
/* фронт на PA8: дождаться нуля, потом единицы; 0 — нет сигнала за 50 мс */
static int edge(uint32_t *t)
{
uint32_t t0 = DWT->CYCCNT;
while (GPIOA->IDR & (1u << 8)) {
if (expired(t0, 50000u))
return 0;
}
while (!(GPIOA->IDR & (1u << 8))) {
if (expired(t0, 50000u))
return 0;
}
*t = DWT->CYCCNT;
return 1;
}
/* период выхода LED15 в наносекундах: восемь периодов по счётчику тактов DWT */
static uint32_t period_ns(void)
{
uint32_t a, b = 0;
if (!edge(&a))
return 0;
for (int i = 0; i < 8; i++)
if (!edge(&b))
return 0;
return (uint32_t)((uint64_t)(b - a) * 1000u / (72u * 8u));
}
int main(void)
{
static uint16_t on[16], off[16];
uint32_t us = 1000u, t0;
int32_t dir = 20;
CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
DWT->CYCCNT = 0;
DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk;
i2c1_init();
while (pca_init(&pca, PCA_ADDR_BASE, 50u, PCA_OUTDRV) != PCA_OK)
pca_port_delay_us(100000u); /* нет ответа: провод, адрес, питание */
/* калибровка: LED15 — половина периода, его фронты считает PA8 */
pca_duty(15u, PCA_STEPS / 2u, 0, &on[15], &off[15]);
if (pca_channel(&pca, 15u, on[15], off[15]) == PCA_OK) {
period_ns_meas = period_ns();
if (period_ns_meas) {
(void)pca_calibrate(&pca, period_ns_meas);
(void)pca_set_freq(&pca, 50u); /* PRE_SCALE заново — уже по настоящей частоте */
}
}
t0 = DWT->CYCCNT;
for (;;) {
for (uint32_t ch = 0; ch < 16u; ch++)
pca_servo(&pca, ch, us, 1, &on[ch], &off[ch]);
if (pca_write_all(&pca, on, off) != PCA_OK)
bus_errors++;
us = (uint32_t)((int32_t)us + dir);
if (us >= 2000u || us <= 1000u)
dir = -dir;
while (!expired(t0, FRAME_US)) {
}
t0 += FRAME_US * (CPU_HZ / 1000000u);
}
}
Дальше: раздел 14 «АЦП» — оцифровка сигналов, режимы преобразования и связка с DMA и таймером.