打印
[活动专区]

【AT-START-AT32F437测评】+ TencentOS-tiny+SPI_DMA驱动WS2812

[复制链接]
3236|0
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
本帖最后由 袁胜富 于 2023-1-2 21:35 编辑

一、前言  

         首先非常感谢雅特力提供的开发板,基于此我本人发表此篇文章。
二、项目介绍

         AT32F437主频高达288MHZ和大容量的Flash和SRAM,非常适合跑操作系统,在操作系统上我们可以做很多复杂的应用逻辑,其优势远远超过了裸机的轮询方法。因此我特别在AT32F437上跑TencentOS-tiny这个开源操作系统。在此篇文章中我只在系统上跑一个任务,运行WS2812,让其跑出不同模式。
三、WS2812的认识

Features and Benefits
 The control circuit and the LED share the only power source.
 Control circuit and RGB chip are integrated in a package of 5050 components, to form a complete addressable
pixel.
 Built-in signal reshaping circuit, after wave reshaping to the next driver, ensure wave-form distortion not
accumulate.
 Built-in electric reset circuit and power lost reset circuit.
 Each pixel of the three primary color can achieve 256 brightness display, completed 16777216 color full color
display, and scan frequency is of 2KHz.
 Cascading port transmission signal by single line.
 Any two point the distance not more than 5m transmission signal without any increase circuit.
 When the refresh rate is 30fps, cascade number are not less than 1024 pixels.
 Send data at speeds of 800Kbps.
 The color of the light is highly consistent, cost-effective.
 No need for external electric components and even the capacitor.
以上是数据手册摘抄下来的,然后来看看WS2812的数据格式
数据传输时间

数据序列和级联法

数据传输以及数据组成方式

通过以上资料我们得知一个灯的数据由24bit组成,GRB中G占位 ,R占8位,B占8位,G代表绿色,R代表红色,B代表蓝色,通过三种颜色可以显示出我们要的颜色。
WS2812B的数据传输速率位800K,1/8000000=1.25us。通过数据手册得知,0码的T0H时间为220ns~380ns,T0L时间为580ns~1us.1码的T1H时间为580ns~1us,T1L时间为220ns~380ns。WS2812使用方法一般为级联使用,由于本身拥有锁存器所以数据流经D1然后流经D2.。。。。

四、AT32F437的SPI和DMA理论


在此应用中我们只用到SPI的MOSI引脚,故SPI的工作模式设置为发送模式就行了,通过查阅芯片的Datasheet知道此芯片只用一个SPI为SPI1,MOSI为PA7引脚。
大家务必记住在使用SPI的时候一定要注意CS_SOFT模式是CS的内部电平应该置为高,只有这样SPI才能工作在主机模式,也就是MASTER Mode。
通过芯片手册知道SPI1挂载在APB2总线。在程序中配置AHB为288MHZ ,APB2为144MHZ。空口无凭请看下图

DMA分为DMA1和DMA2,在手册中了解到AT32F437的DMA很不错,通过DMAMux可以将任务DMAx通道连接任意不同外设,此外带有EDMA增强型DMA,这里只讲普通的DMA使用。DMA框架图如下


DMAMUX,DMA的多路复用框图如下


五、理论总结

       要将系统时钟设置为144M,SPI1时钟分频数设置为16,则SPI的通信频率为9M,1s/9M≈111ns 即传输一位数据的时间约为133纳秒(ns)8*111 =88ns 符合WS2812。
2*111= 222ns   6*111 = 666ns  符合WS281X芯片的通信时序。
1111 1100high level  (十六进制:0XFC)表示WS281X的1码
1100 0000  low level   (十六进制:0XC0)表示WS281X的0码
     SPI1的模式本项目只用发送模式,也就说只用到MOSI,没用到CS,MISO和SCK信号线。其中MOSI连接到PA7,在IO配置时应该选择复用模式,通过GPIO的复用表(如下图所示),知道PA7选择复用5才能将SPI1的MOSI功能体现。



六、程序编写

1.spi_dma_ws2812.h 头文件代码展示,在文件中#define  SPI_DMA_IRQ       1这个宏可以选择DMA传输数据失否需要DMA中断参与

