首页 > 其他分享 >DMA + SPI 刷WS2812

DMA + SPI 刷WS2812

时间:2023-02-19 22:56:56浏览次数:34  
标签:DMA WS2812 SPI InitStructure position byte

#include "WS2812.h"

#define WS2812_DAT_ZERO_16B  0xE000 //1110000000000000, H=3*111=333ns, L=13*111=1.4us
#define WS2812_DAT_ONE_16B   0xFFF8 //1111111111111000, H=13*111=1.4us, L=3*111=333ns

/**
 * @brief 将要通过DMA发送的数据,一个16位变量代表1位数据。
 *
 * @note 一颗LED需要24位,终止信号需要20位。
 */
 
static uint8_t WS2812_Buffer[WS2812_MAX_LED_COUNT * 24 * 3/2 + 1] = {0};

/**
 * @brief 将8位的颜色数据转换为8个uint16_t的位数据,并存入DMA缓冲区中
 *
 * @param data 要转换的8位颜色
 * @param byte_position 当前颜色所在的输入缓冲区字节位置
 */
#if 0
static void WS2812_ColorToBuffer(uint8_t data, uint16_t byte_position)
{
    uint32_t bit_position = byte_position * 8;
    for (uint8_t i = 0x80; i >= 0x01; i >>= 1) {
        //WS2812_Buffer[bit_position++] = ((data & i) ? WS2812_DAT_ONE_16B : WS2812_DAT_ZERO_16B);
		WS2812_Buffer[bit_position++] = ((data & i) ? 0xE0 : 0xFC);
    }
}


/**
 * @brief 向DMA缓冲区的末尾添加20个0x0000的uint16_t,以生成复位信号
 *
 * @param byte_position 当前所在的输入缓冲区字节位置
 */
static void WS2812_AppendStopPulse(uint16_t byte_position)
{
    uint32_t bit_position = byte_position * 8;
    for (uint8_t i = 0; i < 20; i ++) { // 20 * 16bits * 111ns = 350us
        WS2812_Buffer[bit_position++] = 0x0000;
    }
}
#endif

void WS2812_SPI_DMA_Init(void)
{
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_SPI1, ENABLE);

    /* 初始化DMA1通道3 用于SPI1发送 */
    DMA_InitTypeDef DMA_InitStructure;
    DMA_DeInit(DMA1_Channel3);
    DMA_InitStructure.DMA_BufferSize = 0;
    DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t) &(SPI1->DR);
    DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t) &WS2812_Buffer;
    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
    DMA_InitStructure.DMA_Priority = DMA_Priority_Low;
    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
    DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
    DMA_Init(DMA1_Channel3, &DMA_InitStructure);

    /* 初始化化PA7为SPI1_MOSI */
    GPIO_InitTypeDef GPIO_InitStructure;
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStructure);

    /* 初始化化SPI1为仅发送模式 */
    SPI_InitTypeDef SPI_InitStructure;
    SPI_I2S_DeInit(SPI1);
    SPI_InitStructure.SPI_Direction = SPI_Direction_1Line_Tx;
    SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
    SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
    SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;
    SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;
    SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
    SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_8; //72MHz/8 = 9MHz, 1bit=111.1ns
    SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
    SPI_InitStructure.SPI_CRCPolynomial = 7;
    SPI_Init(SPI1, &SPI_InitStructure);
    SPI_I2S_DMACmd(SPI1, SPI_I2S_DMAReq_Tx, ENABLE); //使能SPI1的DMA发送
    SPI_Cmd(SPI1, ENABLE);
}

// MSB	  MSB
// 00   F0_0F_00
// 01	F0_0F_F0
// 10	FF_0F_00
// 11   FF_0F_F0


// MSB	  LSB
// 00   00_0F_F0
// 01	F0_0F_F0
// 10	00_0F_FF
// 11   F0_0F_FF


static const uint32_t table[4] = {
	0x000FF0,
	0xF00FF0,
	0x000FFF,
	0xF00FFF,
};

void WS2812_Write(uint8_t *led_color_buffer, uint16_t led_count)
{
    while (DMA_GetCurrDataCounter(DMA1_Channel3) != 0); //等待上次传输完成

    uint16_t byte_count = led_count > WS2812_MAX_LED_COUNT ? WS2812_MAX_LED_COUNT : led_count;
    //uint16_t byte_position = 0;

    for (uint16_t i = 0, j = 0; i < byte_count*3; i += 3) { //编码颜色数据
        //WS2812_ColorToBuffer(led_color_buffer[i*3+1], byte_position++); //R
        //WS2812_ColorToBuffer(led_color_buffer[i*3+0], byte_position++); //G
        //WS2812_ColorToBuffer(led_color_buffer[i*3+2], byte_position++); //B
		uint32_t rgb = led_color_buffer[i+1]<<16 | led_color_buffer[i]<<8 | led_color_buffer[i+2];
		for (uint8_t shift = 22; shift != 0xFE; shift -= 2, j += 3) {
			 *(uint32_t*)&WS2812_Buffer[j] = table[(rgb>>shift)&0x03];
		}
    }
    //WS2812_AppendStopPulse(byte_position); //添加复位信号

    DMA_Cmd(DMA1_Channel3, DISABLE); //关闭DMA,以便配置传输长度
    DMA_ClearFlag(DMA1_FLAG_TC3); //清除发送完成中断标志
    DMA_SetCurrDataCounter(DMA1_Channel3, byte_count * 36); //设置传输长度
    DMA_Cmd(DMA1_Channel3, ENABLE); //开始发送
}

 

标签:DMA,WS2812,SPI,InitStructure,position,byte
From: https://www.cnblogs.com/kehuadong/p/17135855.html

相关文章