打印
[STM32F4]

STM32F407的SPI操作从设备时,片选信号自动拉高

[复制链接]
10454|18
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
CS_TQ|  楼主 | 2014-10-12 11:16 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
    最近使用407的SPI3连接一个16位的DA芯片,设置SPI3为单向只发送,从设备DA芯片的时序要求如下:片选SYNC的第一个下降沿启动写周期。SCLK必须在24个时钟下降沿后,才能将SYNC重新拉高。如果在第24个SCLK下降沿之前拉高SYNC,写入的数据无效。如果拉高SYNC前有超过24个SCLK下降沿,输入数据同样无效。
    我在代码中明明是写之前拉低片选,写完24位数据再拉高,但是片选信号总是在发送过程中就直接拉高了,片选信号引脚使用的普通IO软件操作,实际波形图如下:
                                                                     
    第一路信号:时钟SCLK;
    第二路信号:片选,使用的是GPIOF8;
    第三路信号:主设备输出MOSI,发送的数据是0xAAA1,数据正确。

摘出配置程序如下:

#define AD5754R_CS_HIGH()       GPIO_SetBits(GPIOF,GPIO_Pin_8)
#define AD5754R_CS_LOW()       GPIO_ResetBits(GPIOF,GPIO_Pin_8)

unsigned char AD5754R_Init(void)
{
        unsigned char status = 0;

        GPIO_InitTypeDef GPIO_InitStructure;/* 配置CPU板上使用LDAC引脚(PB15)为输出模式的GPIO管脚*/
         
          RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE); /*使能LDAC引脚使用的GPIOB时钟*/
          RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF, ENABLE); /*使能SYNC引脚使用的GPIOF时钟*/


    /* 配置LDAC引脚的具体GPIO模式 */
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;   
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;

          GPIO_InitStructure.GPIO_Pin = GPIO_Pin_15;
          GPIO_Init(GPIOB, &GPIO_InitStructure);  /*CPU板使用的LDAC引脚的GPIO口初始化*/

          GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
          GPIO_Init(GPIOF, &GPIO_InitStructure);  /*CPU板使用的SYNC引脚的GPIO口初始化*/

          AD5754R_LDAC_LOW();//LDAC初始设置成低电平,寻址的DAC输出在SYNC的上升沿更新
        AD5754R_CS_HIGH(); //SYNC初始化高电平,传数据时再拉低

        status = AD5754R_SPI_Init(0, 1000000, 1, 1);
                                                        //4个参数:发送优先方式(MSB/LSB)、时钟频率、时钟极性、时钟相位
        return(status);                //返回初始化结果,1:成功  0:初始化失败
}


unsigned char AD5754R_SPI_Init(unsigned char lsbFirst,        //这几个参数只是做一个指示,具体设置在SPI初始化结构体中进行
                       unsigned long clockFreq,                          
                       unsigned char clockPol,   
                       unsigned char clockPha)
{
        SPI_InitTypeDef  SPI_InitStructure;
        GPIO_InitTypeDef GPIO_InitStructure;

  /*   使能 SPI3 和 GPIO 时钟 */
  /*   SPI3_MOSI - PC12,SPI3_SCK - PC10,SPI3_NSS - PA15  */
//        RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,  ENABLE);  //使能GPIOA时钟,SPI3_NSS - PA15
        RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC,  ENABLE);  //使能GPIOC时钟
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI3, ENABLE);        //使能SPI3时钟

    /* SPI3引脚复用映射 */
        GPIO_PinAFConfig(GPIOC, GPIO_PinSource10, GPIO_AF_SPI3);  //SPI3_SCK - PC10
        GPIO_PinAFConfig(GPIOC, GPIO_PinSource12, GPIO_AF_SPI3);  //SPI3_MOSI - PC12

        /* 配置引脚模式类型  */
        GPIO_InitStructure.GPIO_PuPd  = GPIO_PuPd_DOWN;                 //CPOL=0,对应SCK引脚要下拉
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;

        /* 指定SPI3引脚: SCK 、MOSI*/
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10 | GPIO_Pin_12;
        GPIO_Init(GPIOC, &GPIO_InitStructure);

        /* SPI3 配置 */
        // 时钟信号的下降捕捉数据
        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;                                //CPOL=0
        SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;                        //CPHA=1
        SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;                                //NSS片选信号软件控制
        SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_8;        //波特率参数设置
        SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;                 //最高位优先
        SPI_InitStructure.SPI_CRCPolynomial = 7;                        //CRC值计算的多项式
        SPI_Init(SPI3, &SPI_InitStructure);                 //写入配置信息,初始化SPI3结束

        SPI_Cmd(SPI3, ENABLE);        /* 使能 SPI3  */

        return(1);         //初始化成功,返回1
}

