Just tweaked OctoWS2811 library to drive 16 channels plus gamma correct and dithering

Status
Not open for further replies.

DrTune

Member
Hi,
Just mentioning in case anyone's interested that it's not hard to tweak the OctoWS2811 library to run 16 channels instead of 8 (using low 8 lines of Port C + D).

On a Teensie 3.1 (which is a very awesome chip btw) it still hits the max 110hz update for 300-led strings (1.25us * 24 * 300 = 9ms = ~110Hz), so that's 4800 pixels @ 110hz. :)
I'll probably be doing 150leds/channel @ 220hz on 16 channels in my project.

I also added gamma correction (pretty essential), temporal dithering to improve color rendering and range, and conversion of the source pixels from an int32 0RGB format (which can be more convenient to work with).

On a Teensie 3.1 there's still a about 10K ram free w/4800 pixels, can probably be improved a bit. Not looked at loading LEDs over USB; I'll be running patterns straight off the teensy myself.

I'll post code on github and a video when I have a sec if anyone's interested.

Downsides: need to add your own level shifter for the other 8 channels (if using PJRC WS2812b board) , also need to move the pin 15->16 short to something else (C8 or higher instead of C0) to enable use of all 16 channels.

Cheers,
DrTune
 
Sure will do; the 16-channel trick btw is pretty obvious; you adjust the existing 3 DMA channels slightly so it writes Port C then Port D in one "minor loop" (as they call it in datasheet) and interleave the two port channels in the raw data.

This is the tweaked DMA setup section from void OctoWS2811::begin(void), just replaces the existing (very similar) code...


//0x40 byte address gap between sequential ports (a,b,c,d)
#define PORT_SPACING 0x40 /*between ports C and D */
#define MLOFFYES (1+1) // 2 byte tranfers per minor loop (port C then D)
#define FREEZE_DEST_ADDR_BITS 7 /*force dest address to alternate between ports C+D */

DMA_CR = (1<<7); //EMLM minor loop enabled;

//write port C and D in a minor loop
DMA_TCD1_SADDR = &ones;
DMA_TCD1_SOFF = 0;
DMA_TCD1_ATTR = DMA_TCD_ATTR_SSIZE(0) | DMA_TCD_ATTR_DSIZE(0) | (FREEZE_DEST_ADDR_BITS<<3);
DMA_TCD1_NBYTES_MLOFFYES = MLOFFYES;
DMA_TCD1_SLAST = 0;
DMA_TCD1_DADDR = &GPIOC_PSOR;
DMA_TCD1_DOFF = PORT_SPACING;
DMA_TCD1_CITER_ELINKNO = bufSize/2;
DMA_TCD1_DLASTSGA = 0;
DMA_TCD1_CSR = DMA_TCD_CSR_DREQ;
DMA_TCD1_BITER_ELINKNO = bufSize/2;

// DMA channel #2 writes the pixel data at 20% of the cycle
DMA_TCD2_SADDR = frameBuffer[1];
DMA_TCD2_SOFF = 1;
DMA_TCD2_ATTR = DMA_TCD_ATTR_SSIZE(0) | DMA_TCD_ATTR_DSIZE(0) | (FREEZE_DEST_ADDR_BITS<<3);;
DMA_TCD2_NBYTES_MLOFFYES = MLOFFYES;
DMA_TCD2_SLAST = -bufSize;
DMA_TCD2_DADDR = &GPIOC_PDOR;
DMA_TCD2_DOFF = PORT_SPACING;
DMA_TCD2_CITER_ELINKNO = bufSize/2;
DMA_TCD2_DLASTSGA = 0;
DMA_TCD2_CSR = DMA_TCD_CSR_DREQ;
DMA_TCD2_BITER_ELINKNO = bufSize/2;

// DMA channel #3 clear all the pins low at 48% of the cycle
DMA_TCD3_SADDR = &ones;
DMA_TCD3_SOFF = 0;
DMA_TCD3_ATTR = DMA_TCD_ATTR_SSIZE(0) | DMA_TCD_ATTR_DSIZE(0) | (FREEZE_DEST_ADDR_BITS<<3);;
DMA_TCD3_NBYTES_MLOFFYES = MLOFFYES;
DMA_TCD3_SLAST = 0;
DMA_TCD3_DADDR = &GPIOC_PCOR;
DMA_TCD3_DOFF = PORT_SPACING;
DMA_TCD3_CITER_ELINKNO = bufSize/2;
DMA_TCD3_DLASTSGA = 0;
DMA_TCD3_CSR = DMA_TCD_CSR_DREQ | DMA_TCD_CSR_INTMAJOR;
DMA_TCD3_BITER_ELINKNO = bufSize/2;


