打印
[STM32]

stm32通过spi驱动MB85RS2MT铁电,不能读出数据,请教原因?

[复制链接]
12349|13
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
caike1985|  楼主 | 2013-11-2 22:52 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 caike1985 于 2013-11-2 22:56 编辑

先声明,本人是单片机菜鸟,请各位指点迷津。
现象:
用stm32的spi接口驱动铁电MB85RS2MT(此芯片兼容FM25H20),问题是用示波器能看到单片机有数据输出,但是我读不出任何数据,读出的都是0x00,不知道是什么原因,发帖求助。下面是我的代码,我会加注释的,方便大家查看。

系统时钟是72MHZ,芯片型号是STM32F103RE

#define FRAM_WREN_INST      0x06                //设置写使能
#define FRAM_WRDI_INST      0x04                //写禁止
#define FRAM_RDSR_INST      0x05                //读状态寄存器
#define FRAM_WRSR_INST      0x01                //写状态寄存器
#define FRAM_READ_INST      0x03                //读存储器数据
#define FRAM_WRITE_INST     0x02            //写存储器数据
#define FRAM_STATUS_REG     0x0                //
#define FRAM_INIT_STATE     0x09        //

//测试代码:
        SPI_write_FRAM('a',0x01); //向地址1写入字节'a'
        t = SPI_read_FRAM(0x01); //从地址1读出字节

结果: t永远是0,为什么啊?
      


void SPI_FRAM_Init(void)
{
    SPI_InitTypeDef  SPI_InitStructure;
    GPIO_InitTypeDef GPIO_InitStructure;
  
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOC|RCC_APB2Periph_SPI1, ENABLE);        

        GPIO_InitStructure.GPIO_Pin = FRAM_CS;  //SPI CS
         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;  //推挽输出
         GPIO_Init(GPIOA, &GPIO_InitStructure);
         GPIO_SetBits(GPIOA,FRAM_CS);

        GPIO_InitStructure.GPIO_Pin = FRAM_SCK | FRAM_MISO | FRAM_MOSI;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;  //复用推挽输出
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_Init(GPIOA, &GPIO_InitStructure);
         GPIO_SetBits(GPIOA,FRAM_SCK|FRAM_MISO|FRAM_MOSI);

        GPIO_InitStructure.GPIO_Pin = FRAM_HOLD|FRAM_WP;
         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;  
         GPIO_Init(GPIOC, &GPIO_InitStructure);
         GPIO_SetBits(GPIOC,FRAM_HOLD|FRAM_WP);
   
        SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;  //设置SPI单向或者双向的数据模式:SPI设置为双线双向全双工
        SPI_InitStructure.SPI_Mode = SPI_Mode_Master;                //设置SPI工作模式:设置为主SPI
        SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;                //设置SPI的数据大小:SPI发送接收8位帧结构
        SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;                //选择了串行时钟的稳态:时钟悬空高
        SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;        //数据捕获于第二个时钟沿
        SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;                //NSS信号由硬件(NSS管脚)还是软件(使用SSI位)管理:内部NSS信号有SSI位控制
        SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_4;                //定义波特率预分频的值:波特率预分频值为256
        SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;        //指定数据传输从MSB位还是LSB位开始:数据传输从MSB位开始
        SPI_InitStructure.SPI_CRCPolynomial = 7;        //CRC值计算的多项式
        SPI_Init(SPI1, &SPI_InitStructure);  //根据SPI_InitStruct中指定的参数初始化外设SPIx寄存器
        SPI_Cmd(SPI1, ENABLE); //使能SPI外设
    delay_us(500);
}

u8 SPIx_WriteByte(u8 TxData)
{
    while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_BSY) == SET);
    SPI_I2S_SendData(SPI1, TxData); //通过外设SPIx发送一个数据

    while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_BSY) == SET);
    SPI_I2S_ReceiveData(SPI1);
   
}

