The world's first MCU with hardware ARGB LED interface LLSI. Nuvoton NUC1263 - Page 1
Forum section: electronics / general

author: danchouzhou
author_rank: Contributor
timestamp: March 21, 2025, 01:46:47 pm
content: I saw Nuvoton introducing the NUC1262/NUC1263 MCU on their forum weeks ago. In addition to the ARMv8 Cortex-M23 CPU, it features Nuvoton's patented hardware peripheral, LLSI. Moreover, a friend from Everlight gave me their newly developed “magical” product, and some brilliant ideas immediately came to my mind. Therefore, I ordered a NuMaker-NUC1263SD development board and five chips from Nuvoton's online store. To my surprise, they arrived the very next day!Nuvoton NUC1263 Series: Vibrant ARGB Lighting Control with Easy LLSI Interface DesignHowever, the project is still under design, so stay tuned. For now, let’s experiment with the NUC1263 MCU and its LLSI using the Adafruit NeoPixel Ring. The complete test code will also be shared on GitHub and in the comment section! (Looking at the project name, can you guess what I’m going to do again? lol)https://github.com/danchouzhou/LLSIClock/blob/main/firmware/LLSI_RGBW/main.cKey Features of the NUC1263:Arm Cortex-M23, 72 MHz, based on ARMv8-M architectureBuilt-in 64 KB Flash and 20 KB SRAMOperating voltage: 2.5 V ~ 5.5 VIn addition to common peripherals such as UART, SPI, I2C, ADC, and PWM, it also supports I3C, USB, and 4 DACsIt features a built-in level shifter which has independent VDDIO pin, enabling I3C to support a minimum voltage of 0.95 VThe most notable feature is its patented and exclusive hardware function – LLSIFirst Time Hearing about LLSI?LLSI, which is LED Light Strip Interface. It’s a control interface specifically designed for addressable LEDs (ARGB LED). Common models include WS2812B, SK6812, or Adafruit's NeoPixel series. The advantage of this interface lies in its simplicity: a single signal wire connects to the DINinput of the first LED, and its DOUToutput chains to the DINof the next LED, allow us to control the entire strip of full-color LEDs.Since it only uses a single wire, the ARGB LED control interface encodes ‘0’ and ‘1’ in the timing of the high and low signal durations. Nuvoton has implemented this control timing in hardware, giving it the cool name - LLSI and integrating it into the MCU. This makes Nuvoton the first company to launch an MCU with hardware capabilities for controlling ARGB LEDs, also it’s an exclusive function only available on Nuvoton MCUs.Trends of RGB Dynamic Lighting EffectsRGB dynamic lighting effects have become increasingly popular. They can now be seen in countless gaming peripherals, including keyboards, mice, motherboards, graphics cards, PC cases, fans, power supplies, coolers, and headsets. Even Windows 11 has built-in options to adjust lighting effects. RGB LEDs are also appearing behind TV and decorative lighting to create various ambient effects in homes.Controlling ARGB LEDsIn the past, controlling ARGB LEDs with an MCU involved manually changing the GPIO output state, relying on NOP instructions or timer delays to generate the timing sequences by the software. To meet the precision requirements of timing, the CPU couldn’t perform other tasks during transmission, and interrupts had to be disabled to ensure complete data transmission. This method, such as theAdafruit NeoPixel Library, andthe porting of NeoPixel Library to Nuvoton MCUs.As RGB dynamic effects gain popularity, the number and complexity of LEDs are increasing, making software-generated timing sequences less feasible. This has caused significant challenges for firmware designers.World’s First, Exclusive Feature, Latest Patent! What’s the Advantages of LLSI?Fortunately, Nuvoton has introduced LLSI. With LLSI, all you need to do is fill the buffer with the color data for each LED, and the hardware automatically sends out the content by the ARGB LED timing sequence. It operates similarly to some serial communication interfaces.The NUC1263's LLSI provides a 16-byte-depth FIFO buffer, supports transmit threshold interrupt and DMA transfers, design to free up CPU resources. This allows the CPU to focus on its primary tasks or compute complex lighting effects. Thanks to the built-in 64 KB Flash and 20 KB SRAM ensure ample memory, even as the number of LEDs increases!ImplementationAfter introducing LLSI, let’s deep into the technical, what you will realize the benefits of LLSI. Whether you’re accustomed to Keil MDK, IAR, or Nuvoton’s own NuEclipse development environment, you can refer to the NuMaker-NUC1263SD manual to set up the development environment:https://www.nuvoton.com/export/resource-files/en-us--UM_NuMaker-NUC1263SD_EN_Rev1.00.pdfThe LLSI can also Control RGBW “Four-Color” Addressable LEDsThe NUC1263 manual reveals that LLSI is designed for three-color addressable LEDs (RGB). Data is sent 3-byte in a units, supporting both RGB and GRB arrangements. While controlling standard ARGB are obviously, today we’ll test whether LLSI can control the four-color ARGB variant, “ARGBW”!To test the NUC1263’s LLSI, I pulled out a treasured, never-usedAdafruit NeoPixel Ring - 24 x RGBW Natural White (~4500K). I remember get this for over 20 USD at Micro Center during my studies in the US years ago. In addition to the common RGB three colors, it includes an extra white LED, offering better color rendering (CRI) than the white light created by mixing RGB.Lighting Up Each Color (RGBW) with LLSIBefore creating effects, you must first determine the arrangement of R, G, B, W in each LED and how to control them individually. Let’s start by lighting up a single color:The use of LLSI is straightforward and can be activated with these three lines of code. I used PC.5 on the NUC1263 as the LLSI0 output. Since we’re using 24 x four-color RGBW LEDs, not the originally designed three-color RGB LEDs, you’ll need to adjust the LED quantity field manually and can be calculated like this:LLSI_PCNT = 24 / 3 x 4 = 32Code:CLK_EnableModuleClock(LLSI0_MODULE); // Enable LLSI0 module clock// T_Period = 1250ns; T_T0H = 400ns; T_T1H = 850ns; T_ResetPeriod = 50000ns; LED count = 32LLSI_Open(LLSI0, LLSI_MODE_SW, LLSI_FORMAT_RGB, HCLK_CLK, 1250, 400, 850, 50000, 0, LLSI_IDLE_LOW);SET_LLSI0_OUT_PC5(); // Set PC.5 multi-function pins for LLSI0Here are the respective codes for lighting up R, G, B, and W in four LEDs, each occupying 8 bits. Testing reveals the arrangement order is 0xWWBBRRGG. But why is there an extra 0x00000000 sent at the end? As mentioned earlier,QuoteSince four RGBW LEDs total 16 bytes, which isn’t divisible by 3, LLSI assumes the data is incomplete and won’t send the last byte which light up the white LED. Thus, adding an additional dummy data field “tricks” it into sending the last LED’s data.Code:// 0xWWBBRRGGLLSI_WRITE_DATA(LLSI0, 0x000000FF);LLSI_WRITE_DATA(LLSI0, 0x0000FF00);LLSI_WRITE_DATA(LLSI0, 0x00FF0000);LLSI_WRITE_DATA(LLSI0, 0xFF000000);LLSI_WRITE_DATA(LLSI0, 0x00000000);Creating a Marquee Effect with LLSIFortunately, the NeoPixel Ring used here has 24 x RGBW LEDs, which is a common multiple of 3 and 4. When initializing LLSI with `LLSI_Open()` and setting the LED count to 32, creating an RGBW marquee effect doesn’t require additional handling. The program flow will become like this, instead of lighting up one by one:Create an array `g_au32frameBuffer[]` as a “frame.”Enable Threshold Interrupt to notify the CPU to fill up the FIFO when the content drops below the set threshold.Enable frame end interrupts, which trigger when all LED data has been transmitted, setting the flag `g_u32FrameEnd` to ‘1’ and updating the pattern style `g_u32PatternToggle`.In the main program, check the flag, and once the previous “frame” has been sent, calculate new pattern to update the “frame.”This example clearly demonstrates the convenience of controlling ARGB LEDs with LLSI. After filling `g_au32frameBuffer` with the pattern, the hardware automatically generates the timing sequences. When the FIFO falls below the lower limit, the hardware triggers an interrupt to notify the CPU to “reload the cartridge,” conserving significant CPU resources.Below are three lines of code to enable the two interrupt functions mentioned above:Code:/* Set TX FIFO threshold */LLSI_SetFIFO(LLSI0, 2);NVIC_EnableIRQ(LLSI0_IRQn);/* Enable Transmit FIFO Threshold Interrupt and Frame End Interrupt */LLSI_EnableInt(LLSI0, LLSI_TXTH_INT_MASK | LLSI_FEND_INT_MASK);The ISR code:Code:void LLSI0_IRQHandler(){if (LLSI_GetIntFlag(LLSI0, LLSI_TXTH_INT_MASK)){while(LLSI_GET_TX_FIFO_FULL_FLAG(LLSI0) == 0) // Fill up the TX FIFO{if (g_u32DataCount == (TEST_COUNT - 1))LLSI_SET_LAST_DATA(LLSI0); // Before writing last word data to LLSI_DATA, user must write LDT = 1if (g_u32DataCount < TEST_COUNT)LLSI_WRITE_DATA(LLSI0, g_au32frameBuffer[g_u32DataCount++]);elsebreak;}if(g_u32DataCount >= TEST_COUNT){LLSI_DisableInt(LLSI0, LLSI_TXTH_INT_MASK);}}if (LLSI_GetIntFlag(LLSI0, LLSI_FEND_INT_MASK)) // FENDIF will be set to 1 when LLSI transfer last pixel data.{g_u32FrameEnd = 1;g_u32PatternToggle++;LLSI_ClearIntFlag(LLSI0, LLSI_FEND_INT_MASK);}}The algorithm to update the pattern:Code:if (g_u32FrameEnd == 1) // Wait for FEND_INT{u32Tmp = g_u32PatternToggle % 4;/* Generate a new frame */for (int i=0; i<TEST_COUNT; i++){if (i % 4 == u32Tmp)g_au32frameBuffer = 0xFF000000 >> (u32Tmp * 8);elseg_au32frameBuffer = 0x00000000;}g_u32FrameEnd = 0;g_u32DataCount = 0;LLSI_EnableInt(LLSI0, LLSI_TXTH_INT_MASK);CLK_SysTickDelay(50000);}The resultWanna try the latest patented LLSI technology? Don’t miss this!By joining Nuvoton’s forum, you can engage in technical exchanges and also receive a 10% coupon for Nuvoton’s official online store. Tap the link below for event details.https://forum.nuvoton.com/en/programs-events/seminars-events/14355