where 'bufSize' = 3*numPerStrip*NUM_STRIPS; //3 bytes per led
You just set the low 8 bits of PORTC to be outputs (unless you've still got pins 15-16 shorted, in which case leave C0 as an input and ignore that strip) and there you go.

The gamma correction & dithering are very much worth doing. That and RGB->bitslice conversion is way too long and boring to post here, I'll tidy it up and post on github when I have time.

It would be equally possible to write all 4 GPIO ports but given what's pinned out (and ram constraints etc) it's not worth the hassle.
 
Fantastic DrTune, much thanks.

Just getting into using the Teensy 3.1 to drive WS2811 pixels.. hardware on the way but meanwhile working out the software, and was trying to work out how to get more outputs. I had been thinking more along the lines of multiplexing the I/O pins to get more outputs without using a pin per output. But after thinking about it a little bit I think your way is much better.

This part of the code is definitely the critical part, so thanks very much! But if you would be willing to post the rest of your changes it would be much appreciated. Thanks again!
 
Yeah I think this is the only way that will (reasonably) work; I looked at using various TTL latches to mux the outputs but it's hard to generate the timing right (more dma channels, more PWMs etc etc).
This method does work and you can use all 16 outputs if you switch from using C0 to e.g. C8 for the loopback sync (normally is pins 15-16 connected)

Note also that (I assume) that this requires that C8..n and D8..n are not used as regular PORT outputs (using as inputs or muxed to other chip functions is fine) because you're writing the whole port output register with DMA. I've not verified this but my assumption is that the Teensy port hardware doesn't support partial writes (i.e. writing a byte to a PORT register also affects bits 8..31). It may work ok (leaves bits 8..31 undisturbed) but I wouldnt' bet on it.

Errr I'll try to post something soon - it needs serious tidying and I'm under a harsh deadline at the moment (Burning Man coming up soon). I'll see what I can manage but it may be a couple of weeks or more.
 
Last edited:
Yea I understand the burning man rush.. been there a bunch of times. Not this year tho... I do have a late Sept deadline for my project though.
I figure I'll get my first 8 outputs going and get things solid, then work on additional outputs.

My idea for simple multiplexing was to get 14 outputs from 8 output pins with no latches or changes to the output side of the driver code. To do this, connect the first 7 GPIO outputs to the corresponding inputs on a pair of 74HCT245... Then the 8th bit, instead of driving string #8, drives -OE on the first 74HCT245, and through an inverter, -OE on the other 74HCT245.

So when bit 8 is low, you are driving strings 1-7, when bit 8 is high, you are driving strings 8-14. The only software changes are in OctoWS2811::setPixel and OctoWS2811::getPixel.. a couple of small changes in the calculation of where the data should go for each string, and of course set the high bit for the second set of strings... When one set of strings is being output the other set is just held low, waiting. WS2811 data sheet seems to say this is ok.

This doesn't get you higher output rate, it just divides the buffer to more outputs.. but without using any additional GPIO's, nor touching the timing aspects of the code.

The other idea I was thinking about, before I saw your code showing how it's possible to write two 8 bit GPIO's in one DMA, was to use two sets of DMA's.. as you alluded to.. but you would not need two sets of PWMs, one set of PWM outputs can drive both sets of DMA's. But from the coding side it is a very simple change, you just instantiate the driver twice, with each instance configured to use different DMA's and different GPIO's (this would have to be added). Each has their own buffers.

What do you think?

I still like your idea the best but if it doesn't work out I'll pursue something like these...
 
The muxing idea;
Yes you can mux the existing 8 outputs like you say with a '245 (or a '373) but the disadvantage is that you're halving your scan rate; in which case there's no advantage over just doubling the length of your WS2812 strings (which can be arbitrarily long) e.g. with 600 LEDs your max rate is 55Hz whether you use a single long strip or two strips with muxed data lines. Hence you're just making things more complicated by muxing your outputs
I wanted 16 outs so I could retain a high update rate; specifically because temporal dithering is a significant improvement to the WS2812 as the LEDs themselves are only 8-bit and not gamma corrected; hence only a portion of the 256 intensity values are actually useful (e.g. 0xc0 - 0xff looks practically the same); with gamma correction so the eye perceives a fairly linear intensity gradient, you end up using few values at the high end and a lot at the low end (more steps than the LED actually has), and this causes visible stepping/gradients. Therefore you use temporal dithering to increase the perceived intensity resolution (also helps color mixing), and hence you need as high an update rate as you can get in order to make the most of it.
I found 110hz (=300 led strip) to be barely good enough when temporally dithered with an extra 3 bits. If you look at FadeCandy they only support 64 leds per channel which gives them (IIRC) something like 400hz which is great for dithering.

Aaaanyway, yes, using ports C+D for more channels was my preference. Ironically I may not actually use this configuration in my BM project but it does work.
 
Last edited:
Cool I see what you're doing.

The project I'm doing right now is only 14 pixels per string, 10-14 strings, so I could easily have them all on one output if I were to chain them. I want more outputs because the physical layout of the strings isn't friendly to chaining them. So I didn't worry about the scan rate. But I can see caring about that later, for other projects.
 
I recommend the "weatherproof" strips which come in silicone sheath; it's not super tough but it's much better than nothing. With those you can poke an extra wire down the back of the sheath to act as a return from the "far" end of the strip back to the start, allowing you to daisychain them with no external wires.

Also for anyone considering this; 60leds/meter is muuuch better than 30, and a 5M strip of 60 (=300 leds) absolutely needs to have 5V applied at both ends (using non-crappy cable, e.g. 18-22AWG) or you get terrible voltage droop (=flickering and red-shifted color) with them on brightly. A strip of about 14 is not a problem however you wire them.
 
Last edited:
Hi,

This is an awesome modification and I'm really excited to see what you've done!

Would you mind sharing your code related to the gamma curve? I'm currently working on a large display (4500+Leds) and I am very concerned about brightness!
 
Ok I hear ya! Super duper busy (no sleep last night) but I'll pull a zip together of what I have; it's pretty hacked about code but it does the biz.
basically:
a) I generate a gamma+dither table with a python script
b) I borrowed a code snippet from Fadecandy to do the conversion of RGB into bitplanes; this also does gamma+dither at the same time (but not interpolation unlike FC; it's more about raw speed)
c) Supports 300 leds per strip @ 110hz (just about - more if you can handle slightly slower refresh) x 16 channels = 4800 leds.
d) I didn't do USB input or anything else, it just displays an internal framebuffer and swizzles it around a bit
e) I'll need some tidying/hacking or you can just grab the bits you want
 