u8 SPIx_ReadByte(u8 TxData)
{
    while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_BSY) == SET);
    SPI_I2S_SendData(SPI1, TxData); //通过外设SPIx发送一个数据

    while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_BSY) == SET);
    return SPI_I2S_ReceiveData(SPI1);
}

void SPI_write_FRAM(u8 data,u16 address)//写入一个字节到特定地址空间
{
        u8 addr_tempH,addr_tempM,addr_tempL;
        addr_tempH = (u8)((address>>16)&0x000000ff);      //获取高8位地址
        addr_tempM = (u8)((address>>8)&0x000000ff);   //获取中8位地址
        addr_tempL = (u8)(address&0x000000ff);        //获取低8位地址
        FRAM_Reset_CS;
        SPIx_WriteByte(FRAM_WREN_INST);    //写使能
    FRAM_Set_CS;
    delay_us(100);

        FRAM_Reset_CS;
        SPIx_WriteByte(FRAM_WRITE_INST);   //写存储器寄存器操作码
        SPIx_WriteByte(addr_tempH);            //写入高八位地址,高6位忽略
        SPIx_WriteByte(addr_tempM);             //写入中八位地址
        SPIx_WriteByte(addr_tempL);            //
        SPIx_WriteByte(data);                  //写入数据
        FRAM_Set_CS;
}
        
u8 SPI_read_FRAM(u16 address)//读出特定地址空间的数据
{
        u8 dat,addr_tempH,addr_tempM,addr_tempL;
        addr_tempH = (u8)((address>>16)&0x000000ff);      //获取高8位地址
        addr_tempM = (u8)((address>>8)&0x000000ff);   //获取中8位地址
        addr_tempL = (u8)(address&0x000000ff);        //获取低8位地址
        FRAM_Reset_CS;
        SPIx_WriteByte(FRAM_READ_INST);      //读存储器寄存器操作码        
        SPIx_WriteByte(addr_tempH);
        SPIx_WriteByte(addr_tempM);             //写入中八位地址        
        SPIx_WriteByte(addr_tempL);
        dat=SPIx_ReadByte(0xa5);               //读取数据
        FRAM_Set_CS;
        return (dat);
}








相关帖子

沙发
阿南| | 2013-11-3 08:47 | 只看该作者
要对存储器的读写时序和命令
如果这段程序原来是可用的,可以试试调整信号的延时时间

使用特权

评论回复
板凳
bald| | 2013-11-4 20:12 | 只看该作者
先不要忙着读写数据。读一下状态寄存器,如果能读出往后查,如果读不出来往前查。这样可以化繁为简。

使用特权

评论回复
地板
风清扬mxz| | 2014-11-20 15:33 | 只看该作者
亲,你的问题现在解决了吗?

使用特权

评论回复
5
Harvard| | 2016-4-25 14:39 | 只看该作者
同问 . 我是原在c8051f
上可用的c代码 移植到新唐M0 就无**常读出了 .一直读到0xff了

使用特权

评论回复
6
killer2014| | 2016-5-23 12:41 | 只看该作者
SPI 的时序没配置好,你用示波器调试下,

使用特权

评论回复
7
xyang18| | 2017-2-14 15:50 | 只看该作者

1.WP管教保持为高
2.要先设置状态寄存器
                MB_CS_L;
                SPIx_ReadWriteByte(0x06);                //设置写使能锁存器
                MB_CS_H;
                //delay_ms(1);
                MB_CS_L;
                SPIx_ReadWriteByte(0x01);                //写状态寄存器
                xy2 = SPIx_ReadWriteByte( 0x80 );
                MB_CS_H;

3.写入数据
                SPI_write_MB85RS256A(MR_DATA,MR_ADDR);        
4.读取数据
                ReadData=SPI_read_MB85RS256A(MR_ADDR);//

感谢提供驱动程序的程序员
参考驱动程序:
fram.h
#ifndef __FRAM_H
#define __FRAM_H                           
//#include "stm32f10x.h"            
#include "stm32f10x_spi.h"     

