24const uint32_t PCA9685_OSC_HZ = 25000000u;
25const uint8_t PCA9685_PRESCALE_MIN = 3;
26const uint8_t PCA9685_PRESCALE_MAX = 255;
33 return PCA9685_PRESCALE_MAX;
35 uint32_t denom = 4096u * freq_hz;
36 uint32_t pre = (PCA9685_OSC_HZ + denom / 2) / denom;
37 pre = pre ? pre - 1 : 0;
38 if (pre < PCA9685_PRESCALE_MIN)
40 pre = PCA9685_PRESCALE_MIN;
42 if (pre > PCA9685_PRESCALE_MAX)
44 pre = PCA9685_PRESCALE_MAX;
61 uint64_t num = (uint64_t)microseconds * 4096u * freq_hz;
62 uint32_t count = (uint32_t)((num + 500000u) / 1000000u);
74 buf[1] = (uint8_t)(on & 0xFF);
75 buf[2] = (uint8_t)((on >> 8) & 0x1F);
76 buf[3] = (uint8_t)(off & 0xFF);
77 buf[4] = (uint8_t)((off >> 8) & 0x1F);
98bool wr(uint8_t reg, uint8_t val)
100 Wire.beginTransmission(s_pca.addr);
103 return Wire.endTransmission() == 0;
116 delayMicroseconds(500);
129 Wire.beginTransmission(s_pca.addr);
131 return Wire.endTransmission() == 0;
The one owner of the shared I2C bus bring-up for the peripheral drivers.
void pc_i2c_begin()
Bring up the shared I2C bus on PC_I2C_SDA_PIN / PC_I2C_SCL_PIN (-1 = default).
NXP PCA9685 16-channel 12-bit PWM / servo driver codec (PC_ENABLE_PCA9685).
#define PCA9685_CHANNELS
PWM output channels.
size_t pc_pca9685_set_pwm_bytes(uint8_t *buf, size_t cap, uint8_t channel, uint16_t on, uint16_t off)
Emit the 5-byte channel PWM write: [LED_ON_L(channel), ON_L, ON_H, OFF_L, OFF_H] (each count 12-bit l...
uint16_t pc_pca9685_us_to_count(uint32_t microseconds, uint32_t freq_hz)
Convert a servo pulse width (microseconds) at freq_hz to a 12-bit OFF count (rounded),...
bool pc_pca9685_set_servo_us(uint8_t channel, uint32_t microseconds)
Drive a servo on channel to a microseconds pulse (uses the configured frequency).
#define PCA9685_REG_MODE2
#define PCA9685_REG_MODE1
#define PCA9685_COUNT_MAX
a PWM count is 12-bit (0..4095)
bool pc_pca9685_set_pwm(uint8_t channel, uint16_t on, uint16_t off)
Set channel's raw 12-bit ON / OFF counts.
#define PCA9685_REG_LED0_ON_L
channel 0 base; channel n is this + 4*n
#define PCA9685_REG_PRESCALE
uint8_t pc_pca9685_prescale(uint32_t freq_hz)
Compute the PRESCALE register value for a PWM output frequency (25 MHz oscillator): round(25e6 / (409...
uint8_t pc_pca9685_channel_reg(uint8_t channel)
The register base (LED_ON_L) for channel (0..15); 0 for an out-of-range channel.
bool pc_pca9685_begin(uint8_t addr, uint32_t freq_hz)
Reset the PCA9685 at addr and set the PWM frequency freq_hz.
User-facing configuration for ProtoCore.
#define PC_PCA9685_I2C_ADDR
I2C address of the PCA9685 (0x40 default; the six address pins select 0x40..0x7F).
#define PC_PCA9685_FREQ
Default PWM output frequency in Hz (50 Hz suits hobby servos).