Here's a gamma/dither table for 4 bits of dithering:

There are 256 entries for intensity, times 16 sets. You cycle through the 16 sets on 16 successive frames of display.

If you drop this in and draw a gradient from 0x000000 - 0xffffff you should see a dramatically improved+linear brightness range

Lookup is basically just...

outputPixelComponent=gammaTable[ originalPixelComponent | ((frameNumber&15)<<8) ]

You look up R,G,B components individually and recombine into 24-bit for output.

Code:
/* Dithered gamma correction table - autogenerated by gamma.py */
#define DITHER_BITS 4
const unsigned char gammaTable[]={
	0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x4,0x4,0x4,0x4,0x4,0x4,0x4,0x4,0x5,0x5,0x5,0x5,0x5,0x5,0x5,0x6,0x6,0x6,0x6,0x6,0x6,0x6,0x7,0x7,0x7,0x7,0x7,0x8,0x8,0x8,0x8,0x8,0x9,0x9,0x9,0x9,0xa,0xa,0xa,0xa,0xb,0xb,0xb,0xb,0xc,0xc,0xc,0xd,0xd,0xd,0xd,0xe,0xe,0xe,0xf,0xf,0x10,0x10,0x10,0x11,0x11,0x11,0x12,0x12,0x13,0x13,0x14,0x14,0x15,0x15,0x16,0x16,0x17,0x17,0x18,0x18,0x19,0x19,0x1a,0x1b,0x1b,0x1c,0x1c,0x1d,0x1e,0x1e,0x1f,0x20,0x21,0x21,0x22,0x23,0x24,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,0x30,0x31,0x32,0x33,0x34,0x35,0x37,0x38,0x39,0x3a,0x3c,0x3d,0x3e,0x40,0x41,0x43,0x44,0x46,0x47,0x49,0x4a,0x4c,0x4e,0x4f,0x51,0x53,0x55,0x57,0x59,0x5b,0x5d,0x5f,0x61,0x63,0x65,0x67,0x6a,0x6c,0x6f,0x71,0x73,0x76,0x79,0x7b,0x7e,0x81,0x84,0x87,0x8a,0x8d,0x90,0x93,0x96,0x99,0x9d,0xa0,0xa4,0xa8,0xab,0xaf,0xb3,0xb7,0xbb,0xbf,0xc3,0xc7,0xcc,0xd0,0xd5,0xda,0xde,0xe3,0xe8,0xed,0xf3,0xf8,
	0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x4,0x4,0x4,0x4,0x4,0x4,0x4,0x4,0x4,0x5,0x5,0x5,0x5,0x5,0x5,0x5,0x5,0x6,0x6,0x6,0x6,0x6,0x6,0x6,0x7,0x7,0x7,0x7,0x7,0x8,0x8,0x8,0x8,0x8,0x8,0x9,0x9,0x9,0x9,0xa,0xa,0xa,0xa,0xb,0xb,0xb,0xb,0xc,0xc,0xc,0xc,0xd,0xd,0xd,0xe,0xe,0xe,0xf,0xf,0xf,0x10,0x10,0x10,0x11,0x11,0x12,0x12,0x12,0x13,0x13,0x14,0x14,0x15,0x15,0x16,0x16,0x17,0x17,0x18,0x18,0x19,0x19,0x1a,0x1a,0x1b,0x1c,0x1c,0x1d,0x1e,0x1e,0x1f,0x20,0x20,0x21,0x22,0x23,0x23,0x24,0x25,0x26,0x27,0x28,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,0x30,0x31,0x32,0x34,0x35,0x36,0x37,0x38,0x3a,0x3b,0x3c,0x3d,0x3f,0x40,0x42,0x43,0x45,0x46,0x48,0x49,0x4b,0x4d,0x4e,0x50,0x52,0x54,0x55,0x57,0x59,0x5b,0x5d,0x5f,0x61,0x64,0x66,0x68,0x6a,0x6d,0x6f,0x71,0x74,0x77,0x79,0x7c,0x7f,0x81,0x84,0x87,0x8a,0x8d,0x90,0x93,0x97,0x9a,0x9d,0xa1,0xa4,0xa8,0xac,0xaf,0xb3,0xb7,0xbb,0xbf,0xc4,0xc8,0xcc,0xd1,0xd5,0xda,0xdf,0xe4,0xe9,0xee,0xf3,0xf9,
	0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x4,0x4,0x4,0x4,0x4,0x4,0x4,0x4,0x4,0x5,0x5,0x5,0x5,0x5,0x5,0x5,0x5,0x6,0x6,0x6,0x6,0x6,0x6,0x7,0x7,0x7,0x7,0x7,0x7,0x8,0x8,0x8,0x8,0x8,0x9,0x9,0x9,0x9,0xa,0xa,0xa,0xa,0xb,0xb,0xb,0xb,0xc,0xc,0xc,0xc,0xd,0xd,0xd,0xe,0xe,0xe,0xf,0xf,0xf,0x10,0x10,0x11,0x11,0x11,0x12,0x12,0x13,0x13,0x13,0x14,0x14,0x15,0x15,0x16,0x16,0x17,0x17,0x18,0x18,0x19,0x1a,0x1a,0x1b,0x1b,0x1c,0x1d,0x1d,0x1e,0x1f,0x1f,0x20,0x21,0x22,0x22,0x23,0x24,0x25,0x26,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,0x30,0x31,0x32,0x33,0x34,0x36,0x37,0x38,0x39,0x3b,0x3c,0x3d,0x3f,0x40,0x41,0x43,0x44,0x46,0x47,0x49,0x4b,0x4c,0x4e,0x50,0x51,0x53,0x55,0x57,0x59,0x5b,0x5d,0x5f,0x61,0x63,0x65,0x68,0x6a,0x6c,0x6f,0x71,0x74,0x76,0x79,0x7c,0x7e,0x81,0x84,0x87,0x8a,0x8d,0x90,0x93,0x96,0x9a,0x9d,0xa1,0xa4,0xa8,0xab,0xaf,0xb3,0xb7,0xbb,0xbf,0xc3,0xc8,0xcc,0xd1,0xd5,0xda,0xdf,0xe4,0xe9,0xee,0xf3,0xf8,
	0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x4,0x4,0x4,0x4,0x4,0x4,0x4,0x4,0x4,0x4,0x5,0x5,0x5,0x5,0x5,0x5,0x5,0x5,0x6,0x6,0x6,0x6,0x6,0x6,0x6,0x7,0x7,0x7,0x7,0x7,0x7,0x8,0x8,0x8,0x8,0x8,0x9,0x9,0x9,0x9,0x9,0xa,0xa,0xa,0xa,0xb,0xb,0xb,0xb,0xc,0xc,0xc,0xc,0xd,0xd,0xd,0xe,0xe,0xe,0xf,0xf,0xf,0x10,0x10,0x10,0x11,0x11,0x11,0x12,0x12,0x13,0x13,0x14,0x14,0x14,0x15,0x15,0x16,0x16,0x17,0x17,0x18,0x18,0x19,0x1a,0x1a,0x1b,0x1b,0x1c,0x1d,0x1d,0x1e,0x1e,0x1f,0x20,0x21,0x21,0x22,0x23,0x24,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,0x30,0x32,0x33,0x34,0x35,0x36,0x37,0x39,0x3a,0x3b,0x3c,0x3e,0x3f,0x40,0x42,0x43,0x45,0x46,0x48,0x4a,0x4b,0x4d,0x4e,0x50,0x52,0x54,0x56,0x58,0x59,0x5b,0x5d,0x60,0x62,0x64,0x66,0x68,0x6b,0x6d,0x6f,0x72,0x74,0x77,0x79,0x7c,0x7f,0x82,0x84,0x87,0x8a,0x8d,0x91,0x94,0x97,0x9a,0x9e,0xa1,0xa5,0xa8,0xac,0xb0,0xb4,0xb8,0xbc,0xc0,0xc4,0xc8,0xcd,0xd1,0xd6,0xda,0xdf,0xe4,0xe9,0xee,0xf3,0xf9,
	0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x4,0x4,0x4,0x4,0x4,0x4,0x4,0x4,0x5,0x5,0x5,0x5,0x5,0x5,0x5,0x5,0x6,0x6,0x6,0x6,0x6,0x6,0x7,0x7,0x7,0x7,0x7,0x8,0x8,0x8,0x8,0x8,0x9,0x9,0x9,0x9,0x9,0xa,0xa,0xa,0xa,0xb,0xb,0xb,0xb,0xc,0xc,0xc,0xd,0xd,0xd,0xe,0xe,0xe,0xf,0xf,0xf,0x10,0x10,0x10,0x11,0x11,0x12,0x12,0x12,0x13,0x13,0x14,0x14,0x15,0x15,0x16,0x16,0x17,0x17,0x18,0x18,0x19,0x19,0x1a,0x1b,0x1b,0x1c,0x1d,0x1d,0x1e,0x1f,0x1f,0x20,0x21,0x21,0x22,0x23,0x24,0x25,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,0x30,0x31,0x32,0x33,0x34,0x35,0x37,0x38,0x39,0x3a,0x3c,0x3d,0x3e,0x40,0x41,0x43,0x44,0x46,0x47,0x49,0x4b,0x4c,0x4e,0x50,0x51,0x53,0x55,0x57,0x59,0x5b,0x5d,0x5f,0x61,0x63,0x65,0x68,0x6a,0x6c,0x6f,0x71,0x74,0x76,0x79,0x7b,0x7e,0x81,0x84,0x87,0x8a,0x8d,0x90,0x93,0x96,0x9a,0x9d,0xa0,0xa4,0xa8,0xab,0xaf,0xb3,0xb7,0xbb,0xbf,0xc3,0xc8,0xcc,0xd0,0xd5,0xda,0xdf,0xe3,0xe8,0xee,0xf3,0xf8,
	0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x4,0x4,0x4,0x4,0x4,0x4,0x4,0x4,0x4,0x5,0x5,0x5,0x5,0x5,0x5,0x5,0x5,0x6,0x6,0x6,0x6,0x6,0x6,0x6,0x7,0x7,0x7,0x7,0x7,0x7,0x8,0x8,0x8,0x8,0x8,0x9,0x9,0x9,0x9,0x9,0xa,0xa,0xa,0xa,0xb,0xb,0xb,0xb,0xc,0xc,0xc,0xd,0xd,0xd,0xd,0xe,0xe,0xe,0xf,0xf,0xf,0x10,0x10,0x11,0x11,0x11,0x12,0x12,0x13,0x13,0x13,0x14,0x14,0x15,0x15,0x16,0x16,0x17,0x17,0x18,0x18,0x19,0x19,0x1a,0x1b,0x1b,0x1c,0x1c,0x1d,0x1e,0x1e,0x1f,0x20,0x20,0x21,0x22,0x23,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,0x30,0x31,0x33,0x34,0x35,0x36,0x37,0x38,0x3a,0x3b,0x3c,0x3e,0x3f,0x40,0x42,0x43,0x45,0x46,0x48,0x49,0x4b,0x4d,0x4e,0x50,0x52,0x54,0x56,0x57,0x59,0x5b,0x5d,0x5f,0x62,0x64,0x66,0x68,0x6a,0x6d,0x6f,0x72,0x74,0x77,0x79,0x7c,0x7f,0x81,0x84,0x87,0x8a,0x8d,0x90,0x94,0x97,0x9a,0x9e,0xa1,0xa5,0xa8,0xac,0xb0,0xb3,0xb7,0xbb,0xc0,0xc4,0xc8,0xcc,0xd1,0xd6,0xda,0xdf,0xe4,0xe9,0xee,0xf3,0xf9,
	0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x4,0x4,0x4,0x4,0x4,0x4,0x4,0x4,0x4,0x5,0x5,0x5,0x5,0x5,0x5,0x5,0x5,0x6,0x6,0x6,0x6,0x6,0x6,0x7,0x7,0x7,0x7,0x7,0x7,0x8,0x8,0x8,0x8,0x8,0x9,0x9,0x9,0x9,0x9,0xa,0xa,0xa,0xa,0xb,0xb,0xb,0xb,0xc,0xc,0xc,0xd,0xd,0xd,0xe,0xe,0xe,0xf,0xf,0xf,0x10,0x10,0x10,0x11,0x11,0x11,0x12,0x12,0x13,0x13,0x14,0x14,0x14,0x15,0x15,0x16,0x16,0x17,0x17,0x18,0x19,0x19,0x1a,0x1a,0x1b,0x1c,0x1c,0x1d,0x1d,0x1e,0x1f,0x1f,0x20,0x21,0x22,0x22,0x23,0x24,0x25,0x26,0x27,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,0x30,0x31,0x32,0x33,0x35,0x36,0x37,0x38,0x39,0x3b,0x3c,0x3d,0x3f,0x40,0x42,0x43,0x44,0x46,0x48,0x49,0x4b,0x4c,0x4e,0x50,0x52,0x53,0x55,0x57,0x59,0x5b,0x5d,0x5f,0x61,0x63,0x66,0x68,0x6a,0x6d,0x6f,0x71,0x74,0x76,0x79,0x7c,0x7e,0x81,0x84,0x87,0x8a,0x8d,0x90,0x93,0x97,0x9a,0x9d,0xa1,0xa4,0xa8,0xac,0xaf,0xb3,0xb7,0xbb,0xbf,0xc4,0xc8,0xcc,0xd1,0xd5,0xda,0xdf,0xe4,0xe9,0xee,0xf3,0xf8,
	0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x4,0x4,0x4,0x4,0x4,0x4,0x4,0x4,0x4,0x4,0x5,0x5,0x5,0x5,0x5,0x5,0x5,0x5,0x6,0x6,0x6,0x6,0x6,0x6,0x6,0x7,0x7,0x7,0x7,0x7,0x7,0x8,0x8,0x8,0x8,0x8,0x8,0x9,0x9,0x9,0x9,0xa,0xa,0xa,0xa,0xa,0xb,0xb,0xb,0xb,0xc,0xc,0xc,0xd,0xd,0xd,0xd,0xe,0xe,0xe,0xf,0xf,0xf,0x10,0x10,0x10,0x11,0x11,0x12,0x12,0x12,0x13,0x13,0x14,0x14,0x15,0x15,0x15,0x16,0x16,0x17,0x17,0x18,0x19,0x19,0x1a,0x1a,0x1b,0x1b,0x1c,0x1d,0x1d,0x1e,0x1f,0x1f,0x20,0x21,0x21,0x22,0x23,0x24,0x25,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2d,0x2f,0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x39,0x3a,0x3b,0x3c,0x3e,0x3f,0x41,0x42,0x43,0x45,0x46,0x48,0x4a,0x4b,0x4d,0x4f,0x50,0x52,0x54,0x56,0x58,0x5a,0x5c,0x5e,0x60,0x62,0x64,0x66,0x68,0x6b,0x6d,0x6f,0x72,0x74,0x77,0x7a,0x7c,0x7f,0x82,0x85,0x87,0x8a,0x8e,0x91,0x94,0x97,0x9a,0x9e,0xa1,0xa5,0xa8,0xac,0xb0,0xb4,0xb8,0xbc,0xc0,0xc4,0xc8,0xcd,0xd1,0xd6,0xdb,0xdf,0xe4,0xe9,0xee,0xf4,0xf9,
	0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x4,0x4,0x4,0x4,0x4,0x4,0x4,0x4,0x4,0x5,0x5,0x5,0x5,0x5,0x5,0x5,0x6,0x6,0x6,0x6,0x6,0x6,0x7,0x7,0x7,0x7,0x7,0x7,0x8,0x8,0x8,0x8,0x8,0x9,0x9,0x9,0x9,0xa,0xa,0xa,0xa,0xb,0xb,0xb,0xb,0xc,0xc,0xc,0xd,0xd,0xd,0xe,0xe,0xe,0xf,0xf,0xf,0x10,0x10,0x10,0x11,0x11,0x12,0x12,0x12,0x13,0x13,0x14,0x14,0x15,0x15,0x16,0x16,0x17,0x17,0x18,0x18,0x19,0x19,0x1a,0x1b,0x1b,0x1c,0x1c,0x1d,0x1e,0x1e,0x1f,0x20,0x21,0x21,0x22,0x23,0x24,0x25,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,0x30,0x31,0x32,0x33,0x34,0x35,0x37,0x38,0x39,0x3a,0x3c,0x3d,0x3e,0x40,0x41,0x43,0x44,0x46,0x47,0x49,0x4a,0x4c,0x4e,0x50,0x51,0x53,0x55,0x57,0x59,0x5b,0x5d,0x5f,0x61,0x63,0x65,0x68,0x6a,0x6c,0x6f,0x71,0x74,0x76,0x79,0x7b,0x7e,0x81,0x84,0x87,0x8a,0x8d,0x90,0x93,0x96,0x9a,0x9d,0xa0,0xa4,0xa8,0xab,0xaf,0xb3,0xb7,0xbb,0xbf,0xc3,0xc8,0xcc,0xd0,0xd5,0xda,0xdf,0xe3,0xe8,0xee,0xf3,0xf8,
	0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x4,0x4,0x4,0x4,0x4,0x4,0x4,0x4,0x4,0x4,0x5,0x5,0x5,0x5,0x5,0x5,0x5,0x5,0x6,0x6,0x6,0x6,0x6,0x6,0x7,0x7,0x7,0x7,0x7,0x7,0x8,0x8,0x8,0x8,0x8,0x9,0x9,0x9,0x9,0x9,0xa,0xa,0xa,0xa,0xb,0xb,0xb,0xb,0xc,0xc,0xc,0xc,0xd,0xd,0xd,0xe,0xe,0xe,0xf,0xf,0xf,0x10,0x10,0x10,0x11,0x11,0x12,0x12,0x12,0x13,0x13,0x14,0x14,0x15,0x15,0x16,0x16,0x17,0x17,0x18,0x18,0x19,0x19,0x1a,0x1a,0x1b,0x1c,0x1c,0x1d,0x1e,0x1e,0x1f,0x20,0x20,0x21,0x22,0x23,0x23,0x24,0x25,0x26,0x27,0x28,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,0x30,0x31,0x32,0x34,0x35,0x36,0x37,0x38,0x3a,0x3b,0x3c,0x3e,0x3f,0x40,0x42,0x43,0x45,0x46,0x48,0x49,0x4b,0x4d,0x4e,0x50,0x52,0x54,0x55,0x57,0x59,0x5b,0x5d,0x5f,0x61,0x64,0x66,0x68,0x6a,0x6d,0x6f,0x72,0x74,0x77,0x79,0x7c,0x7f,0x81,0x84,0x87,0x8a,0x8d,0x90,0x93,0x97,0x9a,0x9d,0xa1,0xa4,0xa8,0xac,0xb0,0xb3,0xb7,0xbb,0xc0,0xc4,0xc8,0xcc,0xd1,0xd6,0xda,0xdf,0xe4,0xe9,0xee,0xf3,0xf9,
	0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x4,0x4,0x4,0x4,0x4,0x4,0x4,0x4,0x4,0x5,0x5,0x5,0x5,0x5,0x5,0x5,0x6,0x6,0x6,0x6,0x6,0x6,0x6,0x7,0x7,0x7,0x7,0x7,0x8,0x8,0x8,0x8,0x8,0x9,0x9,0x9,0x9,0x9,0xa,0xa,0xa,0xa,0xb,0xb,0xb,0xb,0xc,0xc,0xc,0xd,0xd,0xd,0xd,0xe,0xe,0xe,0xf,0xf,0xf,0x10,0x10,0x11,0x11,0x11,0x12,0x12,0x13,0x13,0x14,0x14,0x14,0x15,0x15,0x16,0x16,0x17,0x17,0x18,0x19,0x19,0x1a,0x1a,0x1b,0x1b,0x1c,0x1d,0x1d,0x1e,0x1f,0x1f,0x20,0x21,0x22,0x22,0x23,0x24,0x25,0x26,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,0x30,0x31,0x32,0x33,0x34,0x36,0x37,0x38,0x39,0x3b,0x3c,0x3d,0x3f,0x40,0x41,0x43,0x44,0x46,0x47,0x49,0x4b,0x4c,0x4e,0x50,0x52,0x53,0x55,0x57,0x59,0x5b,0x5d,0x5f,0x61,0x63,0x66,0x68,0x6a,0x6c,0x6f,0x71,0x74,0x76,0x79,0x7c,0x7e,0x81,0x84,0x87,0x8a,0x8d,0x90,0x93,0x96,0x9a,0x9d,0xa1,0xa4,0xa8,0xac,0xaf,0xb3,0xb7,0xbb,0xbf,0xc3,0xc8,0xcc,0xd1,0xd5,0xda,0xdf,0xe4,0xe9,0xee,0xf3,0xf8,
	0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x4,0x4,0x4,0x4,0x4,0x4,0x4,0x4,0x4,0x4,0x5,0x5,0x5,0x5,0x5,0x5,0x5,0x5,0x6,0x6,0x6,0x6,0x6,0x6,0x6,0x7,0x7,0x7,0x7,0x7,0x7,0x8,0x8,0x8,0x8,0x8,0x9,0x9,0x9,0x9,0x9,0xa,0xa,0xa,0xa,0xb,0xb,0xb,0xb,0xc,0xc,0xc,0xc,0xd,0xd,0xd,0xe,0xe,0xe,0xf,0xf,0xf,0x10,0x10,0x10,0x11,0x11,0x11,0x12,0x12,0x13,0x13,0x14,0x14,0x14,0x15,0x15,0x16,0x16,0x17,0x17,0x18,0x18,0x19,0x1a,0x1a,0x1b,0x1b,0x1c,0x1d,0x1d,0x1e,0x1f,0x1f,0x20,0x21,0x21,0x22,0x23,0x24,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2b,0x2c,0x2d,0x2e,0x2f,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x39,0x3a,0x3b,0x3c,0x3e,0x3f,0x41,0x42,0x43,0x45,0x46,0x48,0x4a,0x4b,0x4d,0x4f,0x50,0x52,0x54,0x56,0x58,0x5a,0x5c,0x5e,0x60,0x62,0x64,0x66,0x68,0x6b,0x6d,0x6f,0x72,0x74,0x77,0x79,0x7c,0x7f,0x82,0x85,0x87,0x8a,0x8d,0x91,0x94,0x97,0x9a,0x9e,0xa1,0xa5,0xa8,0xac,0xb0,0xb4,0xb8,0xbc,0xc0,0xc4,0xc8,0xcd,0xd1,0xd6,0xda,0xdf,0xe4,0xe9,0xee,0xf4,0xf9,
	0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x4,0x4,0x4,0x4,0x4,0x4,0x4,0x4,0x4,0x5,0x5,0x5,0x5,0x5,0x5,0x5,0x6,0x6,0x6,0x6,0x6,0x6,0x7,0x7,0x7,0x7,0x7,0x7,0x8,0x8,0x8,0x8,0x8,0x9,0x9,0x9,0x9,0xa,0xa,0xa,0xa,0xa,0xb,0xb,0xb,0xc,0xc,0xc,0xc,0xd,0xd,0xd,0xe,0xe,0xe,0xf,0xf,0xf,0x10,0x10,0x10,0x11,0x11,0x12,0x12,0x13,0x13,0x13,0x14,0x14,0x15,0x15,0x16,0x16,0x17,0x17,0x18,0x18,0x19,0x1a,0x1a,0x1b,0x1b,0x1c,0x1d,0x1d,0x1e,0x1f,0x1f,0x20,0x21,0x21,0x22,0x23,0x24,0x25,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,0x30,0x31,0x32,0x33,0x34,0x36,0x37,0x38,0x39,0x3a,0x3c,0x3d,0x3e,0x40,0x41,0x43,0x44,0x46,0x47,0x49,0x4b,0x4c,0x4e,0x50,0x51,0x53,0x55,0x57,0x59,0x5b,0x5d,0x5f,0x61,0x63,0x65,0x68,0x6a,0x6c,0x6f,0x71,0x74,0x76,0x79,0x7c,0x7e,0x81,0x84,0x87,0x8a,0x8d,0x90,0x93,0x96,0x9a,0x9d,0xa1,0xa4,0xa8,0xab,0xaf,0xb3,0xb7,0xbb,0xbf,0xc3,0xc8,0xcc,0xd1,0xd5,0xda,0xdf,0xe4,0xe9,0xee,0xf3,0xf8,
	0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x4,0x4,0x4,0x4,0x4,0x4,0x4,0x4,0x4,0x4,0x5,0x5,0x5,0x5,0x5,0x5,0x5,0x5,0x6,0x6,0x6,0x6,0x6,0x6,0x7,0x7,0x7,0x7,0x7,0x7,0x8,0x8,0x8,0x8,0x8,0x8,0x9,0x9,0x9,0x9,0xa,0xa,0xa,0xa,0xa,0xb,0xb,0xb,0xc,0xc,0xc,0xc,0xd,0xd,0xd,0xe,0xe,0xe,0xe,0xf,0xf,0x10,0x10,0x10,0x11,0x11,0x11,0x12,0x12,0x13,0x13,0x13,0x14,0x14,0x15,0x15,0x16,0x16,0x17,0x17,0x18,0x18,0x19,0x19,0x1a,0x1b,0x1b,0x1c,0x1c,0x1d,0x1e,0x1e,0x1f,0x20,0x21,0x21,0x22,0x23,0x24,0x24,0x25,0x26,0x27,0x28,0x29,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,0x30,0x31,0x33,0x34,0x35,0x36,0x37,0x38,0x3a,0x3b,0x3c,0x3e,0x3f,0x40,0x42,0x43,0x45,0x46,0x48,0x49,0x4b,0x4d,0x4e,0x50,0x52,0x54,0x56,0x57,0x59,0x5b,0x5d,0x5f,0x62,0x64,0x66,0x68,0x6a,0x6d,0x6f,0x72,0x74,0x77,0x79,0x7c,0x7f,0x82,0x84,0x87,0x8a,0x8d,0x90,0x94,0x97,0x9a,0x9e,0xa1,0xa5,0xa8,0xac,0xb0,0xb4,0xb7,0xbc,0xc0,0xc4,0xc8,0xcd,0xd1,0xd6,0xda,0xdf,0xe4,0xe9,0xee,0xf3,0xf9,
	0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x4,0x4,0x4,0x4,0x4,0x4,0x4,0x4,0x4,0x5,0x5,0x5,0x5,0x5,0x5,0x5,0x6,0x6,0x6,0x6,0x6,0x6,0x6,0x7,0x7,0x7,0x7,0x7,0x7,0x8,0x8,0x8,0x8,0x8,0x9,0x9,0x9,0x9,0xa,0xa,0xa,0xa,0xa,0xb,0xb,0xb,0xc,0xc,0xc,0xc,0xd,0xd,0xd,0xe,0xe,0xe,0xf,0xf,0xf,0x10,0x10,0x10,0x11,0x11,0x12,0x12,0x12,0x13,0x13,0x14,0x14,0x15,0x15,0x16,0x16,0x17,0x17,0x18,0x18,0x19,0x19,0x1a,0x1a,0x1b,0x1c,0x1c,0x1d,0x1e,0x1e,0x1f,0x20,0x20,0x21,0x22,0x23,0x23,0x24,0x25,0x26,0x27,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,0x30,0x31,0x32,0x33,0x35,0x36,0x37,0x38,0x39,0x3b,0x3c,0x3d,0x3f,0x40,0x42,0x43,0x45,0x46,0x48,0x49,0x4b,0x4c,0x4e,0x50,0x52,0x53,0x55,0x57,0x59,0x5b,0x5d,0x5f,0x61,0x63,0x66,0x68,0x6a,0x6d,0x6f,0x71,0x74,0x76,0x79,0x7c,0x7e,0x81,0x84,0x87,0x8a,0x8d,0x90,0x93,0x97,0x9a,0x9d,0xa1,0xa4,0xa8,0xac,0xaf,0xb3,0xb7,0xbb,0xbf,0xc4,0xc8,0xcc,0xd1,0xd5,0xda,0xdf,0xe4,0xe9,0xee,0xf3,0xf8,
	0x0,0x0,0x0,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x4,0x4,0x4,0x4,0x4,0x4,0x4,0x4,0x4,0x4,0x5,0x5,0x5,0x5,0x5,0x5,0x5,0x5,0x5,0x6,0x6,0x6,0x6,0x6,0x6,0x6,0x7,0x7,0x7,0x7,0x7,0x7,0x8,0x8,0x8,0x8,0x8,0x9,0x9,0x9,0x9,0x9,0xa,0xa,0xa,0xa,0xa,0xb,0xb,0xb,0xb,0xc,0xc,0xc,0xd,0xd,0xd,0xd,0xe,0xe,0xe,0xf,0xf,0xf,0x10,0x10,0x10,0x11,0x11,0x12,0x12,0x12,0x13,0x13,0x14,0x14,0x15,0x15,0x16,0x16,0x17,0x17,0x18,0x18,0x19,0x19,0x1a,0x1a,0x1b,0x1b,0x1c,0x1d,0x1d,0x1e,0x1f,0x1f,0x20,0x21,0x22,0x22,0x23,0x24,0x25,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x39,0x3a,0x3b,0x3d,0x3e,0x3f,0x41,0x42,0x44,0x45,0x47,0x48,0x4a,0x4b,0x4d,0x4f,0x50,0x52,0x54,0x56,0x58,0x5a,0x5c,0x5e,0x60,0x62,0x64,0x66,0x68,0x6b,0x6d,0x6f,0x72,0x74,0x77,0x7a,0x7c,0x7f,0x82,0x85,0x88,0x8b,0x8e,0x91,0x94,0x97,0x9a,0x9e,0xa1,0xa5,0xa8,0xac,0xb0,0xb4,0xb8,0xbc,0xc0,0xc4,0xc8,0xcd,0xd1,0xd6,0xdb,0xdf,0xe4,0xe9,0xee,0xf4,0xf9
	};