#ifndef __SPI_DMA_WS2812_H
#define __SPI_DMA_WS2812_H
#include "stdlib.h"
#include "at32f435_437_board.h"
#include "stdint.h"
#include "tos_k.h"
/*
要将系统时钟设置为144M,SPI分频数设置为16,则SPI的通信频率为9M,1s/9M≈111ns 即传输一位数据的时间约为133纳秒(ns)8*111 =88ns 符合WS2812

2*111= 222ns   6*111 = 666ns  符合WS281X芯片的通信时序。

1111 1100high level  (十六进制:0XFC)表示WS281X的1码

1100 0000  low level   (十六进制:0XC0)表示WS281X的0码
程序头文件部分: 通过宏的方式定义了灯珠个数和WS281X的0码和1码。
*/

//  _____   

// |     |___|    1111 1100 high level

//  ___         

// |   |_____|   1100 0000  low level

#define  SPI_DMA_IRQ       1
#define Delay_ms(wait)   tos_task_delay(wait)
#define WS2812B   //选择WS2812B
#define PIXEL_NUM1  2     //RGB灯的数量                                         //灯带1灯数(组数)
#define PIXEL_NUM2  2                                                          //灯带2灯数(组数)
#define PIXEL_NUM3  2                                                          //灯带3灯数(组数)
#define PIXEL_NUM4  2                                                          //灯带4灯数(组数)

#define PIXEL_NUM  (PIXEL_NUM1+PIXEL_NUM2+PIXEL_NUM3+PIXEL_NUM4)//灯数统计
#define GRB  24   //3*8 //Red8位 Green8位 Blue8位 加起来24位

#ifdef WS2812B
#define WS_HIGH 0xFC
#endif
#define WS_LOW  0xC0
/*   
      R      G      B
红: 255     0      0
黄: 255    255     0
绿:  0     255     0
青:  0     255    255
蓝:  0      0     255
紫: 255     0     255
白: 255    255    255
*/

typedef union _rgbPixelBuffer
{
    struct
    {
                        uint8_t PixelBuffer1[PIXEL_NUM1][GRB];
                        uint8_t PixelBuffer2[PIXEL_NUM2][GRB];
                        uint8_t PixelBuffer3[PIXEL_NUM3][GRB];
                        uint8_t PixelBuffer4[PIXEL_NUM4][GRB];
    }buff;
    uint8_t All_Buffer[PIXEL_NUM][GRB];
}RGB_PixelBuffer,*PRGB_PixelBuffer;
void WS281x_Init(void);
void WS281x_CloseAll(void);
uint32_t WS281x_Color(uint8_t red, uint8_t green, uint8_t blue);
void WS281x_SetPixelColor(uint16_t n, uint32_t GRBColor);
void WS281x_SetPixelRGB(uint16_t n ,uint8_t red, uint8_t green, uint8_t blue);
void WS281x_Show(void);
void WS281x_RainbowCycle(uint8_t wait);
void WS281x_TheaterChase(uint32_t c, uint8_t wait);
void WS281x_ColorWipe(uint32_t c, uint8_t wait);
void WS281x_Rainbow(uint8_t wait);
void WS281x_TheaterChaseRainbow(uint8_t wait);
void RGB_DEBUG_TEST(void);
#endif
2.spi_dma_ws2812.c代码展示
#include "spi_dma_ws2812.h"
#include "string.h"
#include "stdlib.h"
#include "stdbool.h"
RGB_PixelBuffer pixelBuffer;
#if SPI_DMA_IRQ
void DMA1_Channel2_IRQHandler(void);
volatile bool app_dma_xfer_done = false; /* DMA xfer done flag. */
#endif