#define MB85RS256A_WREN_INST  0x06                //设置写使能锁存器        //MB85RS256A寄存器定义
#define MB85RS256A_WRDI_INST  0x04                //写禁止
#define MB85RS256A_RDSR_INST  0x05                //读状态寄存器
#define MB85RS256A_WRSR_INST  0x01                //写状态寄存器
#define MB85RS256A_READ_INST  0x03                //读存储器数据
#define MB85RS256A_WRITE_INST 0x02                //写存储器数据
#define MB85RS256A_STATUS_REG 0x0                //
#define MB85RS256A_INIT_STATE 0x09                //
#define MB85RS256A_RDID_INST  0x9F                //读器件ID

#define MB_CS_L                GPIO_ResetBits(GPIOB,GPIO_Pin_11)
#define MB_CS_H                GPIO_SetBits(GPIOB,GPIO_Pin_11)
#define MB_CS                         GPIO_ReadOutputDataBit(GPIOB,GPIO_Pin_11)

#define MB_WP_L                GPIO_ResetBits(GPIOB,GPIO_Pin_12)
#define MB_WP_H                GPIO_SetBits(GPIOB,GPIO_Pin_12)
#define MB_WP                 GPIO_ReadOutputDataBit(GPIOB,GPIO_Pin_12)

#define MB_SCLK_L        GPIO_ResetBits(GPIOB,GPIO_Pin_13)
#define MB_SCLK_H        GPIO_SetBits(GPIOB,GPIO_Pin_13)
#define MB_MOSI_L        GPIO_ResetBits(GPIOB,GPIO_Pin_15)
#define MB_MOSI_H        GPIO_SetBits(GPIOB,GPIO_Pin_15)

void SPI_Fram_Init(void);
u8 SPIx_ReadWriteByte(u8 data);
void SPI_write_MB85RS256A(u8 data,u16 address);//写入一个字节到特定地址空间
u8 SPI_read_MB85RS256A(u16 address);//读出特定地址空间的数据
void MB85RS256A_WRITE(u16 add, u8 *buf, u16 len);
void MB85RS256A_READ(u16 add, u8 *buf, u16 len);
extern void delay(u32 i);
extern void delay_ms(u32 i);
#endif


fram.c
#include "fram.h"
/********************************************************
//project:STM32F1  SPI2读写MB85RS256A驱动代码  
//date:2015.10.12
//author:chenxuying
//annotation:适用铁电存储器mb85系列读写代码,直接读写一个字节
**********************************************************/
//初始化SPI2 FRAM的IO口
void SPI_Fram_Init(void)
{
        GPIO_InitTypeDef GPIO_InitStructure;
        SPI_InitTypeDef  SPI_InitStructure;
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE);

        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10|GPIO_Pin_11|GPIO_Pin_12;  //SPI CS/HOLD
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;  //推挽输出
        GPIO_Init(GPIOB, &GPIO_InitStructure);
        GPIO_SetBits(GPIOB,GPIO_Pin_10|GPIO_Pin_11|GPIO_Pin_12);

        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_14;//PB14
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //上拉输入
        GPIO_Init(GPIOB, &GPIO_InitStructure);

        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13|GPIO_Pin_15;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;  //复用推挽输出
        GPIO_Init(GPIOB, &GPIO_InitStructure);
        GPIO_SetBits(GPIOB,GPIO_Pin_13|GPIO_Pin_15);

        SPI_I2S_DeInit(SPI2);
        SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;  //设置SPI单向或者双向的数据模式:SPI设置为双线双向全双工
        SPI_InitStructure.SPI_Mode = SPI_Mode_Master;                //设置SPI工作模式:设置为主SPI
        SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;        //设置SPI的数据大小:SPI发送接收8位帧结构
        SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;                //选择了串行时钟的稳态:时钟悬空高
        SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;        //数据捕获于第二个时钟沿
        SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;                //NSS信号由硬件(NSS管脚)还是软件(使用SSI位)管理:内部NSS信号有SSI位控制
        SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256;        //定义波特率预分频的值:波特率预分频值为256
        SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;        //指定数据传输从MSB位还是LSB位开始:数据传输从MSB位开始
        SPI_InitStructure.SPI_CRCPolynomial = 7;        //CRC值计算的多项式
        SPI_Init(SPI2, &SPI_InitStructure);  //根据SPI_InitStruct中指定的参数初始化外设SPIx寄存器
        
        SPI_Cmd(SPI2, ENABLE); //使能SPI外设
        SPIx_ReadWriteByte(0x00);//0x00,0xff,0xaa都行
}  