Generated by this python script:


Code:
fout=open("gamma.h","wt")

#adjust me! Each extra bit doubles the table size 
ditherBits=4

ditherMSB=1<<(ditherBits-1)

res="/* Dithered gamma correction table - autogenerated by gamma.py by DrTune */\n#define DITHER_BITS %d\nconst unsigned char gammaTable[]={" % ditherBits

for dither in range(1<<ditherBits):
    out=[]

    #reverse the low order bits so the dithering is semi-randomized to reduce flicker
    ditherValue=0
    dread=1<<ditherBits
    dout=1
    for d in range(ditherBits):
        dread>>=1
        if dither & dread:
            ditherValue|=dout
        dout<<=1;
    
    ditherValue=(ditherValue<<(8-ditherBits))

    for n in range(256):
        #adjust for logarithmic eye response
        gamma=pow(255,(n/256.0))-1
        gamma=int(gamma*256)
        gamma+=ditherValue
        out.append( gamma>>8 )
    if dither:
        res+=","
    res+="\n\t"+(",".join([ "0x%x"%n for n in out]))  
    
res+="\n\t};\n"

print >>fout,res
fout.close()

You may find that 4 bits of dither causes flickering of low intensity pixels at lower frame rates; in which case just generate a 3-bit or 2-bit instead (change 'ditherBits')
 
