WSD2811 led time code in C, optimize further - Page 1
Forum section: electronics / beginners

author: Vindhyachal.takniki
author_rank: Frequent Contributor
timestamp: May 27, 2019, 02:04:17 pm
content: 1. I am using WSD2811 to run led in series. I am using C-code for programming. My below code is working by carefully adjusting some of NOP instructions.2. 100 leds are working fine on WSD2811, my code is in C, so no issues. Dont want to write in assembly.3. Below is my code, in which I check each bit of red/green/blue by if/else, then make pin high/low4. Want to know if there any other way I can optimize code in c language or better way to do that in C-language.5. Please dont suggest to write in assembly or if code is already working why to change.I want to write in C only, & check if there any way I can further optimize code in C language.Again by current code, my leds are working fineCode:static void ws2811_rgb_write(uint8_t red, uint8_t green , uint8_t blue){//R1if(red & 0x80U){LED_PIN_HIGH();}else{LED_PIN_LOW();}/////R2if(red & 0x40U){LED_PIN_HIGH();}else{LED_PIN_LOW();}/////R3if(red & 0x20U){LED_PIN_HIGH();}else{LED_PIN_LOW();}/////R4if(red & 0x10U){LED_PIN_HIGH();}else{LED_PIN_LOW();}/////R5if(red & 0x08U){LED_PIN_HIGH();}else{LED_PIN_LOW();}/////R6if(red & 0x04U){LED_PIN_HIGH();}else{LED_PIN_LOW();}/////R7if(red & 0x02U){LED_PIN_HIGH();}else{LED_PIN_LOW();}/////R8if(red & 0x01U){LED_PIN_HIGH();}else{LED_PIN_LOW();}/////R1if(green & 0x80U){LED_PIN_HIGH();}else{LED_PIN_LOW();}/////R2if(green & 0x40U){LED_PIN_HIGH();}else{LED_PIN_LOW();}/////R3if(green & 0x20U){LED_PIN_HIGH();}else{LED_PIN_LOW();}/////R4if(green & 0x10U){LED_PIN_HIGH();}else{LED_PIN_LOW();}/////R5if(green & 0x08U){LED_PIN_HIGH();}else{LED_PIN_LOW();}/////R6if(green & 0x04U){LED_PIN_HIGH();}else{LED_PIN_LOW();}/////R7if(green & 0x02U){LED_PIN_HIGH();}else{LED_PIN_LOW();}/////R8if(green & 0x01U){LED_PIN_HIGH();}else{LED_PIN_LOW();}/////R1if(blue & 0x80U){LED_PIN_HIGH();}else{LED_PIN_LOW();}/////R2if(blue & 0x40U){LED_PIN_HIGH();}else{LED_PIN_LOW();}/////R3if(blue & 0x20U){LED_PIN_HIGH();}else{LED_PIN_LOW();}/////R4if(blue & 0x10U){LED_PIN_HIGH();}else{LED_PIN_LOW();}/////R5if(blue & 0x08U){LED_PIN_HIGH();}else{LED_PIN_LOW();}/////R6if(blue & 0x04U){LED_PIN_HIGH();}else{LED_PIN_LOW();}/////R7if(blue & 0x02U){LED_PIN_HIGH();}else{LED_PIN_LOW();}/////R8if(blue & 0x01U){LED_PIN_HIGH();}else{LED_PIN_LOW();}///}

author: garethw
author_rank: Regular Contributor
timestamp: May 27, 2019, 02:10:56 pm
content: I believe that apart from purchasing a more efficient compiler the only alternative is what you’ve told us not to tell you.Sent from my iPhone using Tapatalk

author: cgroen
author_rank: Unknown
timestamp: May 27, 2019, 02:14:34 pm
content: Get a CPU that will allow you to handle some of that timing direct in hardware....I use a LPC1549 that uses one of its SCT modules to handle this. I do all in C and have no problem with timing

author: garethw
author_rank: Regular Contributor
timestamp: May 27, 2019, 02:18:55 pm
content: What is it that isn’t working? You said it works with 100 leds. Why try to optimise if it already works.I’m not the best person to comment as I really like assembly and only use C for quick jobs if I’m using an unfamiliar mcu.Sent from my iPhone using Tapatalk

author: Kjelt
author_rank: Super Contributor
timestamp: May 27, 2019, 03:49:41 pm
content: Easy optimization is a for loop per led color databyte where you just shift left and use the same bitmask 0x80.Code looks cleaner that way and others can easier understand the code IMO.BTW working with NOPs for bitbanging is a last resort if you really need the extreme speed.It will only work on that uC , others it might fail due to timing issues. Cleaner to use a timer peripheral for the exact timing, but as said this might be impossible in some extreme cases.

author: Nerull
author_rank: Frequent Contributor
timestamp: May 27, 2019, 04:06:44 pm
content: WS2811s require really tight timing, depending on the MCU and clock speed used there may not be time to use timers. For example, to send a '0' you must toggle the IO with less than 500ns between the rising and falling edges, which is a single instruction on a 8MHz PIC.

author: zzattack
author_rank: Regular Contributor
timestamp: May 27, 2019, 05:52:40 pm
content: Easiest way to drive these LEDs without having to worry about timing too much is with an SPI peripheral, even better if you have DMA too. I've driven a chain of over 2000 leds using a PIC18 but getting timing right with C code seems a dumb effort.

author: Vindhyachal.takniki
author_rank: Frequent Contributor
timestamp: June 06, 2019, 12:00:04 pm
content: thanks for inputs. current code is working fine for me at the moment

author: ejeffrey
author_rank: Super Contributor
timestamp: June 06, 2019, 04:23:42 pm
content: Quote from: Vindhyachal.takniki on May 27, 2019, 02:04:17 pmBasically at this level optimizations are extremely specific to the platform, compiler, compiler settings, and so on. People might be able to give you some ideas, but it isn't usually practical to say X will be faster since we can't really test it on your system. Typically you would also look at the generated assembler to see what the compiler is doing. You haven't even specified your architecture, compiler, or what you have already tried, so we don't really know what is going on.That said, some things I would try:Rewrite LED_PIN_HIGH() and LED_PIN_LOW() into a macro LED_SET_PIN(int val) that can set the pin by writing the value directly to an IO port rather than requiring a conditional comparison and jump followed by the write. That can save you 1-2 instructions.Pack rgb into 24 bits of a 32 bit integer and use a loop with bit shifting and then always look at the high or low order bit. On some architectures this will shove the bit that shifts off the end of the register into an overflow/carry flag which can directly be used by a conditional without extra logical operations. Maybe your C compiler is smart enough to figure out what you are doing and maybe not.Other options: use a faster CPU, or one that supports DMA. DMA will get you two advantages: first, the bits can be shifted out as fast as the hardware allows, and second you can be doing your computations to figure out what bits to toggle in parallel with the DMA transfer. With a faster CPU you have to be careful: if you change architectures, you may get a faster core with a slower GPIO peripheral.