OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 16716|回复: 18

终于搞定 DMA SPI 硬件单线通信

[复制链接]

30

主题

104

帖子

1

精华

论坛元老

Rank: 8Rank: 8

积分
456475
金钱
456475
注册时间
2014-8-23
在线时间
59 小时
发表于 2015-3-15 14:52:27 | 显示全部楼层 |阅读模式
本帖最后由 cl17726 于 2016-5-27 06:59 编辑

<div>Update:随便发个邮件说明要这个代码发到我邮箱admin@lijingquan.net 有点老了,博客曾经被取消备案,so</div><div><br></div>一个线的通信不需要再用定时器,不需要再搞一大堆中断了,DMA,结合SPI,就可以了.看看结果:<br>
<br>
单线的从机设备:WS2811<br>
<br>
使用的芯片:STM32F051C8T6<br>
<br>
使用的外设MA1 + SPI1<br>
<br>
协议:<br>
<br>
<img src="http://ww3.sinaimg.cn/bmiddle/a7d07956gw1eq5pc83bkcj20b6083jrx.jpg" alt=""><br>
<img src="http://ww2.sinaimg.cn/bmiddle/a7d07956gw1eq5pc8p0jbj20qm08zgnn.jpg" alt=""><br>
<br>
结果:

<br>

<br>
<br>
参考代码,内有说明~ 大家调试方法可以参考:http://www.lijingquan.net/ws2811-use-spi-for-one-wire.html [比较多代码和图,太难转移了.]<br>
<br>
<div style="background-color:#E8E8E8;">
[mw_shl_code=c,true]#include "stm32f0xx.h"
#include "LED_SPI.h"

uint16_t PixelBuffer[404] = {0};
uint16_t PixelPointer = 0;

void LED_SPI_LowLevel_Init(void)
{
    uint16_t i = 0;

    GPIO_InitTypeDef  GPIO_InitStructure;
    SPI_InitTypeDef   SPI_InitStructure;
    DMA_InitTypeDef   DMA_InitStructure;

    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA | RCC_AHBPeriph_DMA1, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);

    DMA_DeInit(DMA1_Channel3);
    DMA_InitStructure.DMA_BufferSize = 0;
    DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t) &amp; (SPI1-&gt;DR);
    DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)PixelBuffer;
    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_HalfWord;
    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
    DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
    DMA_Init(DMA1_Channel3, &amp;DMA_InitStructure); /* DMA1 CH3 = MEM -&gt; DR */

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
    GPIO_InitStructure.GPIO_PuPd  = GPIO_PuPd_UP;
    GPIO_Init(GPIOA, &amp;GPIO_InitStructure);

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
    GPIO_Init(GPIOA, &amp;GPIO_InitStructure);

    GPIO_PinAFConfig(GPIOA, GPIO_PinSource7, GPIO_AF_0);
    GPIO_PinAFConfig(GPIOA, GPIO_PinSource5, GPIO_AF_0);

    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_15b;
    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; /* 48MHz / 8 = 6MHz */
    SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
    SPI_InitStructure.SPI_CRCPolynomial = 7;
    SPI_Init(SPI1, &amp;SPI_InitStructure);

    SPI_I2S_DMACmd(SPI1, SPI_I2S_DMAReq_Tx, ENABLE);

    SPI_Cmd(SPI1, ENABLE);

    for (i = 0; i &lt; 404; i++)
    {
        PixelBuffer<i> = 0xAAAA;
    }

    PixelPointer = 0;

}

void LED_SPI_WriteByte(uint16_t Data)
{
    /* Wait until the transmit buffer is empty */
    /*
    while(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET)
    {
    }
    */

    PixelBuffer[PixelPointer] = Data;
    PixelPointer++;

    /* Send the byte */
    /* SPI_I2S_SendData16(SPI1, Data); */
}

void LED_SPI_SendBits(uint8_t bits)
{
    int zero = 0x7000;  //111000000000000
    int one = 0x7F00;  //111111100000000
    int i = 0x00;

    for (i = 0x80; i &gt;= 0x01; i &gt;&gt;= 1)
    {
        LED_SPI_WriteByte((bits &amp; i) ? one : zero);
    }
}

