Thank you for the clarification! The history of the serial protocol is also interesting.
I've been working on the code all day today, I hooked up my oscilloscope to it and I managed to see the waveform that comes from the library directly. After that initial test, I started tinkering and trying to understand what does what.
At the moment I've managed to sort of output my desired waveform. Here is what I did:
Since a frame for DShot is 16bits (2bytes) I changed the "drawingMemory" buffer to have a length of 2 and the "displayMemory" to 8 (following the logic for the LEDs - for each byte of the LEDs I need 4 to compose the serial output). Here is the code I'm using:
This is all I changed in the header file, this is how I set the drawBuffer to the value I want. Its supposed to be 0x800F, (I think I had to switch the order because the Teensy is LSB)
Code:
void setPixel(uint32_t num, uint32_t color) {
if (num >= numled) return;
drawBuffer[0] = 0x0F;
drawBuffer[1] = 0x80;
}
This is the show function.
Code:
void WS2812Serial::show()
{
uint32_t microseconds_per_led, bytes_per_led;
// wait if prior DMA still in progress
while ((DMA_ERQ & (1 << dma->channel)))
{
yield();
}
// copy drawing buffer to frame buffer
const uint8_t *p = drawBuffer;
uint8_t *fb = frameBuffer;
uint8_t firstHalf = *p++;
uint8_t secondHalf = *p;
uint16_t n = 0;
n = (firstHalf <<8) | (secondHalf);
const uint8_t *stop = fb + 8; //The logic behind this being 8 is because in order to compose serial data for 2 bytes I just need to perform the while loop only 8 times
do
{
uint8_t x = 0x08;
if (!(n & 0x00800000)) //Here I tested removing 2 0s from then end, the logic being that I'm working with.
x |= 0x07;
if (!(n & 0x00400000))
x |= 0xE0;
n <<= 2;
*fb++ = x;
} while (fb < stop);
microseconds_per_led = 30;
bytes_per_led = 8; //Again changing this because of the 2byte frame.
// wait 300us WS2812 reset time
uint32_t min_elapsed = (numled * microseconds_per_led) + 300;
if (min_elapsed < 2500)
min_elapsed = 2500;
uint32_t m;
while (1)
{
m = micros();
if ((m - prior_micros) > min_elapsed)
break;
yield();
}
prior_micros = m;
// start DMA transfer to update LEDs :-)
// See if we need to muck with DMA cache...
if ((uint32_t)frameBuffer >= 0x20200000u)
{
arm_dcache_flush(frameBuffer, bytes_per_led);
}
dma->sourceBuffer(frameBuffer, bytes_per_led);
//dma->transferSize(1);
dma->transferCount(bytes_per_led);
dma->disableOnCompletion();
uart->STAT = 0; // try clearing out the status
dma->enable();
}
This is the example program I'm using, it's based on the basic example from the library
Code:
#include <LedLib.h>
#include <Arduino.h>
const int numled = 1;
const int pin = 1;
byte drawingMemory[2]; // 2 bytes per DSHOT Frame
DMAMEM byte displayMemory[8]; // This means 8 total bytes to compose serial data.
WS2812Serial leds(numled, displayMemory, drawingMemory, pin, WS2812_RGB);
void colorWipe(int color, int wait)
{
for (int i = 0; i < leds.numPixels(); i++)
{
leds.setPixel(i, color);
leds.show();
delayMicroseconds(wait);
}
}
void setup()
{
leds.begin();
}
void loop()
{
// change all the LEDs in 1.5 seconds
int microsec = 300000 / leds.numPixels();
colorWipe(0xF001, microsec);
}
After all of these changes I assumed that I'd send only 16bits of information, but I send 24bits- the same amount that the untouched code sent, the only difference is that the last 16bits are the data I want to send and there are 8 bits in the front and I don't know where they come from, considering the DMAMEM buffer is only 8.
This is the waveform I got before

This is the waveform I got after the code modifications

Its those 8bits in the front that confuse me the most. I've written out the logic behind the changes on paper a couple of times and they seem correct, I also wrote out how the code that composes the serial data works and I got the hang of it (its pretty clever!)