author: danchouzhou
author_rank: Contributor
timestamp: March 21, 2025, 01:49:30 pm
content: Full test code for the marquee effect:main.c(5.66 kB - downloaded 11 times.)Code:#include <stdio.h>#include "NuMicro.h"#define HCLK_CLK 72000000#define TEST_COUNT 24// Color format is 0xWWBBRRGG for the Adafruit NeoPixel Ring 24 x RGBW (2862)volatile uint32_t g_au32frameBuffer = {0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000};volatile uint32_t g_u32PatternToggle = 0;volatile uint32_t g_u32DataCount = 0;volatile uint32_t g_u32FrameEnd = 0;void LLSI0_IRQHandler(){if (LLSI_GetIntFlag(LLSI0, LLSI_TXTH_INT_MASK)){while(LLSI_GET_TX_FIFO_FULL_FLAG(LLSI0) == 0) // Fill up the TX FIFO{if (g_u32DataCount == (TEST_COUNT - 1))LLSI_SET_LAST_DATA(LLSI0); // Before writing last word data to LLSI_DATA, user must write LDT = 1if (g_u32DataCount < TEST_COUNT)LLSI_WRITE_DATA(LLSI0, g_au32frameBuffer[g_u32DataCount++]);elsebreak;}if(g_u32DataCount >= TEST_COUNT){LLSI_DisableInt(LLSI0, LLSI_TXTH_INT_MASK);}}if (LLSI_GetIntFlag(LLSI0, LLSI_FEND_INT_MASK)) // FENDIF will be set to 1 when LLSI transfer last pixel data.{g_u32FrameEnd = 1;g_u32PatternToggle++;LLSI_ClearIntFlag(LLSI0, LLSI_FEND_INT_MASK);}}void SYS_Init(void){/*---------------------------------------------------------------------------------------------------------*//* Init System Clock *//*---------------------------------------------------------------------------------------------------------*//* Enable HIRC clock */CLK_EnableXtalRC(CLK_PWRCTL_HIRCEN_Msk);/* Wait for HIRC clock ready */CLK_WaitClockReady(CLK_STATUS_HIRCSTB_Msk);/* Set core clock to HCLK_CLK Hz */CLK_SetCoreClock(HCLK_CLK);/* Enable UART0 module clock */CLK_EnableModuleClock(UART0_MODULE);/* Select UART0 module clock source as HIRC/2 and UART0 module clock divider as 1 */CLK_SetModuleClock(UART0_MODULE, CLK_CLKSEL1_UART0SEL_HIRC_DIV2, CLK_CLKDIV0_UART0(1));/* Enable LLSI0 module clock */CLK_EnableModuleClock(LLSI0_MODULE);/*---------------------------------------------------------------------------------------------------------*//* Init I/O Multi-function *//*---------------------------------------------------------------------------------------------------------*//* Set PB multi-function pins for UART0 RXD and TXD */SYS->GPB_MFPH = (SYS->GPB_MFPH & (~(UART0_RXD_PB12_Msk | UART0_TXD_PB13_Msk))) | UART0_RXD_PB12 | UART0_TXD_PB13;/* Set PC multi-function pins for LLSI0 */SET_LLSI0_OUT_PC5();}void UART0_Init(){/*---------------------------------------------------------------------------------------------------------*//* Init UART *//*---------------------------------------------------------------------------------------------------------*//* Reset UART0 module */SYS_ResetModule(UART0_RST);/* Configure UART0 and set UART0 Baudrate */UART_Open(UART0, 115200);}void LLSI_Init(void){/*---------------------------------------------------------------------------------------------------------*//* Init LLSI *//*---------------------------------------------------------------------------------------------------------*//* Configure as software mode, RGB output format, 6 pixels in a frame and idle output low *//* Set clock divider. LLSI clock rate = 72MHz *//* Set data transfer period. T_Period = 1250ns *//* Set duty period. T_T0H = 400ns; T_T1H = 850ns *//* Set reset command period. T_ResetPeriod = 50000ns */LLSI_Open(LLSI0, LLSI_MODE_SW, LLSI_FORMAT_RGB, HCLK_CLK, 1250, 400, 850, 50000, 32, LLSI_IDLE_LOW);/* Set TX FIFO threshold */LLSI_SetFIFO(LLSI0, 2);/* Enable reset command function */LLSI_ENABLE_RESET_COMMAND(LLSI0);NVIC_EnableIRQ(LLSI0_IRQn);}void main(void){uint32_t u32Tmp;/* Unlock protected registers */SYS_UnlockReg();/* Init System, IP clock and multi-function I/O. */SYS_Init();/* Lock protected registers */SYS_LockReg();/* Init UART0 for printf */UART_Open(UART0, 115200);printf("\n\nCPU @ %d Hz\n", SystemCoreClock);/* Init LLSI */LLSI_Init();/* Enable Transmit FIFO Threshold Interrupt and Frame End Interrupt */LLSI_EnableInt(LLSI0, LLSI_TXTH_INT_MASK | LLSI_FEND_INT_MASK);LLSI_WRITE_DATA(LLSI0, g_au32frameBuffer[g_u32DataCount++]); // Write the first word to trigger TXTH_INTwhile(1){if (g_u32FrameEnd == 1) // Wait for FEND_INT{u32Tmp = g_u32PatternToggle % 4;/* Generate a new frame */for (int i=0; i<TEST_COUNT; i++){if (i % 4 == u32Tmp)g_au32frameBuffer = 0xFF000000 >> (u32Tmp * 8);elseg_au32frameBuffer = 0x00000000;}g_u32FrameEnd = 0;g_u32DataCount = 0;LLSI_EnableInt(LLSI0, LLSI_TXTH_INT_MASK);CLK_SysTickDelay(50000);}}}

author: Ian.M
author_rank: Super Contributor
timestamp: March 21, 2025, 02:22:07 pm
content: Prior art: Microchip had hardware support for the WS2811 LED protocol on their Enhanced Midrange PIC16s with MSSP and CLC back in 2013.http://ww1.microchip.com/downloads/en/AppNotes/00001606A.pdfThey also added CLC support to some of their more powerful PICs with DMA, enabling streaming bytes from a buffer to strings of single wire addressable LEDs without CPU intervention during the transfer.

author: ColinB
author_rank: Contributor
timestamp: March 21, 2025, 06:52:50 pm
content: You'd think someone would have implemented hardware for the WS2811 type ARGB strips by now after all these years of them being produced and used. It's a great idea.But I wonder how much different this is from something like using PWM+DMA on an STM32 like this code does:https://github.com/MaJerle/stm32-ws2811-ws2812-ws2812b-ws281x-tim-pwm-dma-timer?tab=readme-ov-file- which seems fairly similar to how the Microchip AN1606 method works.Also the RP2040 PIO interface has been programmed as an addressable RGB driver, which is cool because of how flexible this module is. Here is a clever implementation using the RP2040 PIO to drive 8x ARGB buses in parallel.https://mcuoneclipse.com/2023/04/02/rp2040-with-pio-and-dma-to-address-ws2812b-leds/- and also the RP2040 is less than half the price of the NUC1262 even including the RP2040's required external flash chip.