//------------------SPI写操作,8位数据帧格式,循环发三次共计24位数据,24位数据字格式已经在相关函数配置好,送该函数发送-------------
void AD5754R_SPI_Write(unsigned char* data,   //指向数据数组data[]
                        unsigned char bytesNumber)  //bytesNumber=3
{
        unsigned char i=0;

        AD5754R_CS_LOW();  //片选先拉高再拉低,产生一个下降沿启动写周期
       
        for(i=0;i<bytesNumber;i++)   //写入三个字节,24位数据
        {
                /* Loop while DR register in not empty */
                while (SPI_I2S_GetFlagStatus(SPI3, SPI_I2S_FLAG_TXE) == RESET);
                SPI_I2S_SendData(SPI3, data); //通过SPI3发送数据
        }

        AD5754R_CS_HIGH();
}

    各位有没有碰到类似情况,片选信号不受控制拉高,之前按照网上一些参照用的NSS引脚设置软件输出模式是这个情况,现在改成普通IO引脚片选还这样,求帮忙分析。
沙发
CS_TQ|  楼主 | 2014-10-12 12:47 | 只看该作者
自己顶一下,希望有遇到类似问题的提点意见啊

使用特权

评论回复
板凳
mmuuss586| | 2014-10-12 15:03 | 只看该作者
这是我407发送24位数据到外部设备,你可以参考下:
nSS_L;
SPI_I2S_SendData(SPI1, udt.ucdata[2]);
        // Wait for SPIx Busy flag
        while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_BSY) != RESET);
       
        // SPI byte send
   SPI_I2S_SendData(SPI1, udt.ucdata[1]);
        // Wait for SPIx Busy flag
        while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_BSY) != RESET);

        // SPI byte send
   SPI_I2S_SendData(SPI1, udt.ucdata[0]);
        // Wait for SPIx Busy flag
        while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_BSY) != RESET);
  nSS_H;

使用特权

评论回复
地板
mmuuss586| | 2014-10-12 15:05 | 只看该作者
初始化部分,不一定要主机模式下,你可以改下看看:
/* SPI configuration ------------------------------------------------------*/
        SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;//È«Ë«¹¤
        SPI_InitStructure.SPI_Mode = SPI_Mode_Master;//Ö÷»úģʽ
        SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;//8λÊý¾Ýģʽ
        SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;//¿ÕÏÐģʽÏÂSCKΪ1
        SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;//Êý¾Ý²ÉÑù´ÓµÚ2¸öʱ¼ä±ßÑØ¿ªÊ¼
        SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;//NSSÈí¼þ¹ÜÀí
        SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_16;//·¢ËͺͽÓÊÕʱÖÓ·ÖƵÉèÖà  168/2/16=5.25M
        SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;//´ó¶Ëģʽ
        SPI_InitStructure.SPI_CRCPolynomial = 7;//CRC¶àÏîʽ         
        SPI_Init(SPI1, &SPI_InitStructure);
        SPI_Cmd(SPI1, ENABLE);

使用特权

评论回复
5
icecut| | 2014-10-12 15:34 | 只看该作者
这种da我们用过。当时我们的片子支持可选是不是8bit后拉高。
stm32我看着好像没这配置。你还是做软件片选吧

使用特权

评论回复
6
CS_TQ|  楼主 | 2014-10-12 15:57 | 只看该作者
mmuuss586 发表于 2014-10-12 15:03
这是我407发送24位数据到外部设备,你可以参考下:
nSS_L;
SPI_I2S_SendData(SPI1, udt.ucdata[2]);

配成全双工而只用他的发送是么,只设置单线发送会有什么问题?板子在公司,明天试一下您的方法

使用特权

评论回复
7
CS_TQ|  楼主 | 2014-10-12 16:03 | 只看该作者
mmuuss586 发表于 2014-10-12 15:03
这是我407发送24位数据到外部设备,你可以参考下:
nSS_L;
SPI_I2S_SendData(SPI1, udt.ucdata[2]);

我也试过你这种不用循环逐个字节单独摘出来发送的,但是片选还是莫名自动变高,你的udt.ucdata[2]第一次发送之前没有判忙么?

使用特权

评论回复
8
CS_TQ|  楼主 | 2014-10-12 16:06 | 只看该作者
icecut 发表于 2014-10-12 15:34
这种da我们用过。当时我们的片子支持可选是不是8bit后拉高。
stm32我看着好像没这配置。你还是做软件片选吧 ...

