[DemoCode下载] 通过PDMA使用LLSI接口控制WS2812彩色LED

[复制链接]
1566|9
 楼主| yiyigirl2014 发表于 2024-1-28 18:40 | 显示全部楼层 |阅读模式
  1. /**************************************************************************//**
  2. * [url=home.php?mod=space&uid=288409]@file[/url]     main.c
  3. * [url=home.php?mod=space&uid=895143]@version[/url]  V3.00
  4. * [url=home.php?mod=space&uid=247401]@brief[/url]    This is a LLSI demo for marquee display in PDMA mode.
  5. *           It needs to be used with WS2812 LED strip.
  6. *
  7. * @note
  8. * [url=home.php?mod=space&uid=17282]@CopyRight[/url] SPDX-License-Identifier: Apache-2.0
  9. * @copyright Copyright (C) 2021 Nuvoton Technology Corp. All rights reserved.
  10. *****************************************************************************/
  11. #include <stdio.h>
  12. #include "NuMicro.h"

  13. #define TEST_COUNT 5

  14. volatile uint32_t g_au32RED_Marquee0[TEST_COUNT] = {0x000000FF, 0x00000000, 0x00000000, 0x00000000, 0x00000000};
  15. volatile uint32_t g_au32RED_Marquee1[TEST_COUNT] = {0xFF000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000};
  16. volatile uint32_t g_au32RED_Marquee2[TEST_COUNT] = {0x00000000, 0x00FF0000, 0x00000000, 0x00000000, 0x00000000};
  17. volatile uint32_t g_au32RED_Marquee3[TEST_COUNT] = {0x00000000, 0x00000000, 0x0000FF00, 0x00000000, 0x00000000};
  18. volatile uint32_t g_au32RED_Marquee4[TEST_COUNT] = {0x00000000, 0x00000000, 0x00000000, 0x000000FF, 0x00000000};
  19. volatile uint32_t g_au32RED_Marquee5[TEST_COUNT] = {0x00000000, 0x00000000, 0x00000000, 0xFF000000, 0x00000000};
  20. volatile uint32_t g_au32RED_Marquee6[TEST_COUNT] = {0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000};
  21. volatile uint32_t g_u32PatternToggle = 0;

  22. void SYS_Init(void)
  23. {
  24.     /*---------------------------------------------------------------------------------------------------------*/
  25.     /* Init System Clock                                                                                       */
  26.     /*---------------------------------------------------------------------------------------------------------*/
  27.     /* Enable HIRC clock */
  28.     CLK_EnableXtalRC(CLK_PWRCTL_HIRCEN_Msk);

  29.     /* Wait for HIRC clock ready */
  30.     CLK_WaitClockReady(CLK_STATUS_HIRCSTB_Msk);

  31.     /* Set core clock to 72MHz */
  32.     CLK_SetCoreClock(72000000);

  33.     /* Enable UART0 module clock */
  34.     CLK_EnableModuleClock(UART0_MODULE);

  35.     /* Select UART0 module clock source as HIRC/2 and UART0 module clock divider as 1 */
  36.     CLK_SetModuleClock(UART0_MODULE, CLK_CLKSEL1_UART0SEL_HIRC_DIV2, CLK_CLKDIV0_UART0(1));

  37.     /* Enable LLSI0 module clock */
  38.     CLK_EnableModuleClock(LLSI0_MODULE);

  39.     /* Enable PDMA peripheral clock */
  40.     CLK_EnableModuleClock(PDMA_MODULE);

  41.     /*---------------------------------------------------------------------------------------------------------*/
  42.     /* Init I/O Multi-function                                                                                 */
  43.     /*---------------------------------------------------------------------------------------------------------*/
  44.     /* Set PB multi-function pins for UART0 RXD and TXD */
  45.     SYS->GPB_MFPH = (SYS->GPB_MFPH & (~(UART0_RXD_PB12_Msk | UART0_TXD_PB13_Msk))) | UART0_RXD_PB12 | UART0_TXD_PB13;

  46.     /* Set PB multi-function pins for LLSI0 */
  47.     SYS->GPB_MFPH = (SYS->GPB_MFPH & ~(SYS_GPB_MFPH_PB15MFP_Msk)) | SYS_GPB_MFPH_PB15MFP_LLSI0_OUT;
  48. }

  49. void UART0_Init()
  50. {
  51.     /*---------------------------------------------------------------------------------------------------------*/
  52.     /* Init UART                                                                                               */
  53.     /*---------------------------------------------------------------------------------------------------------*/
  54.     /* Reset UART0 module */
  55.     SYS_ResetModule(UART0_RST);

  56.     /* Configure UART0 and set UART0 Baudrate */
  57.     UART_Open(UART0, 115200);
  58. }

  59. void LLSI_Init(void)
  60. {
  61.     /*---------------------------------------------------------------------------------------------------------*/
  62.     /* Init LLSI                                                                                               */
  63.     /*---------------------------------------------------------------------------------------------------------*/
  64.     /* Configure as PDMA mode, GRB output format, 6 pixels in a frame and idle output low */
  65.     /* Set clock divider. LLSI clock rate = 72MHz */
  66.     /* Set data transfer period. T_Period = 1250ns */
  67.     /* Set duty period. T_T0H = 400ns; T_T1H = 850ns */
  68.     /* Set reset command period. T_ResetPeriod = 50000ns */
  69.     LLSI_Open(LLSI0, LLSI_MODE_PDMA, LLSI_FORMAT_GRB, 72000000, 1250, 400, 850, 50000, 6, LLSI_IDLE_LOW);

  70.     /* Enable reset command function */
  71.     LLSI_ENABLE_RESET_COMMAND(LLSI0);
  72. }

  73. /*---------------------------------------------------------------------------------------------------------*/
  74. /* MAIN function                                                                                           */
  75. /*---------------------------------------------------------------------------------------------------------*/
  76. int main(void)
  77. {
  78.     /* Unlock protected registers */
  79.     SYS_UnlockReg();

  80.     /* Init System, IP clock and multi-function I/O. */
  81.     SYS_Init();

  82.     /* Lock protected registers */
  83.     SYS_LockReg();

  84.     /* Init UART0 for printf */
  85.     UART0_Init();

  86.     printf("\n\nCPU [url=home.php?mod=space&uid=72445]@[/url] %d Hz\n", SystemCoreClock);
  87.     printf("+------------------------------------------------+\n");
  88.     printf("|      LLSI Marquee Sample Code (PDMA Mode)      |\n");
  89.     printf("+------------------------------------------------+\n");
  90.     printf("The first to sixth LEDs will flash red in sequence.\n\n");

  91.     /* Reset PDMA module */
  92.     SYS_ResetModule(PDMA_RST);

  93.     /* Open Channel 0 */
  94.     PDMA_Open(1 << 0);
  95.     /* Transfer count is TEST_COUNT, transfer width is 32 bits(one word) */
  96.     PDMA_SetTransferCnt(0, PDMA_WIDTH_32, TEST_COUNT);
  97.     /* Transfer type is single transfer */
  98.     PDMA_SetBurstType(0, PDMA_REQ_SINGLE, 0);
  99.     /* Set source address is g_au32RED_Marquee0, destination address is &LLSI0->DATA */
  100.     PDMA_SetTransferAddr(0, (uint32_t)g_au32RED_Marquee0, PDMA_SAR_INC, (uint32_t)&LLSI0->DATA, PDMA_DAR_FIX);
  101.     /* Request source is LLSI0 */
  102.     PDMA_SetTransferMode(0, PDMA_LLSI0, FALSE, 0);

  103.     /* Init LLSI */
  104.     LLSI_Init();

  105.     while(g_u32PatternToggle < 7)
  106.     {
  107.         CLK_SysTickDelay(100000);

  108.         g_u32PatternToggle++;

  109.         /* Reset PDMA module */
  110.         SYS_ResetModule(PDMA_RST);

  111.         /* Open Channel 0 */
  112.         PDMA_Open(1 << 0);
  113.         /* Transfer count is TEST_COUNT, transfer width is 32 bits(one word) */
  114.         PDMA_SetTransferCnt(0, PDMA_WIDTH_32, TEST_COUNT);
  115.         /* Transfer type is single transfer */
  116.         PDMA_SetBurstType(0, PDMA_REQ_SINGLE, 0);

  117.         if(g_u32PatternToggle == 1)
  118.         {
  119.             /* Set source address is g_au32RED_Marquee1, destination address is &LLSI0->DATA */
  120.             PDMA_SetTransferAddr(0, (uint32_t)g_au32RED_Marquee1, PDMA_SAR_INC, (uint32_t)&LLSI0->DATA, PDMA_DAR_FIX);
  121.         }
  122.         else if(g_u32PatternToggle == 2)
  123.         {
  124.             /* Set source address is g_au32RED_Marquee2, destination address is &LLSI0->DATA */
  125.             PDMA_SetTransferAddr(0, (uint32_t)g_au32RED_Marquee2, PDMA_SAR_INC, (uint32_t)&LLSI0->DATA, PDMA_DAR_FIX);
  126.         }
  127.         else if(g_u32PatternToggle == 3)
  128.         {
  129.             /* Set source address is g_au32RED_Marquee3, destination address is &LLSI0->DATA */
  130.             PDMA_SetTransferAddr(0, (uint32_t)g_au32RED_Marquee3, PDMA_SAR_INC, (uint32_t)&LLSI0->DATA, PDMA_DAR_FIX);
  131.         }
  132.         else if(g_u32PatternToggle == 4)
  133.         {
  134.             /* Set source address is g_au32RED_Marquee4, destination address is &LLSI0->DATA */
  135.             PDMA_SetTransferAddr(0, (uint32_t)g_au32RED_Marquee4, PDMA_SAR_INC, (uint32_t)&LLSI0->DATA, PDMA_DAR_FIX);
  136.         }
  137.         else if(g_u32PatternToggle == 5)
  138.         {
  139.             /* Set source address is g_au32RED_Marquee5, destination address is &LLSI0->DATA */
  140.             PDMA_SetTransferAddr(0, (uint32_t)g_au32RED_Marquee5, PDMA_SAR_INC, (uint32_t)&LLSI0->DATA, PDMA_DAR_FIX);
  141.         }
  142.         else if(g_u32PatternToggle == 6)
  143.         {
  144.             /* Set source address is g_au32RED_Marquee6, destination address is &LLSI0->DATA */
  145.             PDMA_SetTransferAddr(0, (uint32_t)g_au32RED_Marquee6, PDMA_SAR_INC, (uint32_t)&LLSI0->DATA, PDMA_DAR_FIX);
  146.         }

  147.         /* Request source is LLSI0 */
  148.         PDMA_SetTransferMode(0, PDMA_LLSI0, FALSE, 0);
  149.     }

  150.     /* Close LLSI0 */
  151.     LLSI_Close(LLSI0);

  152.     printf("Exit LLSI sample code.\n");

  153.     while(1);
  154. }


 楼主| yiyigirl2014 发表于 2024-1-28 18:41 | 显示全部楼层
