Skip to content

CH5xx WS2812B by PWM/TMR/DMA/UART example - #887

Open
mattshepcar wants to merge 8 commits into
cnlohr:masterfrom
mattshepcar:ch57x-ws2812b-pwm
Open

CH5xx WS2812B by PWM/TMR/DMA/UART example#887
mattshepcar wants to merge 8 commits into
cnlohr:masterfrom
mattshepcar:ch57x-ws2812b-pwm

Conversation

@mattshepcar

Copy link
Copy Markdown

An example of some other ways to drive those fancy addressable LEDs on CH5xx MCUs for when you don't want to use the SPI pins or you need even more LEDs.

@cnlohr

cnlohr commented May 7, 2026

Copy link
Copy Markdown
Owner

@mattshepcar why not just use the code in the WS2812B driver in extralibs? https://github.com/cnlohr/ch32fun/blob/master/extralibs/ws2812b_dma_spi_led_driver.h#L243-L273 it works on the CH5xx

Fixed typo and clarified explanation of UART lookup table.
@mattshepcar

Copy link
Copy Markdown
Author

Mainly because I don't want to or can't use the SPI pins. This also gives an example of how to set up PWM/TMR DMAs which could be used for things other than driving WS2812Bs.

#define TMR_PA9 1
// the PWM buffers start and end with zero entry (duty cycle of 0 = output off).
// I'm not sure why the start one is needed but you get flickering without it.
uint16_t __attribute__((aligned(4))) WS2812B_PWM123_LedBuffer[(NR_LEDS * 24 + 2) * 3] = {0};

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you add a comment here explaining why the alignment? (I.e. because these are the raw buffers that are sent out via DMA)


static const uint8_t WS2812B_UART_LUT[8] =
{
~0b0100100, // 9 bits are used to encode 3 bits of WS2812B data.

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You don't need to change this! But, specifying ~ in a LUT is not normally a natural way to express this, instead, you would normally write out the inverted bitstream in the LUT. This is to make debugging easier.

~0b0101101,
~0b1101101,
};
void WS2812B_UART0_Send(const uint32_t* ledData, int numLeds)

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you write a blirb about these functions and what they do, and whether the ledData pointer is used as the DMA pointer, and/or if the data is made available upon completion or after completion.

}
}
#ifdef CH57x
void WS2812B_PWM_Init(int channel)

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Normally, you would make these zero indexed, even though it would disagree with the datasheet. So because you are matching the datasheet, can you change it around so that makes it clear that it's pwm_channel_1_indexed

@cnlohr

cnlohr commented May 16, 2026

Copy link
Copy Markdown
Owner

this is really close, do you mind fixing the things I outlined? they're mostly documentation.

@cnlohr

cnlohr commented Jul 3, 2026

Copy link
Copy Markdown
Owner

@mattshepcar up for addressing the comments?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants