The code below works in conjunction with my High Power RGB LED shield http://ledshield.wordpress.com. The shield is connected to the Teensy3 per I2C bus.
The core routine is an adapted 3D Bresenham algorithm to with the three coordinates being red, green, blue. each time through the main loop the algorithm advances one pixel in 3D RGB space (I guess in that case it's really a voxel )
When out-commenting the blink-without-delay code marked as such in the main loop the fading algorithm runs substantially faster than with it enabled (the value for "interval" is set to 0). The rough measurement for an 8-bit fade from r,g,b 0,0,0 --> 255,255,255 appears to be dependent on which frequency I am running the I2C bus with. Going from 100kHz to 2.4MHz results in a 10x increase. When the blink-without-delay code is enabled there is no increase in execution speed beyond 4ookHz.
Is there an alternative method to mills() or am I using this incorrectly or inefficiently ?
Without blink-without-delay code
100 kHz --> 337 ms
400 kHz --> 97 ms
600 kHz --> 75 ms
800 kHz --> 58 ms
1000 kHz --> 53 ms
1200 kHz --> 47 ms
1500 kHz --> 42 ms
2000 kHz --> 36 ms
2400 kHz --> 33 ms
with blink-without-delay
100kHz --> 337 ms
400kHz --> 256 ms
600kHz --> 256 ms
800kHz --> 256 ms
1000kHz --> 256 ms
1200kHz --> 256 ms
1500kHz --> 256 ms
2000kHz --> 256 ms
2400kHz --> 256 ms
The core routine is an adapted 3D Bresenham algorithm to with the three coordinates being red, green, blue. each time through the main loop the algorithm advances one pixel in 3D RGB space (I guess in that case it's really a voxel )
When out-commenting the blink-without-delay code marked as such in the main loop the fading algorithm runs substantially faster than with it enabled (the value for "interval" is set to 0). The rough measurement for an 8-bit fade from r,g,b 0,0,0 --> 255,255,255 appears to be dependent on which frequency I am running the I2C bus with. Going from 100kHz to 2.4MHz results in a 10x increase. When the blink-without-delay code is enabled there is no increase in execution speed beyond 4ookHz.
Is there an alternative method to mills() or am I using this incorrectly or inefficiently ?
Without blink-without-delay code
100 kHz --> 337 ms
400 kHz --> 97 ms
600 kHz --> 75 ms
800 kHz --> 58 ms
1000 kHz --> 53 ms
1200 kHz --> 47 ms
1500 kHz --> 42 ms
2000 kHz --> 36 ms
2400 kHz --> 33 ms
with blink-without-delay
100kHz --> 337 ms
400kHz --> 256 ms
600kHz --> 256 ms
800kHz --> 256 ms
1000kHz --> 256 ms
1200kHz --> 256 ms
1500kHz --> 256 ms
2000kHz --> 256 ms
2400kHz --> 256 ms
Code:
#include "i2c_t3.h"
#include "HPRGB2.h"
long interval = 0;
long previousMillis = 0;
long previousMillisTimer = 0;
int current;
class RGBFader:
public HPRGB {
public:
RGBFader (uint8_t mcp4728ID = 0x00, uint8_t pca9685ID = 0x00);
void randomLineInit(void);
void randomLine(void);
void rgbFade(uint8_t x1, uint8_t y1, uint8_t z1,uint8_t x2,uint8_t y2,uint8_t z2);
private:
int16_t xd, yd, zd;
uint8_t x, y, z;
uint16_t ax, ay, az;
int8_t sx, sy, sz;
int16_t dx, dy, dz;
uint8_t x1, y1, z1;
uint8_t x2, y2, z2;
uint8_t r, g, b;
boolean newLine;
boolean (RGBFader::*pLine)();
uint16_t MAX(uint16_t a, uint16_t b);
uint16_t ABS(int16_t a);
int8_t ZSGN(int16_t a);
boolean lineXdominant(void);
boolean lineYdominant(void);
boolean lineZdominant(void);
};
RGBFader::RGBFader(uint8_t mcp4728ID, uint8_t pca9685ID)
{
_mcp4728ID = mcp4728ID;
_mcp4728_address = (MCP4728_BASE_ADDR | _mcp4728ID);
_pca9685ID = pca9685ID;
_pca9685_address = (PCA9685_BASE_ADDR | _pca9685ID);
}
/* find maximum of a and b */
inline uint16_t RGBFader::MAX(uint16_t a, uint16_t b) {
return (a > b) ? a : b;
}
/* absolute value of a */
inline uint16_t RGBFader::ABS(int16_t a) {
return (a < 0) ? -a : a;
}
/* take sign of a, either -1, 0, or 1 */
inline int8_t RGBFader::ZSGN(int16_t a) {
return (a < 0) ? -1 : a > 0 ? 1 : 0;
}
void RGBFader::randomLineInit(void){
uint8_t rand;
rand = random (1, 4);
x1 = 0;
y1 = 0;
z1 = 0;
if (rand==1) { x2=255; } else { x2= random(0, 256); };
if (rand==2) { y2=255; } else { y2= random(0, 256); };
if (rand==3) { z2=255; } else { z2= random(0, 256); };
x = x1;
y = y1;
z = z1;
dx = x2 - x1;
dy = y2 - y1;
dz = z2 - z1;
ax = ABS(dx) << 1;
ay = ABS(dy) << 1;
az = ABS(dz) << 1;
sx = ZSGN(dx);
sy = ZSGN(dy);
sz = ZSGN(dz);
if (ax >= MAX(ay, az)){ /* x dominant */
yd = ay - (ax >> 1);
zd = az - (ax >> 1);
pLine = &RGBFader::lineXdominant;
}
else if (ay >= MAX(ax, az)){ /* y dominant */
xd = ax - (ay >> 1);
zd = az - (ay >> 1);
pLine = &RGBFader::lineYdominant;
}
else if (az >= MAX(ax, ay)){ /* z dominant */
xd = ax - (az >> 1);
yd = ay - (az >> 1);
pLine = &RGBFader::lineZdominant;
}
}
void RGBFader::rgbFade(uint8_t x1, uint8_t y1, uint8_t z1, uint8_t x2, uint8_t y2, uint8_t z2){
newLine = (this->*pLine) ();
if (newLine){
unsigned long currentMillis = micros();
Serial.println(currentMillis-previousMillisTimer);
previousMillisTimer = currentMillis;
x = x1;
y = y1;
z = z1;
dx = x2 - x1;
dy = y2 - y1;
dz = z2 - z1;
ax = ABS(dx) << 1;
ay = ABS(dy) << 1;
az = ABS(dz) << 1;
sx = ZSGN(dx);
sy = ZSGN(dy);
sz = ZSGN(dz);
if (ax >= MAX(ay, az)){ /* x dominant */
yd = ay - (ax >> 1);
zd = az - (ax >> 1);
pLine = &RGBFader::lineXdominant;
}
else if (ay >= MAX(ax, az)){ /* y dominant */
xd = ax - (ay >> 1);
zd = az - (ay >> 1);
pLine = &RGBFader::lineYdominant;
}
else if (az >= MAX(ax, ay)){ /* z dominant */
xd = ax - (az >> 1);
yd = ay - (az >> 1);
pLine = &RGBFader::lineZdominant;
}
}
}
void RGBFader::randomLine(void){
newLine = (this->*pLine) ();
if (newLine){
int rand;
rand = random (1, 4);
x1 = x2;
y1 = y2;
z1 = z2;
if (rand==1) { x2=0; } else { x2= random(0, 256); };
if (rand==2) { y2=0; } else { y2= random(0, 256); };
if (rand==3) { z2=0; } else { z2= random(0, 256); };
x = x1;
y = y1;
z = z1;
dx = x2 - x1;
dy = y2 - y1;
dz = z2 - z1;
ax = ABS(dx) << 1;
ay = ABS(dy) << 1;
az = ABS(dz) << 1;
sx = ZSGN(dx);
sy = ZSGN(dy);
sz = ZSGN(dz);
if (ax >= MAX(ay, az)){ /* x dominant */
yd = ay - (ax >> 1);
zd = az - (ax >> 1);
pLine = &RGBFader::lineXdominant;
}
else if (ay >= MAX(ax, az)){ /* y dominant */
xd = ax - (ay >> 1);
zd = az - (ay >> 1);
pLine = &RGBFader::lineYdominant;
}
else if (az >= MAX(ax, ay)){ /* z dominant */
xd = ax - (az >> 1);
yd = ay - (az >> 1);
pLine = &RGBFader::lineZdominant;
}
}
}
boolean RGBFader::lineXdominant(void){
goToRGB(x, y, z);
if (x == x2)
{
return 1;
}
if (yd >= 0)
{
y += sy;
yd -= ax;
}
if (zd >= 0)
{
z += sz;
zd -= ax;
}
x += sx;
yd += ay;
zd += az;
return 0;
}
boolean RGBFader::lineYdominant(void){
goToRGB(x, y, z);
if (y == y2){
return true;
}
if (xd >= 0){
x += sx;
xd -= ay;
}
if (zd >= 0){
z += sz;
zd -= ay;
}
y += sy;
xd += ax;
zd += az;
return false;
}
boolean RGBFader::lineZdominant(void){
goToRGB(x, y, z);
if (z == z2)
{
return true;
}
if (xd >= 0)
{
x += sx;
xd -= az;
}
if (yd >= 0)
{
y += sy;
yd -= az;
}
z += sz;
xd += ax;
yd += ay;
return false;
}
RGBFader ledOne;// default mcp4728 id(0) and default PCA9685 id(0)
void setup()
{
Serial.begin(115200);
ledOne.begin();
ledOne.setCurrent(100,100,100); // set maximum current for channel 1-3 (mA)
ledOne.setFreq(330); // operation frequency of the LED driver (KHz)
ledOne.setPWMFrequency(120);
ledOne.eepromWrite(); // write current settings to EEPROM
delay(100); // wait for EEPROM writing
//test current-settings read function
Serial.print("Max current - channel one :");
Serial.println(ledOne.getCurrent(1));
Serial.print("Max current - channel two :");
Serial.println(ledOne.getCurrent(2));
Serial.print("Max current - channel three :");
Serial.println(ledOne.getCurrent(3));
//test current-switch-frequency read function
Serial.print("Operating Frequency :");
Serial.println(ledOne.getFreq());
ledOne.randomLineInit();
}
void loop()
{
unsigned long currentMillis = millis(); // if out commented
if(currentMillis - previousMillis > interval) { // code runs
previousMillis = currentMillis; // substantially
ledOne.rgbFade(0,0,0,255,255,255);
} // faster
}