void LED_SPI_SendPixel(struct Pixel pixel)
{
    /*
     r7,r6,r5,r4,r3,r2,r1,r0,g7,g6,g5,g4,g3,g2,g1,g0,b7,b6,b5,b4,b3,b2,b1,b0
     \_____________________________________________________________________/
                               |      _________________...
                               |     /   __________________...
                               |    /   /   ___________________...
                               |   /   /   /
                              RGB,RGB,RGB,RGB,...,STOP
    */

    /*
            BUG Fix : Actual is GRB,datasheet is something wrong.
    */
    LED_SPI_SendBits(pixel.green);
    LED_SPI_SendBits(pixel.red);
    LED_SPI_SendBits(pixel.blue);
}

ErrorStatus LED_SPI_Update(struct Pixel buffer[], uint32_t length)
{
    uint8_t i = 0;
    uint8_t m = 0;
    if(DMA_GetCurrDataCounter(DMA1_Channel3) == 0)
    {

        for (i = 0; i &lt; length; i++)
        {
            LED_SPI_SendPixel(buffer<i>);
        }

        if(length &lt; 16)
        {
            for(i = 16 - length; i &lt; length; i++)
            {
                for(m = 0; m &lt; 3; m++)
                {
                    LED_SPI_SendBits(0x00);
                }
            }
        }

        for (i = 0; i &lt; 20; i++)   /* (20+1) * 2.5 = 51.5 ~ 52.5us */
        {
            LED_SPI_WriteByte(0x00);
        }

        PixelPointer = 0;

        DMA_Cmd(DMA1_Channel3, DISABLE);
        DMA_ClearFlag(DMA1_FLAG_TC3);
        DMA_SetCurrDataCounter(DMA1_Channel3, 404);
        DMA_Cmd(DMA1_Channel3, ENABLE);

        return SUCCESS;
    }
    else
    {
        return ERROR;
    }
}[/mw_shl_code]
</i></i></div><i><i>
<br>
<br>
<br>
<br></i></i>
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

28

主题

95

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
313
金钱
313
注册时间
2013-10-11
在线时间
38 小时
发表于 2015-3-15 15:10:26 | 显示全部楼层
回复 支持 反对

使用道具 举报

4

主题

12

帖子

0

精华

初级会员

Rank: 2

积分
67
金钱
67
注册时间
2012-6-8
在线时间
3 小时
发表于 2015-9-15 09:29:01 | 显示全部楼层
利害啊,我都折腾了好几天现在还是没什么头绪
创新电子科技,引领世界潮流
回复 支持 反对

使用道具 举报

0

主题

5

帖子

0

精华

新手上路

积分
30
金钱
30
注册时间
2013-1-12
在线时间
1 小时
发表于 2016-1-28 15:09:48 | 显示全部楼层
好东西,顶一个!
回复 支持 反对

使用道具 举报

0

主题

2

帖子

0

精华

新手上路

积分
27
金钱
27
注册时间
2013-6-17
在线时间
1 小时
发表于 2016-4-15 16:58:16 | 显示全部楼层
呼吸灯实现了吗
回复 支持 反对

使用道具 举报

26

主题

100

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
396
金钱
396
注册时间
2014-2-10
在线时间
67 小时
发表于 2016-4-22 15:29:50 | 显示全部楼层
GPIO_PinAFConfig(GPIOA, GPIO_PinSource7, GPIO_AF_0);
    GPIO_PinAFConfig(GPIOA, GPIO_PinSource5, GPIO_AF_0);

移植到stm32f103战舰,这两行代码报错,请问一下在stm32f103是用哪个库函数代替着个函数呢?
回复 支持 反对

使用道具 举报

26

主题

100

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
396
金钱
396
注册时间
2014-2-10
在线时间
67 小时
发表于 2016-4-22 16:01:36 | 显示全部楼层
用软件仿真怎么没有波形输出的呢
回复 支持 反对

使用道具 举报

0

主题

2

帖子

0

精华

新手上路

积分
24
金钱
24
注册时间
2015-12-25
在线时间
1 小时
发表于 2016-5-24 19:47:10 | 显示全部楼层
楼主您好,您的博客里的这个帖子怎么没有了,没能看太懂您的程序,能把工程发给我一份吗,万分感谢
回复 支持 反对

使用道具 举报

30

主题

104

帖子

1

精华

论坛元老

Rank: 8Rank: 8

积分
456475
金钱
456475
注册时间
2014-8-23
在线时间
59 小时
 楼主| 发表于 2016-5-27 06:59:30 | 显示全部楼层
晨晓科创 发表于 2016-5-24 19:47
楼主您好,您的博客里的这个帖子怎么没有了,没能看太懂您的程序,能把工程发给我一份吗,万分感谢