author: SiliconWizard
author_rank: Super Contributor
timestamp: March 21, 2025, 07:29:51 pm
content: Yes there are many ways to do this efficiently using various peripherals, such as the PIO on the RP2040/2350 or output compare on most MCUs having that coupled to DMA.But it's a bit of work, or requires relying on a third-party library which may be shaky, and usually while the transfer will be efficient via DMA, there's still a bit of overhead to build the data buffers with the correctly encoded data.So having a ready-made peripheral guaranteed to work robustly is a plus. But clearly, not a game-changer.

author: ozcar
author_rank: Frequent Contributor
timestamp: March 22, 2025, 02:30:35 am
content: I have seen many ways of skinning this cat.The Adafruit Library already mentioned uses different ways for different processors. Yes, mostly bit-banging while running with interrupts disabled, but that is not always the case, for example, it does use PIO for RP2040. What is a bit odd about that library is that it uses slightly different ways of doing the same thing, perhaps due to different parts being contributed by different authors who did not look closely at other existing code there. For example, for some ARM processors, it times the bit-banging by closely watching DWT CYCCNT, while for others is uses the SysTick timer in a way that even the author called "kind of horrible".One way that I don't see utilised by the Adafruit library uses SPI in slightly unusual way, that requires one LED data bit to be expanded to 3 bits to transmit. For a large number of LEDs this can be an issue in terms of RAM usage, but maybe that is not a big deal these days. By making use of DMA together with SPI, the RAM usage can be reduced anyway, by expanding the data in an interrupt routine as the transmission progresses.To transmit using timer PWM requires an even larger expansion of the data, where one LED bit has to be converted to a pulse duration, which could be 8, 16 or even 32 bits. The MaJerle code expands/converts the data for one RGB LED at a time (24 bits), so has to process interrupts at a fairly leisurely rate.I did see where somebody used timer PWM, with no DMA, processing one interrupt per bit of LED data. It was using about 50% of the available CPU time on a 168MHz processor to do this, but who cares if there is not much else to do?One thing I notice about these Nuvoton processors is the voltage range they can run on is 2.5V to 5.5V. The pixel type LEDs often run on 5V and may require level conversion if driven by a processor running on a lower voltage.