u8 SPIx_ReadWriteByte(u8 TxData)                           //SPI 发送接收字节
{
        u8 retry=0;                                         
        while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE) == RESET) //检查指定的SPI标志位设置与否:发送缓存空标志位
        {
                retry++;
                if(retry>200)return 0;
        }                          
        SPI_I2S_SendData(SPI2, TxData); //通过外设SPIx发送一个数据
        retry=0;

        while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_RXNE) == RESET) //检查指定的SPI标志位设置与否:接受缓存非空标志位
        {
                retry++;
                if(retry>200)return 0;
        }                                                              
        return SPI_I2S_ReceiveData(SPI2); //返回通过SPIx最近接收的数据        
}

void SPI_write_MB85RS256A(u8 data,u16 address)//写入一个字节到特定地址空间
{
        u8 addr_tempH,addr_tempL;
        addr_tempH = (u8)((address&0xff00)>>8);   //获取高8位地址
        addr_tempL = (u8)(address&0x00ff);        //获取低8位地址
        MB_CS_L;
        SPIx_ReadWriteByte(MB85RS256A_WREN_INST);    //写使能
        MB_CS_H;
//         delay(1000);
        MB_CS_L;
        SPIx_ReadWriteByte(MB85RS256A_WRITE_INST);   //写存储器寄存器操作吗
        SPIx_ReadWriteByte(addr_tempH);            //写入高八位地址,高3位忽略
        SPIx_ReadWriteByte(addr_tempL);            //
        SPIx_ReadWriteByte(data);                  //写入数据
        MB_CS_H;
//         MB_CS_L;
//         SPIx_ReadWriteByte(MB85RS256A_WRDI_INST);
//         MB_CS_H;
}

u8 SPI_read_MB85RS256A(u16 address)//读出特定地址空间的数据
{
        u8 dat,addr_tempH,addr_tempL;
        addr_tempH = (u8)((address&0xff00)>>8);
        addr_tempL = (u8)(address&0x00ff);
        MB_CS_L;
        SPIx_ReadWriteByte(MB85RS256A_READ_INST);      //读存储器寄存器操作码
        SPIx_ReadWriteByte(addr_tempH);
        SPIx_ReadWriteByte(addr_tempL);
        dat=SPIx_ReadWriteByte(0x00);               //读取数据,0xAA给予读取数据所需的时钟
        MB_CS_H;
        return (dat);
}

void MB85RS256A_WRITE(u16 add, u8 *buf, u16 len)
{
        MB_CS_L;
        SPIx_ReadWriteByte(MB85RS256A_WREN_INST);                   /* step 1 .  WEL = 1            */
        MB_CS_H;
//         delay(1000);
        MB_CS_L;
        SPIx_ReadWriteByte(MB85RS256A_WRITE_INST);
    SPIx_ReadWriteByte((u8)(add>>8));
    SPIx_ReadWriteByte((u8)(add));
    for (; len > 0; len--)
        {                                                                            /* step 4 . send out bytes      */
        SPIx_ReadWriteByte(*buf++);
        }
        MB_CS_H;
}

void MB85RS256A_READ(u16 add, u8 *buf, u16 len)
{        
        MB_CS_L;
        SPIx_ReadWriteByte(MB85RS256A_READ_INST);
    SPIx_ReadWriteByte((u8)(add>>8));
    SPIx_ReadWriteByte((u8)(add));
    for (;len > 0; len--)
        {
       *buf++ = (SPIx_ReadWriteByte(0x00));
        }
        MB_CS_H;
}