你随便发个邮件说明要这个代码发到我邮箱admin@lijingquan.net 有点老了.
回复 支持 反对

使用道具 举报

0

主题

1

帖子

0

精华

新手入门

积分
15
金钱
15
注册时间
2016-8-9
在线时间
2 小时
发表于 2016-8-9 11:33:32 | 显示全部楼层
可以看到共享源码吗?
回复 支持 反对

使用道具 举报

2

主题

68

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
4128
金钱
4128
注册时间
2016-7-22
在线时间
580 小时
发表于 2016-10-18 20:19:11 | 显示全部楼层
cl17726 发表于 2016-5-27 06:59
你随便发个邮件说明要这个代码发到我邮箱 有点老了.

楼主你好,我查看了代码,发现代码里头,没有SPI1的输出,最终的数据都给到了数组 PixelBuffer[PixelPointer] 当中,可是没有看到输出该数组的语句啊,谢谢。
回复 支持 反对

使用道具 举报

30

主题

104

帖子

1

精华

论坛元老

Rank: 8Rank: 8

积分
456475
金钱
456475
注册时间
2014-8-23
在线时间
59 小时
 楼主| 发表于 2017-3-12 18:44:35 | 显示全部楼层
冻结的鱼 发表于 2016-10-18 20:19
楼主你好,我查看了代码,发现代码里头,没有SPI1的输出,最终的数据都给到了数组 PixelBuffer 当中,可 ...

DMA输出
回复 支持 反对

使用道具 举报

30

主题

104

帖子

1

精华

论坛元老

Rank: 8Rank: 8

积分
456475
金钱
456475
注册时间
2014-8-23
在线时间
59 小时
 楼主| 发表于 2017-3-12 18:45:03 | 显示全部楼层
[STM32]WS281x_STM32F051.zip (312.45 KB, 下载次数: 1204)
回复 支持 反对

使用道具 举报

0

主题

1

帖子

0

精华

新手上路

积分
20
金钱
20
注册时间
2018-3-5
在线时间
2 小时
发表于 2017-4-28 09:13:36 | 显示全部楼层

大神
void LED_SPI_SendBits(uint8_t bits)
{
    int zero = 0x7000;  //111000000000000
    int one = 0x7F00;  //111111100000000
    int i = 0x00;

    for (i = 0x80; i >= 0x01; i >>= 1)
    {
        LED_SPI_WriteByte((bits & i) ? one : zero);
    }
}
为啥要发送
zero = 0x7000;  //111000000000000
one = 0x7F00;  //111111100000000
不理解求教
回复 支持 反对

使用道具 举报

2

主题

26

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
203
金钱
203
注册时间
2017-7-6
在线时间
45 小时
发表于 2017-7-7 11:00:43 | 显示全部楼层
小妮 发表于 2017-4-28 09:13
大神
void LED_SPI_SendBits(uint8_t bits)
{

这应该是RGB灯珠需要的“1”、“0”的脉冲波形,每一种RGB灯珠需要的波形可能是不一样的,这个需要看规格书
回复 支持 反对

使用道具 举报

6

主题

19

帖子

0

精华

初级会员

Rank: 2

积分
91
金钱
91
注册时间
2017-6-14
在线时间
26 小时
发表于 2017-7-20 15:27:16 | 显示全部楼层
麻烦问下,用SPI如何准确生成周期为1.25us的时序?
回复 支持 反对

使用道具 举报

3

主题

15

帖子

0

精华

初级会员

Rank: 2

积分
143
金钱
143
注册时间
2016-8-9
在线时间
26 小时
发表于 2017-8-7 13:48:25 | 显示全部楼层
zhanlej 发表于 2017-7-20 15:27
麻烦问下,用SPI如何准确生成周期为1.25us的时序?

TH+TL=1.25us±600ns
回复 支持 反对

使用道具 举报

5

主题

43

帖子

0

精华

初级会员

Rank: 2

积分
158
金钱
158
注册时间
2016-11-1
在线时间
27 小时
发表于 2017-8-29 15:54:33 | 显示全部楼层
留下脚印,等我 把SPI 搞通了 再来
回复 支持 反对

使用道具 举报

0

主题

2

帖子

0

精华

新手入门

积分
17
金钱
17
注册时间
2018-1-2
在线时间
2 小时
发表于 2018-1-5 09:27:15 | 显示全部楼层
你好 请问
int zero = 0x7000;  //111000000000000
    int one = 0x7F00;  //111111100000000
这两个值怎么推算出来的?
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2025-6-11 05:46

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表