这真是一个创举,可以方便的用于控制LED彩色灯条,在一定程度可以实现丰富的彩灯控制,甚至楼宇彩色照明控制。比如作为显示器用。
小明的同学 发表于 2024-1-28 19:51 | 显示全部楼层
这下方便多了,这个技术好。
呐咯密密 发表于 2024-1-28 20:07 来自手机 | 显示全部楼层
新唐的外设名字和别人不一样
LEDyyds 发表于 2024-1-28 23:48 | 显示全部楼层
LLSI是不是就是SPI啊
埃娃 发表于 2024-1-29 10:09 来自手机 | 显示全部楼层
LEDyyds 发表于 2024-1-28 23:48
LLSI是不是就是SPI啊

不是,这两个不一样
少女诗篇 发表于 2025-9-27 14:53 | 显示全部楼层
利用 PDMA 自动传输数据,经 LLSI 接口按 WS2812 时序生成高低电平,实现对 RGB LED 的精准控制,提升效率,减少 CPU 占用。
小岛西岸来信 发表于 2025-9-28 11:42 | 显示全部楼层
先配置新唐 MCU 的 LLSI 接口为 WS2812 时序(如 800kHz 通信速率),再使能 PDMA 并关联 LLSI 发送通道。将 LED 色彩数据(24 位 GRB 格式)存入 PDMA 缓冲区,设置 PDMA 传输触发源为 LLSI 发送完成、传输长度等参数。启动 PDMA 后,无需 CPU 干预,PDMA 自动将数据通过 LLSI 发送至 WS2812,实现低占用率的 LED 色彩控制。
桃乐丝 发表于 2025-10-2 17:44 | 显示全部楼层
通过 PDMA(可编程直接内存访问)结合 LLSI(低功耗串行接口)控制 WS2812 时,先配置 LLSI 时序匹配 WS2812 的通信协议(高低电平脉冲编码),将 LED 色彩数据存入内存,再设置 PDMA 通道,让其自动将数据经 LLSI 发送,无需 CPU 干预,减少资源占用,实现高效、无闪烁的彩色 LED 控制。
我趴在云边 发表于 2025-10-17 15:14 | 显示全部楼层
通过 PDMA 结合 LLSI 接口控制 WS2812,可实现高效无 CPU 干预的 LED 驱动。LLSI 生成 WS2812 所需的特定时序(如 T0H/T1H 高电平、低电平时间),PDMA 则自动从数据缓冲区搬运 RGB 颜色数据至 LLSI,无需 CPU 频繁中断处理。这种方式能减少 CPU 占用率,避免时序紊乱,支持多颗 WS2812 级联,实现流畅的彩色光效控制。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

230

主题

3676

帖子

10

粉丝
快速回复 在线客服 返回列表 返回顶部