void WS281x_Init(void)
{
        /*Set GPIO*/
  gpio_init_type gpio_initstructure;
  spi_init_type spi_init_struct;
  dma_init_type dma_init_struct;
  crm_periph_clock_enable(CRM_SPI1_PERIPH_CLOCK, TRUE);
  crm_periph_clock_enable(CRM_GPIOA_PERIPH_CLOCK, TRUE);
  crm_periph_clock_enable(CRM_DMA1_PERIPH_CLOCK, TRUE);
        
  /* mosi */
  gpio_initstructure.gpio_out_type       = GPIO_OUTPUT_PUSH_PULL;
  gpio_initstructure.gpio_mode           = GPIO_MODE_MUX;
  gpio_initstructure.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
  gpio_initstructure.gpio_pull           = GPIO_PULL_UP;
  gpio_initstructure.gpio_pins           = GPIO_PINS_7;
  gpio_init(GPIOA, &gpio_initstructure);
  gpio_pin_mux_config(GPIOA, GPIO_PINS_SOURCE7, GPIO_MUX_5);
        
  dma_reset(DMA1_CHANNEL2);
  dma_default_para_init(&dma_init_struct);
  dma_init_struct.buffer_size = 0;
  dma_init_struct.direction = DMA_DIR_MEMORY_TO_PERIPHERAL ;
  dma_init_struct.memory_base_addr = (uint32_t)&pixelBuffer;
  dma_init_struct.memory_data_width = DMA_MEMORY_DATA_WIDTH_BYTE;
  dma_init_struct.memory_inc_enable = TRUE;
  dma_init_struct.peripheral_base_addr = (uint32_t)(&SPI1->dt);
  dma_init_struct.peripheral_data_width = DMA_PERIPHERAL_DATA_WIDTH_BYTE;
  dma_init_struct.peripheral_inc_enable = FALSE;
  dma_init_struct.priority = DMA_PRIORITY_VERY_HIGH;
  dma_init_struct.loop_mode_enable = FALSE;
  dma_init(DMA1_CHANNEL2, &dma_init_struct);
  dmamux_enable(DMA1, TRUE);
  dmamux_init(DMA1MUX_CHANNEL2, DMAMUX_DMAREQ_ID_SPI1_TX);
  spi_i2s_dma_transmitter_enable(SPI1, TRUE);
  dma_channel_enable(DMA1_CHANNEL2, TRUE);
  while(dma_flag_get(DMA1_FDT2_FLAG) != RESET);
  dma_flag_clear(DMA1_FDT2_FLAG);
  dma_channel_enable(DMA1_CHANNEL2, FALSE);
  spi_i2s_dma_transmitter_enable(SPI1, TRUE);
#if SPI_DMA_IRQ
  dma_interrupt_enable(DMA1_CHANNEL2,DMA_FDT_INT,TRUE);
        dma_flag_clear(DMA1_FDT2_FLAG);
  nvic_irq_enable(DMA1_Channel2_IRQn, 1, 0);
#endif
  spi_default_para_init(&spi_init_struct);
  spi_init_struct.transmission_mode = SPI_TRANSMIT_HALF_DUPLEX_TX;
  spi_init_struct.master_slave_mode = SPI_MODE_MASTER;
  spi_init_struct.mclk_freq_division = SPI_MCLK_DIV_16;
  spi_init_struct.first_bit_transmission = SPI_FIRST_BIT_MSB;
  spi_init_struct.frame_bit_num = SPI_FRAME_8BIT;
  spi_init_struct.clock_polarity = SPI_CLOCK_POLARITY_LOW;
  spi_init_struct.clock_phase = SPI_CLOCK_PHASE_1EDGE;
  spi_init_struct.cs_mode_selection = SPI_CS_SOFTWARE_MODE;
  spi_init(SPI1, &spi_init_struct);
        spi_crc_polynomial_set(SPI1, 7);
  spi_crc_enable(SPI1, TRUE);
  spi_software_cs_internal_level_set(SPI1,SPI_SWCS_INTERNAL_LEVEL_HIGHT);//主机模式 SPI_CS_SOFTWARE_MODE SPI_SWCS_INTERNAL_LEVEL_HIGHT
  spi_enable(SPI1, TRUE);
        WS281x_CloseAll();  //关闭全部的灯
  Delay_ms(100); //关闭全部的灯需要一定的时间

}

//更新颜色显示(在设定颜色后将颜色数据存入缓存只有执行该函数后才会进行显示)
void WS281x_Show(void)
{

#if SPI_DMA_IRQ
        app_dma_xfer_done = false;
        dma_channel_enable(DMA1_CHANNEL2, FALSE);
        dma_data_number_set(DMA1_CHANNEL2, PIXEL_NUM * GRB);
        dma_channel_enable(DMA1_CHANNEL2, TRUE);
        while(!app_dma_xfer_done);
        SPI1->dt = 0x00;
#else
        // 检查DMA发送通道内是否还有数据
        while(dma_data_number_get(DMA1_CHANNEL2)){};
        dma_channel_enable(DMA1_CHANNEL2, FALSE);
        dma_data_number_set(DMA1_CHANNEL2, PIXEL_NUM * GRB);
        dma_channel_enable(DMA1_CHANNEL2, TRUE);
        while(dma_data_number_get(DMA1_CHANNEL2)){};
        __NOP();
        __NOP();   
        __NOP();
        SPI1->dt = 0x00;
        while(dma_flag_get(DMA1_FDT2_FLAG) == RESET){};
        dma_flag_clear(DMA1_FDT2_FLAG);
        dma_channel_enable(DMA1_CHANNEL2, FALSE);
#endif

}
//配置完成之后便可以构思底层控制函数了,为了方便多个LED灯珠的可控制首先要定义一个缓冲区pixelBuffer[PIXEL_NUM][24]\
通过设定颜色将数据填入缓冲区再通过更新函数将数据传入到LED灯珠上。
//关闭所有灯珠
void WS281x_CloseAll(void)
{
  uint16_t i;
  uint8_t j;

  for(i = 0; i < PIXEL_NUM; ++i)
  {
    for(j = 0; j < 24; ++j)
    {
      pixelBuffer.All_Buffer[j] = WS_LOW;
    }
  }
  WS281x_Show();
}


