// Custom chips playground
// See https://link.wokwi.com/custom-chips-alpha for more info
// ======================= Copied Definitions ====================
// Copied some adafruit servo driver code rather than import the library - will do that later
// This explains the defines below etc...
#include <Wire.h>
// #define ENABLE_DEBUG_OUTPUT
// REGISTER ADDRESSES
#define PCA9685_MODE1 0x00 /**< Mode Register 1 */
#define PCA9685_PRESCALE 0xFE /**< Prescaler for PWM output frequency */
// MODE1 bits
#define MODE1_ALLCAL 0x01 /**< respond to LED All Call I2C-bus address */
#define MODE1_SUB3 0x02 /**< respond to I2C-bus subaddress 3 */
#define MODE1_SUB2 0x04 /**< respond to I2C-bus subaddress 2 */
#define MODE1_SUB1 0x08 /**< respond to I2C-bus subaddress 1 */
#define MODE1_SLEEP 0x10 /**< Low power mode. Oscillator off */
#define MODE1_AI 0x20 /**< Auto-Increment enabled */
#define MODE1_EXTCLK 0x40 /**< Use EXTCLK pin clock */
#define MODE1_RESTART 0x80 /**< Restart enabled */
#define FREQUENCY_OSCILLATOR 25000000 /**< Int. osc. frequency in datasheet */
#define PCA9685_PRESCALE_MIN 3 /**< minimum prescale value */
#define PCA9685_PRESCALE_MAX 255 /**< maximum prescale value */
// ======================= End of Copied Definitions ====================
// chip address. must match the wiring in diagram.json
const uint8_t _i2caddr = 0x5F;
static void begin(uint8_t prescale=0);
static void reset();
static void restart();
static void setPWMFreq(float f);
void setup() {
Serial.begin(115200);
Wire.begin();
// initialise the PCA9685 chip
begin();
setPWM(_i2caddr, 0, 1500, 2000);
delay(5000);
reset();
delay(1000);
setPWM(_i2caddr, 0, 1000, 3000);
delay(5000);
restart();
// setPWM(_i2caddr, 1, 4000, 3000);
}
void loop() {
// static uint16_t ndx;
// for (uint16_t i = 0; i < 8; i++) {
// // Serial.print(ndx);Serial.print(" spwm ");Serial.print(i); Serial.print(" on:"); Serial.print(i * 256); Serial.print(" off:");Serial.println((i+ 1 + (ndx %10))*256);
// setPWM(_i2caddr, i, i * 256, (i+ 1 + (ndx & 7))*256);
// }
// ndx++;
delay(500);
}
void begin(uint8_t prescale=0) {
restart();
// set a default frequency
setPWMFreq(1);
}
/*!
* @brief Sends a reset command to the PCA9685 chip over I2C
*/
void restart() {
write8(PCA9685_MODE1, MODE1_RESTART);
delay(10);
}
void setPWMFreq(float freq) {
// Range output modulation frequency is dependant on oscillator
if (freq < 1)
freq = 1;
if (freq > 3500)
freq = 3500; // Datasheet limit is 3052=50MHz/(4*4096)
float prescaleval = ((FREQUENCY_OSCILLATOR / (freq * 4096.0)) + 0.5) - 1;
if (prescaleval < PCA9685_PRESCALE_MIN)
prescaleval = PCA9685_PRESCALE_MIN;
if (prescaleval > PCA9685_PRESCALE_MAX)
prescaleval = PCA9685_PRESCALE_MAX;
uint8_t prescale = (uint8_t)prescaleval;
// #ifdef ENABLE_DEBUG_OUTPUT
Serial.print("Final pre-scale: ");
Serial.println(prescale);
// #endif
uint8_t oldmode = read8(PCA9685_MODE1);
uint8_t newmode = (oldmode & ~MODE1_RESTART) | MODE1_SLEEP; // sleep
write8(PCA9685_MODE1, newmode); // go to sleep
write8(PCA9685_PRESCALE, prescale); // set the prescaler
write8(PCA9685_MODE1, oldmode);
delay(5);
// This sets the MODE1 register to turn on auto increment.
write8(PCA9685_MODE1, oldmode | MODE1_RESTART | MODE1_AI);
#ifdef ENABLE_DEBUG_OUTPUT
Serial.print("Mode now 0x");
Serial.println(read8(PCA9685_MODE1), HEX);
#endif
}
void setPWM(int addr, int chan, uint16_t on, uint16_t off ) {
#ifdef ENABLE_DEBUG_OUTPUT
Serial.print("Setting PWM ");
Serial.print(chan);
Serial.print(": ");
Serial.print(on);
Serial.print("->");
Serial.println(off);
#endif
Wire.beginTransmission(addr);
Wire.write(6 + 4 * chan);
Wire.write(on);
Wire.write(on >> 8);
Wire.write(off);
Wire.write(off >> 8);
Wire.endTransmission();
}
uint8_t read8(uint8_t addr) {
Wire.beginTransmission(_i2caddr);
Wire.write(addr);
Wire.endTransmission();
Wire.requestFrom((uint8_t)_i2caddr, (uint8_t)1);
return Wire.read();
}
void write8(uint8_t addr, uint8_t d) {
Wire.beginTransmission(_i2caddr);
Wire.write(addr);
Wire.write(d);
Wire.endTransmission();
}
void reset() {
Wire.beginTransmission(0);
Wire.write(6);
Wire.endTransmission();
}
mega:SCL
mega:SDA
mega:AREF
mega:GND.1
mega:13
mega:12
mega:11
mega:10
mega:9
mega:8
mega:7
mega:6
mega:5
mega:4
mega:3
mega:2
mega:1
mega:0
mega:14
mega:15
mega:16
mega:17
mega:18
mega:19
mega:20
mega:21
mega:5V.1
mega:5V.2
mega:22
mega:23
mega:24
mega:25
mega:26
mega:27
mega:28
mega:29
mega:30
mega:31
mega:32
mega:33
mega:34
mega:35
mega:36
mega:37
mega:38
mega:39
mega:40
mega:41
mega:42
mega:43
mega:44
mega:45
mega:46
mega:47
mega:48
mega:49
mega:50
mega:51
mega:52
mega:53
mega:GND.4
mega:GND.5
mega:IOREF
mega:RESET
mega:3.3V
mega:5V
mega:GND.2
mega:GND.3
mega:VIN
mega:A0
mega:A1
mega:A2
mega:A3
mega:A4
mega:A5
mega:A6
mega:A7
mega:A8
mega:A9
mega:A10
mega:A11
mega:A12
mega:A13
mega:A14
mega:A15
chip1:A0
chip1:A1
chip1:A2
chip1:A3
chip1:A4
chip1:LED0
chip1:LED1
chip1:LED2
chip1:LED3
chip1:LED4
chip1:LED5
chip1:LED6
chip1:LED7
chip1:VSS
chip1:LED8
chip1:LED9
chip1:LED10
chip1:LED11
chip1:LED12
chip1:LED13
chip1:LED14
chip1:LED15
chip1:OE
chip1:A5
chip1:EXTCLK
chip1:SCL
chip1:SDA
chip1:VDD
led0:A
led0:C
led1:A
led1:C
led2:A
led2:C
led3:A
led3:C
led4:A
led4:C
led5:A
led5:C
led6:A
led6:C
led7:A
led7:C
r1:1
r1:2
logic1:D0
logic1:D1
logic1:D2
logic1:D3
logic1:D4
logic1:D5
logic1:D6
logic1:D7
logic1:GND