You could ignore the arduino PWM library and configure the PWM peripheral yourself. Also never look for reason in those libraries, there is little to be found.
Find the datasheet for the microcontroller, the sections of interest are the Timers and what pins they allow for output compare / PWM. Each timer should have 2 output pins that are suitable for PWM. Usually you set the pin for output mode like normal, setup the TCCRx registers with a suitable output compare mode and prescaler (for frequency) and load OCRx with a value for length of pulse.
You might need to be careful with timer 0 as i think arduino likes to use it for the time keeping functions. If you wont be using those functions you can re-configure the timer for your own use or try to work with whatever frequency it is already running at.
The difficult part is usally finding a picture that shows what arbitary number an arduino pin is mapped to in the hardware, ex arduino pin 5 to PORTA bit 6.
Some example code from one of my ATmega328 projects if you find it helpful. Comments might be incorrect.
void TimersInit() {
GTCCR = _BV(TSM) | _BV(PSR10); // pause timers
// OCR0A = 0;
//timer 0 - CTC toggle - output pulse 500kHz
TCCR0A = _BV(WGM01);
//timer 0 - prescale factor 8 - 1MHz
TCCR0B = _BV(CS01);
//122 full 4096 cycles / s
OCR1A = 4096*2+1;//timer 0 takes 2 cycles for each pulse, first pulse is ignored. +1 to edge align with timer 0
// OCR1B = 0;
//timer 1 - Fast PWM
TCCR1A = _BV(WGM11) | _BV(WGM10);
//timer 1 - prescale factor 8
TCCR1B = _BV(WGM13) | _BV(WGM12) | _BV(CS11);
//122Hz full cycles
GTCCR = 0; // resume timers
}
//timer compare to pin
#define TIMER0A 6
#define TIMER0B 5
#define TIMER1A 9
#define TIMER1B 10
#define TIMER2A 11
#define TIMER2B 3
void PWM(uint8_t pin, uint8_t val){
/**
* If PWM is in fast mode val == 0 does not work
* if (val == 0) {
* PORT &= ~_BV(PIN);
* } else {
*/
if (pin == TIMER1A) {
TCCR1A |= _BV(COM1A1);
// set PWM duty
OCR1A = val;
} else if (pin == TIMER1B) {
TCCR1A |= _BV(COM1B1);
// set PWM duty
OCR1B = val;
} else if (pin == TIMER0A) {
TCCR0A |= _BV(COM0A1);
// set PWM duty
OCR0A = val;
} else if (pin == TIMER0B) {
TCCR0A |= _BV(COM0B1);
// set PWM duty
OCR0B = val;
} else if (pin == TIMER2A) {
TCCR2A |= _BV(COM2A1);
// set PWM duty
OCR2A = val;
} else if (pin == TIMER2B) {
TCCR2A |= _BV(COM2B1);
// set PWM duty
OCR2B = val;
} else {
extern void error(uint8_t errorCode);
error(12);
}
}
Once you activate a servo on a pin with servo.attach(pin), the servo ISR continues pulsing that pin even when you aren't moving the servo. If you stop it, one of four things may happen, depending on the servo - it may stay where it is, or power down, or drive to a preset 'safe' position, or drive to either limit. Unless you know what the servo is specified to do on loss of signal, and that's power down or hold position, it isn't safe to use servo.detach().
Most Arduinos will use Timer 1 for the servo library (see ServoTimers.h in the library for exceptions).
In Servo.cpp:
#define usToTicks(_us) (( clockCyclesPerMicrosecond()* _us) / 8) // converts microseconds to tick (assumes prescale of 8) // 12 Aug 2009
defines the relationship between timer ticks and us.
In Servo.h:
#define MIN_PULSE_WIDTH 544 // the shortest pulse sent to a servo
#define MAX_PULSE_WIDTH 2400 // the longest pulse sent to a servo
#define DEFAULT_PULSE_WIDTH 1500 // default pulse width when servo is attached
#define REFRESH_INTERVAL 20000 // minumim time to refresh servos in microseconds
gives the limits for one servo pulse, and the total frame length.
The servo library outputs pulses to its active channels consecutively during the servo frame. Therefore if you are controlling three servos, there's a gap between approx 7.2ms and 20ms in the servo frame where you can be certain no servo pulses are being output. That's when you need to update the neopixel string(s).
As usToTicks() is private in the Servo lib, you need a copy of its definition in your sketch, then you can simply do
while(TCNT1<=usToTicks(8192)){};
pixels.show();
which waits for the gap in the servo frame before updating the neopixels. For 16 RGBW neopixels, show() has 512 bits of data to send, which will take approx 0.7us @800KHz pixel clock.
N.B. you can daisy-chain the neopixel strips by connecting DIN to DOUT, so you'll only need one I/O and one call to the show() method for all the neopixels.
There's a small overhead in show() for setting up the transfer and the reset gap that latches in the data, so one show() would be ever so slightly faster, but if its physically inconvenience to daisychain them, there's no reason not to put them on separate pins then:
while(TCNT1<=usToTicks(8192)){}; // Wait till no servo pulses
pixels1.show();
pixels2.show();
You definitely need a *lot* of bulk decoupling capacitance for the Neopixels and the servos. Unfortunately the USB standard calls for a maximum of 10uF on Vbus in a device, which is far too low for running servos on the same 5V rail as a MCU, and if you exceed the 10uF permitted by the standard significantly, you'll have problems with USB over-current at plug-in, or erosion of the connector contacts due to sparking. It would therefore be preferable to keep the buck converter and power it all from a higher voltage. The Arduino would use its onboard regulator and the servos and Neopixels would be fed by the buck converter. The seperate servo/neopixel +5V and Arduino +5v prevents servo noise crashing the Arduino. Also, it could be programmed via USB with just the Arduino powered, and there'd no USB excessive inrush current problem. You'd use an I/O pin to detect if the buck converter is outputting 5V so that the code would only enable the Neopixels and servos if they are powered.
N.B. Adafruit recommend a 470R resistor in series with DIN between the Arduino and the Neopixels to prevent damage to DIN due to transients on the data line. If you don't want dead Neopiexls fit the resistors! Also, similar resistors in the servo control lines would be advisable.
No dice so far. I am using an Arduino Uno. I plugged the power (Yellow) into the 5v pin, Ground (Black) into the GND pin, and data (Green) into pin 6. Then I used the below code to run the strip. A simple cycle test of R, G, B, W.
Getting no light at all. Does anybody see an issue with my code?
If not then I think the next step is to wire up just some wire leads on a bare NeoPixel strip and see if I can get that working with none of the other stuff. Is that a good next step? Is it possible that I just damaged one of the components during soldering and the whole assembly is broken at some point?
#include <Adafruit_NeoPixel.h>
#define neoPixelPin 6
#define neoPixelCount 8
Adafruit_NeoPixel lidPixel(neoPixelCount, neoPixelCount, NEO_RGBW + NEO_KHZ800);
void setup() {
lidPixel.begin();
lidPixel.show();
Serial.begin(9600);
Serial.println("Starting");
}
void loop() {
for (int i = 0; i < lidPixel.numPixels(); i++) {
lidPixel.setPixelColor(i, lidPixel.Color(255, 0, 0, 0));
}
lidPixel.show();
Serial.println("Red");
delay(1000);
for (int i = 0; i < lidPixel.numPixels(); i++) {
lidPixel.setPixelColor(i, lidPixel.Color(0, 255, 0, 0));
}
lidPixel.show();
Serial.println("Green");
delay(1000);
for (int i = 0; i < lidPixel.numPixels(); i++) {
lidPixel.setPixelColor(i, lidPixel.Color(0, 0, 255, 0));
}
lidPixel.show();
Serial.println("Blue");
delay(1000);
for (int i = 0; i < lidPixel.numPixels(); i++) {
lidPixel.setPixelColor(i, lidPixel.Color(0, 0, 0, 255));
}
lidPixel.show();
Serial.println("White");
delay(1000);
}
EDIT: I soldered wires on a second strip because I'm going to need it anyway. One of the leads was kind of a mess and I had to use some desoldering wire to clean it up. Anyway this strip with just the wires and nothing else didn't work either. So either I messed up the second pixel as well or there is something wrong with my code. I'm hoping for the latter. I certainly hope the NeoPixels aren't this fragile, I can't imagine how they could possibly be used in anything if they were.