author: danchouzhou
author_rank: Contributor
timestamp: March 22, 2025, 05:20:53 am
content: I have discussed with others that PIO/PSIO can do the same thing, and the conclusion is that they require a larger area in the chip, which is very cost-effective in mass production products.

author: danchouzhou
author_rank: Contributor
timestamp: March 22, 2025, 06:08:46 am
content: Quote from: ozcar on March 22, 2025, 02:30:35 am5 V is indeed a highlight, but their development board NuMaker-NUC1263SD is 3.3 V by default.To be honest, I didn't change the voltage. I connected the NeoPixel Ring power supply to 5 V and the signal from NUC1263 is 3.3 V, and it worked.As you said, in actual use, 5V is more likely to ensure compatibility.

author: Kasper
author_rank: Frequent Contributor
timestamp: March 22, 2025, 06:46:24 am
content: I use RP2040 and Adafruit library for 8 strips and about 500 LEDs. It was easy to set up and works well. But if this MCU removes the need for external flash, level shifter and a regulator, that is attractive.

author: bilibili
author_rank: Newbie
timestamp: March 23, 2025, 05:49:54 am
content: the first mcu that support LLSI isfcm32

author: danchouzhou
author_rank: Contributor
timestamp: March 23, 2025, 06:11:58 am
content: Quote from: bilibili on March 23, 2025, 05:49:54 amI'm surprised. They even have the same diagram in their documents.But from the revision history, NUC1262 seems to be released earlier.