uint32_t WS281x_Color(uint8_t red, uint8_t green, uint8_t blue)
{
  return green << 16 | red << 8 | blue;
}

void WS281x_SetPixelColor(uint16_t n, uint32_t GRBColor)
{
  uint8_t i;
  if(n < PIXEL_NUM)
  {
    for(i = 0; i < GRB; i++)
    {
      pixelBuffer.All_Buffer[n] = ((GRBColor << i) & 0x800000) ? WS_HIGH : WS_LOW;
    }
  }
}

void WS281x_SetPixelRGB(uint16_t n ,uint8_t red, uint8_t green, uint8_t blue)
{
  uint8_t i;

  if(n < PIXEL_NUM)
  {
    for(i = 0; i < GRB; ++i)
    {
      pixelBuffer.All_Buffer[n] = (((WS281x_Color(red,green,blue) << i) & 0X800000) ? WS_HIGH : WS_LOW);
    }
  }
}

// Input a value 0 to 255 to get a color value.
// The colours are a transition r - g - b - back to r.
uint32_t WS281x_Wheel(uint8_t wheelPos) {
  wheelPos = 255 - wheelPos;
  if(wheelPos < 85) {
    return WS281x_Color(255 - wheelPos * 3, 0, wheelPos * 3);
  }
  if(wheelPos < 170) {
    wheelPos -= 85;
    return WS281x_Color(0, wheelPos * 3, 255 - wheelPos * 3);
  }
  wheelPos -= 170;
  return WS281x_Color(wheelPos * 3, 255 - wheelPos * 3, 0);
}

// Fill the dots one after the other with a color
void WS281x_ColorWipe(uint32_t c, uint8_t wait) {
  for(uint16_t i=0; i<PIXEL_NUM; i++) {
    WS281x_SetPixelColor(i, c);
    WS281x_Show();
    Delay_ms(wait);
  }
}

void WS281x_Rainbow(uint8_t wait) {
  uint16_t i, j;

  for(j=0; j<256; j++) {
    for(i=0; i<PIXEL_NUM; i++) {
      WS281x_SetPixelColor(i, WS281x_Wheel((i+j) & 255));
    }
    WS281x_Show();
    Delay_ms(wait);
  }
}

// Slightly different, this makes the rainbow equally distributed throughout
void WS281x_RainbowCycle(uint8_t wait) {
  uint16_t i, j;

  for(j=0; j<256*5; j++) { // 5 cycles of all colors on wheel
    for(i=0; i< PIXEL_NUM; i++) {
      WS281x_SetPixelColor(i,WS281x_Wheel(((i * 256 / PIXEL_NUM) + j) & 255));
    }
    WS281x_Show();
    Delay_ms(wait);
  }
}

//Theatre-style crawling lights.
void WS281x_TheaterChase(uint32_t c, uint8_t wait) {
  for (int j=0; j<10; j++) {  //do 10 cycles of chasing
    for (int q=0; q < 3; q++) {
      for (uint16_t i=0; i < PIXEL_NUM; i=i+3) {
        WS281x_SetPixelColor(i+q, c);    //turn every third pixel on
      }
      WS281x_Show();

      Delay_ms(wait);

      for (uint16_t i=0; i < PIXEL_NUM; i=i+3) {
        WS281x_SetPixelColor(i+q, 0);        //turn every third pixel off
      }
    }
  }
}

//Theatre-style crawling lights with rainbow effect
void WS281x_TheaterChaseRainbow(uint8_t wait) {
  for (int j=0; j < 256; j++) {     // cycle all 256 colors in the wheel
    for (int q=0; q < 3; q++) {
      for (uint16_t i=0; i < PIXEL_NUM; i=i+3) {
        WS281x_SetPixelColor(i+q, WS281x_Wheel( (i+j) % 255));    //turn every third pixel on
      }
      WS281x_Show();

      Delay_ms(wait);

      for (uint16_t i=0; i < PIXEL_NUM; i=i+3) {
        WS281x_SetPixelColor(i+q, 0);        //turn every third pixel off
      }
    }
  }
}