MB85RS16.zip

3.02 KB

使用特权

评论回复
评论
苍天蓝耀 2021-7-1 11:24 回复TA
SPI发送那的200次循环去掉就好使了,F407 
8
xyang18| | 2017-2-14 15:59 | 只看该作者
判断通讯成功,我是通过读取ID确定的,这个不需要任何条件,直接读取就可以
                                        MB_CS_L;
                                        xy2=SPIx_ReadWriteByte( 0x9F );        //去除ID
                                        xy3=SPIx_ReadWriteByte(0);
                                        xy4=SPIx_ReadWriteByte(0);
                                        xy5=SPIx_ReadWriteByte(0);
                                        xy6=SPIx_ReadWriteByte(0);
                                        xy7=SPIx_ReadWriteByte(0);
                                        MB_CS_H;

使用特权

评论回复
评论
苍天蓝耀 2021-7-1 11:26 回复TA
可行,手册里写的:输出顺序是制造商 ID,0x04( 8 位) / 继续代码,0x7f( 8 位) / 产品 ID,0x01(第 1 个字节) / 产品 ID,0x01(第 2 个字节) 
9
bfl111| | 2017-5-4 15:43 | 只看该作者
程序可以用,就是需要在写入数据之前失能保护快和保护状态寄存器。我的stm8l单片机,miso引脚是这么配置的
void SPI_Fram_Init(void)
{
    //mb85
  GPIO_Init(GPIOB, GPIO_Pin_2, GPIO_Mode_Out_PP_High_Fast);    //CS
  GPIO_Init(GPIOD, GPIO_Pin_7, GPIO_Mode_Out_PP_High_Fast);              //HOLD  
  GPIO_Init( GPIOB, GPIO_Pin_4, GPIO_Mode_Out_PP_High_Fast  );   // SDN PB4   GPIO_Mode_Out_PP_High_Slow
  GPIO_Init( GPIOD, GPIO_Pin_6, GPIO_Mode_Out_PP_High_Fast  );   //wp

  GPIO_Init( GPIOB, GPIO_Pin_5, GPIO_Mode_Out_PP_High_Fast );    // SCK PB5  
  GPIO_Init( GPIOB, GPIO_Pin_6, GPIO_Mode_Out_PP_High_Fast  );    // MOSI PB6  
  GPIO_Init( GPIOB, GPIO_Pin_7, GPIO_Mode_In_FL_No_IT );          // MISO PB7  

      //设备时钟使能
    CLK_PeripheralClockConfig(CLK_Peripheral_SPI1, ENABLE);
    //默认初始化
    SPI_DeInit(SPI1);
    //SPI初始化
    SPI_Init(SPI1,
             SPI_FirstBit_MSB,
             SPI_BaudRatePrescaler_8,
             SPI_Mode_Master,
             SPI_CPOL_Low,
             SPI_CPHA_1Edge,
             SPI_Direction_2Lines_FullDuplex,
             SPI_NSS_Soft,
             0x07);
    //SPI_ITConfig(SPI2, SPI_IT_RXNE, DISABLE);
    //使能SPI
    SPI_Cmd(SPI1, ENABLE);
  
}  

使用特权

评论回复
10
yongwong99| | 2017-7-11 20:09 | 只看该作者
mark!

使用特权

评论回复
11
苍天蓝耀| | 2021-7-1 10:11 | 只看该作者
Harvard 发表于 2016-4-25 14:39
同问 . 我是原在c8051f
上可用的c代码 移植到新唐M0 就无**常读出了 .一直读到0xff了  ...

你好,请问解决了吗,我这一直读出来的也是0xff

使用特权

评论回复
12
呐咯密密| | 2021-7-2 16:44 | 只看该作者
可以看一下时序图吗

使用特权

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

本版积分规则

1

主题

1

帖子

1

粉丝