Very cool stuff.. you've clearly put a lot of work into it :) I've gone over your code a bunch and see now how it all works...

I got my hardware and wrote a little code to do Artnet to WS2811 and right away saw the need for what you're doing. I put in an 8 bit log curve (no dithering, so I'm losing resolution) and it looks smoother.. but the dithering is needed. Hopefully this weekend I will have the time to give your code a try.

Hope your burn was great and your project looked good out there.

Thanks!
 
Heh that (WS2812b) project was very last-minute and survived about 15 minutes until suffering an undiagnosable hw failure on the playa. Got a few vids in the 'lab':
https://www.youtube.com/watch?v=uc3usXKintI
https://www.youtube.com/watch?v=0Vz4jE65GeM
This failure was a shame but not at all unexpected; Burning Man requires 'mil-spec' not 'alpha' level hardware; I had a bunch of critical issues with power wiring & connectors to run 2400 LEDs flicker-free and that took too long to sort out in the end.
I had some nice things working with controller gloves and foot sensors so maybe I'll finish it off and get it working well for halloween :)

...However, the other three projects worked (Snowconeokie (did 500 snowcones this year) , Retroscope (UV laser thing https://www.youtube.com/watch?v=DWYPvA4e8D8 ), and simplest of all the "Bad Advice Booth")

eh, next year. :)
 
Status
Not open for further replies.
Back
Top