diff --git a/examples/usb-basic.py b/examples/usb-basic.py index 30bd077017dc46c0b39e6c334bdcd13f5a7665d3..42f2b5aa690d18cf3449e57d56c1779d266ac2db 100755 --- a/examples/usb-basic.py +++ b/examples/usb-basic.py @@ -59,5 +59,5 @@ while True: #time.sleep(0.1) print - time.sleep(2) + time.sleep(0.1) diff --git a/firmware/fadecandy.cpp b/firmware/fadecandy.cpp index f29414f889de872f2d328f0ce15f717d05e0b331..5ad420d32ebe71d2bffc0693abb05dffd2511887 100644 --- a/firmware/fadecandy.cpp +++ b/firmware/fadecandy.cpp @@ -39,6 +39,29 @@ static OctoWS2811z leds(LEDS_PER_STRIP, ledBuffer, WS2811_800kHz); static int8_t residual[CHANNELS_TOTAL]; +static uint32_t calculateInterpCoefficient() +{ + /* + * Calculate our interpolation coefficient. This is a value between + * 0x0000 and 0x10000, representing some point in between fbPrev and fbNext. + * + * We timestamp each frame at the moment its final packet has been received. + * In other words, fbNew has no valid timestamp yet, and fbPrev/fbNext both + * have timestamps in the recent past. + * + * fbNext's timestamp indicates when both fbPrev and fbNext entered their current + * position in the keyframe queue. The difference between fbPrev and fbNext indicate + * how long the interpolation between those keyframes should take. + */ + + uint32_t now = millis(); + uint32_t tsPrev = buffers.fbPrev->timestamp; + uint32_t tsNext = buffers.fbNext->timestamp; + + uint32_t scaled = ((now - tsNext) << 16) / (tsNext - tsPrev); + return std::min<uint32_t>(scaled, 0x10000); +} + ALWAYS_INLINE static inline uint32_t lutInterpolate(const uint16_t *lut, uint32_t arg) { /* @@ -54,7 +77,7 @@ ALWAYS_INLINE static inline uint32_t lutInterpolate(const uint16_t *lut, uint32_ return (lut[index] * invAlpha + lut[index + 1] * alpha) >> 8; } -static inline uint32_t updatePixel(uint32_t icPrev, uint32_t icNext, +static uint32_t updatePixel(uint32_t icPrev, uint32_t icNext, const uint8_t *pixelPrev, const uint8_t *pixelNext, const uint16_t *lut, int8_t *pResidual) { @@ -416,8 +439,7 @@ extern "C" int main() while (1) { buffers.handleUSB(); - - updateDrawBuffer((millis() << 4) & 0xFFFF); + updateDrawBuffer(calculateInterpCoefficient()); leds.show(); // Optionally disable dithering by clearing our residual buffer every frame. diff --git a/firmware/fc_usb.cpp b/firmware/fc_usb.cpp index de1ec1f7d6641b3b5bbf56ba1cfe3ec826caa5f3..364223918eee025ee3cb74552dad9e435e1dda10 100644 --- a/firmware/fc_usb.cpp +++ b/firmware/fc_usb.cpp @@ -86,6 +86,7 @@ void fcBuffers::handleUSB() void fcBuffers::finalizeFramebuffer() { fcFramebuffer *recycle = fbPrev; + fbNew->timestamp = millis(); fbPrev = fbNext; fbNext = fbNew; fbNew = recycle; diff --git a/firmware/fc_usb.h b/firmware/fc_usb.h index e975cdec53779f74bb29bfe6b52b29b6c6171153..5d69081777ef654095905c3e63188c5de5d72d0f 100644 --- a/firmware/fc_usb.h +++ b/firmware/fc_usb.h @@ -36,6 +36,7 @@ template <unsigned tSize> struct fcPacketBuffer { usb_packet_t *packets[tSize]; + uint32_t timestamp; fcPacketBuffer() {