我用的AD5754R的DA转换芯片,完整24位数据字之后才能拉高片选,片选引脚我改成普通GPIO,如上面写的GPIOF8,还是有这个问题,一直没找出来错误

使用特权

评论回复
9
icecut| | 2014-10-12 19:19 | 只看该作者
CS_TQ 发表于 2014-10-12 16:06
我用的AD5754R的DA转换芯片,完整24位数据字之后才能拉高片选,片选引脚我改成普通GPIO,如上面写的GPIOF ...

spi配置成软件片选模式

使用特权

评论回复
10
CS_TQ|  楼主 | 2014-10-12 20:12 | 只看该作者
icecut 发表于 2014-10-12 19:19
spi配置成软件片选模式

SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;    //NSS片选信号软件控制

你的意思是用SPI复用的NSS引脚做片选么?

使用特权

评论回复
11
搞IT的| | 2014-10-12 21:21 | 只看该作者
mmuuss586 发表于 2014-10-12 15:05
初始化部分,不一定要主机模式下,你可以改下看看:
/* SPI configuration ----------------------------- ...

后面的怎么有乱码啊

使用特权

评论回复
12
mmuuss586| | 2014-10-12 22:15 | 只看该作者
CS_TQ 发表于 2014-10-12 15:57
配成全双工而只用他的发送是么,只设置单线发送会有什么问题?板子在公司,明天试一下您的方法 ...

是的,结果一样的

使用特权

评论回复
13
mmuuss586| | 2014-10-12 22:16 | 只看该作者
搞IT的 发表于 2014-10-12 21:21
后面的怎么有乱码啊

我mdk注释中文的,每次复制过来就成这个样子了

使用特权

评论回复
14
icecut| | 2014-10-12 23:53 | 只看该作者
mmuuss586 发表于 2014-10-12 22:16
我mdk注释中文的,每次复制过来就成这个样子了

乱码是中文注视。你编码和网站使用的不一样。一个是gbk一个是utf8

使用特权

评论回复
15
CS_TQ|  楼主 | 2014-10-13 14:02 | 只看该作者
还是老样子毫无头绪啊,望各位指点

使用特权

评论回复
16
CS_TQ|  楼主 | 2014-10-14 11:15 | 只看该作者
片选问题解决了,把SPI写函数修改成如下所示,片选波形逻辑正常,但是边沿处的振铃还比较严重,还要继续修改。

        while (SPI_I2S_GetFlagStatus(SPI3, SPI_I2S_FLAG_BSY) != RESET);               
                while (SPI_I2S_GetFlagStatus(SPI3, SPI_I2S_FLAG_TXE) == RESET);
        SPI_I2S_SendData(SPI3, data[0]); //通过SPI3发送数据

        while (SPI_I2S_GetFlagStatus(SPI3, SPI_I2S_FLAG_BSY) != RESET);               
                while (SPI_I2S_GetFlagStatus(SPI3, SPI_I2S_FLAG_TXE) == RESET);
        SPI_I2S_SendData(SPI3, data[1]); //通过SPI3发送数据

/* */        while (SPI_I2S_GetFlagStatus(SPI3, SPI_I2S_FLAG_TXE) == RESET);
        SPI_I2S_SendData(SPI3, data[2]); //通过SPI3发送数据         
        while (SPI_I2S_GetFlagStatus(SPI3, SPI_I2S_FLAG_BSY) != RESET);

几个while判断的顺序不能变,尝试过不同的顺序判断while,波形就异常。

正常波形如下:

                                               
     

使用特权

评论回复
17
搞IT的| | 2014-11-13 15:18 | 只看该作者
icecut 发表于 2014-10-12 23:53
乱码是中文注视。你编码和网站使用的不一样。一个是gbk一个是utf8

哦哦 要是都用国际编码来写就不会出现这种现象了吧??

使用特权

评论回复
18
forever521313| | 2017-2-16 17:42 | 只看该作者
本帖最后由 forever521313 于 2017-2-16 17:48 编辑

兄弟,我和你碰到一样的问题,我用的也是AD5754.片选被提前拉高,我用IO口模拟Spi就可以,用硬件接口就不行,能加一下我的QQ294921908吗,我也在做模拟量采集的项目,方便交流。

使用特权

评论回复
19
forever521313| | 2017-2-16 18:01 | 只看该作者
你好,我也在做嵌入式的,我也在用AD5754R这个芯片,和你碰到同样的问题,能加一下我的QQ294921908吗?有问题可以请教你一下

使用特权

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

本版积分规则

4

主题

18

帖子

2

粉丝