// Slightly different, this makes the rainbow equally distributed throughout
void WS2812_RainbowRotate(uint16_t wait) {
        uint16_t i, j;

        for (j = 0; j < 256 * 5; j++) { // 5 cycles of all colors on wheel
                for (i = 0; i < PIXEL_NUM; i++) {
                        WS281x_SetPixelColor(i,  WS281x_Wheel(((i * 256 / PIXEL_NUM) + j) & 255));
                }
                WS281x_Show();
    Delay_ms(wait);
        }
}

#if SPI_DMA_IRQ
/* ISP for SPI1_TX DMA done. */
void DMA1_Channel2_IRQHandler(void)
{
        if (tos_knl_is_running())
  {
    tos_knl_irq_enter();
    if(dma_flag_get(DMA1_FDT2_FLAG) != RESET)
    {
        dma_channel_enable(DMA1_CHANNEL2, FALSE);
        app_dma_xfer_done = true;
        dma_flag_clear(DMA1_FDT2_FLAG);
    }
    tos_knl_irq_leave();
  }
}
#endif

void RGB_DEBUG_TEST(void)
{
        int i,j;
        for(i=0;i<3;i++)
        {
               
                for(j=0;j<8;j++)
                {
                        if(i==0)
                        {
                                WS281x_ColorWipe(WS281x_Color(255, 0, 255), 1); // Red
                        }
                        else if(i==1)
                        {
                                WS281x_ColorWipe(WS281x_Color(0, 255, 255), 1); // Green
                        }
                        else
                        {
                                WS281x_ColorWipe(WS281x_Color(255, 255, 0), 1); // Blue
                        }
                }
        }
                for(i=0;i<3;i++)
        {
               
                for(j=0;j<8;j++)
                {
                        if(i==0)
                        {
                                WS281x_ColorWipe(WS281x_Color(255, 0, 0), 10); // Red
                        }
                        else if(i==1)
                        {
                                WS281x_ColorWipe(WS281x_Color(0, 255, 0), 10); // Green
                        }
                        else
                        {
                                WS281x_ColorWipe(WS281x_Color(0, 0, 255), 10); // Blue
                        }
                }
        }
                for(i=0;i<3;i++)
        {
               
                for(j=0;j<8;j++)
                {
                        if(i==0)
                        {
                                WS281x_ColorWipe(WS281x_Color(255, 0, 0), 10); // Red
                                Delay_ms(100);
                                WS281x_ColorWipe(WS281x_Color(0, 255, 0), 10); // Green
                        }
                        else if(i==1)
                        {
                                WS281x_ColorWipe(WS281x_Color(0, 255, 0), 10); // Green
                                Delay_ms(100);
                                WS281x_ColorWipe(WS281x_Color(255, 0, 0), 10); // Red
                        }
                        else
                        {
                                WS281x_ColorWipe(WS281x_Color(0, 0, 255), 10); // Blue
                                Delay_ms(100);
                                WS281x_ColorWipe(WS281x_Color(0, 255, 0), 10); // Green
                                Delay_ms(100);
                                WS281x_ColorWipe(WS281x_Color(0, 0, 255), 10); // Blue
                                Delay_ms(100);
                                WS281x_ColorWipe(WS281x_Color(255, 0, 0), 10); // Red
                        }
                }
        }
        WS2812_RainbowRotate(2);
        // Some example procedures showing how to display to the pixels:
        WS281x_ColorWipe(WS281x_Color(255, 0, 0), 10); // Red
        WS281x_ColorWipe(WS281x_Color(0, 255, 0), 10); // Green
        WS281x_ColorWipe(WS281x_Color(0, 0, 255), 10); // Blue


        WS281x_TheaterChase(WS281x_Color(127, 127, 127), 10); // White
        WS281x_TheaterChase(WS281x_Color(127, 0, 0), 10); // Red
        WS281x_TheaterChase(WS281x_Color(0, 0, 127), 10); // Blue

        WS281x_Rainbow(10);
        WS281x_RainbowCycle(10);
        WS281x_TheaterChaseRainbow(10);

}
3.main.c代码展示
#include "at32f435_437_board.h"
#include "at32f435_437_clock.h"
#include <spi_dma_ws2812.h>

#include "tos_k.h"

#define DELAY                            100
#define FAST                             1
#define SLOW                             4
uint8_t g_speed = FAST;

#define APPLICATION_TASK_STK_SIZE       1024
k_task_t application_task;
uint8_t application_task_stk[APPLICATION_TASK_STK_SIZE];

extern void application_entry(void *arg);

__weak void application_entry(void *arg)
{
                WS281x_Init();
    while (1)
                {
                        at32_led_toggle(LED2);
                        tos_task_delay(g_speed * DELAY);
                        at32_led_toggle(LED3);
                        tos_task_delay(g_speed * DELAY);
                        at32_led_toggle(LED4);
                        tos_task_delay(g_speed * DELAY);
                        RGB_DEBUG_TEST();
                        printf("LED_Toggle DEMO!!!\r\n");
    }
}



void button_exint_init(void);
void button_isr(void);

/**
  * @brief  configure button exint
  * @param  none
  * @retval none
  */
void button_exint_init(void)
{
  exint_init_type exint_init_struct;

  crm_periph_clock_enable(CRM_SCFG_PERIPH_CLOCK, TRUE);
  scfg_exint_line_config(SCFG_PORT_SOURCE_GPIOA, SCFG_PINS_SOURCE0);

  exint_default_para_init(&exint_init_struct);
  exint_init_struct.line_enable = TRUE;
  exint_init_struct.line_mode = EXINT_LINE_INTERRUPUT;
  exint_init_struct.line_select = EXINT_LINE_0;
  exint_init_struct.line_polarity = EXINT_TRIGGER_RISING_EDGE;
  exint_init(&exint_init_struct);

  nvic_priority_group_config(NVIC_PRIORITY_GROUP_4);
  nvic_irq_enable(EXINT0_IRQn, 0, 0);
}

/**
  * @brief  button handler function
  * @param  none
  * @retval none
  */
void button_isr(void)
{
  /* delay 5ms */
  tos_task_delay(5);

  /* clear interrupt pending bit */
  exint_flag_clear(EXINT_LINE_0);

  /* check input pin state */
  if(SET == gpio_input_data_bit_read(USER_BUTTON_PORT, USER_BUTTON_PIN))
  {
    if(g_speed == SLOW)
      g_speed = FAST;
    else
      g_speed = SLOW;
  }
}

/**
  * @brief  exint0 interrupt handler
  * @param  none
  * @retval none
  */
void EXINT0_IRQHandler(void)
{
        if (tos_knl_is_running())
  {
    tos_knl_irq_enter();
    button_isr();
    tos_knl_irq_leave();
  }

}


crm_clocks_freq_type crm_clocks_freq_struct = {0};
/**
  * @brief  main function.
  * @param  none
  * @retval none
  */
int main(void)
{
        nvic_priority_group_config(NVIC_PRIORITY_GROUP_4);
  system_clock_config();
  at32_board_init();
  button_exint_init();
          /* get system clock */
  crm_clocks_freq_get(&crm_clocks_freq_struct);
        printf("ahb_freq=%d\r\n",crm_clocks_freq_struct.ahb_freq);
        printf("apb1_freq=%d\r\n",crm_clocks_freq_struct.apb1_freq);
        printf("apb2_freq=[url=]Removeformat[/url]%d\r\n",crm_clocks_freq_struct.apb2_freq);
        printf("sclk_freq=%d\r\n",crm_clocks_freq_struct.sclk_freq);
        printf("Welcome to TencentOS tiny(%s)\r\n", TOS_VERSION);
        tos_knl_init(); // TencentOS Tiny kernel initialize
        tos_task_create(&application_task, "application_task", application_entry, NULL, 0, application_task_stk, APPLICATION_TASK_STK_SIZE, 0);
        tos_knl_start();
  while(1)
  {

  }
}

七、效果展示



    视频效果图已经发布在了Bilibili,如想了解请移步:【AT32F437的SPI+DMA驱动WS2812B.-哔哩哔哩】 https://b23.tv/YLAgjLK
    相关代码工程已经放在了附件里,有兴趣的朋友请下载烧录试试吧,最后有的朋友会问为啥不用TIM+DMA的方式实现呢,我试过,奈何怎么的调不出来,关于TIM+DMA的代码我一并放在附件里,有兴趣的伙伴我们一起来完善它。假期马上结束了,又要投入到紧张的工作中,祝大家新的一年,万事如意,好运连连。



  

AT32F437-TencentOS-tiny-TIM+DMA_W281B.zip

3.72 MB

AT32F437-TencentOS-tiny-SPI+DMA_W281B.zip

3.73 MB

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

24

主题

132

帖子

2

粉丝