TI中文支持网
TI专业的中文技术问题搜集分享网站

msp430F5438 spi与铁电存储器FM25H20

F5438的spi与FM25H20通信,现在读取FM25H20的状态寄存器返回的也是0xff,给FM25H20的任一地址写数据,然后再读该地址的数据,返回的也是0xFF,不论什么操作,FM25返回的都是0xff。不知道出了什么问题。。。

#include "msp430x54x.h" #include <stdlib.h> #include <stdio.h> #include <string.h>

#define WREN_CMD 0x06    //允许写操作 

#define WRDI_CMD 0x04    //禁止写

 #define RDSR_CMD 0x05    //读状态寄存器

 #define WRSR_CMD 0x01    //写状态寄存器

#define READ_CMD 0x03    //读存储器数据

#define WRITE_CMD 0x02   //写存储器数据

#define SLEEP_CMD 0xB9  //进入睡眠模式

#define DUMY_CMD  0      //产生读时序

 

unsigned char FmTxData=0x55;

unsigned char FmRxData;

unsigned char temp;

 unsigned char temp1;

unsigned char rxdata;

void  WrMemData(long int addr, unsigned char c);

unsigned char RdMemData(long int addr);

 unsigned char RdMemStatReg();

 

 

void Init_SPI1(void)

{      P3SEL |=0x80;                       //P3.7功能选择为SPI1,–SIMO    

P3SEL &=0xBF;                       //p3.6端口模式    

P5SEL |=0x30;                       //P5.4/5功能选择为SPI1,—SOMI,CLK        

P3DIR  |= 0x40;                    //P3.6输出,控制FM片选信号    

P4DIR  |= 0x03;               //p4.0/1输出,控制wp和hold        

P3DIR |=0x80;   // SIMO output    

P5DIR &=0xEF;    // SOMI input    

P5DIR |=0x20;     //CLK output                

P3OUT  |= 0x40;     //CS is high    

P4OUT  |= 0x03;     // wp and hold are high                

UCB1CTL1 |= UCSWRST;             // 复位SPI1状态机        

UCB1CTL0 |= UCMST+UCSYNC+UCCKPL+UCMSB ; // 3-pin, 8位, SPI master, Clock polarity high, MSB    

UCB1CTL1 |= UCSSEL_2  ;                        // 选择SCK参考源为SMCLK    

UCB1BR0   = 0x02  ;                            // SCK = SMCLK/2    

UCB1BR1   = 0 ;   

 //UCA0MCTL = 0;        

UCB1CTL1 &=~UCSWRST ;               // SPI1状态机使能

}

 

unsigned char TransceiveSPI1 (unsigned char txdata)   {       while (!(UCB1IFG & UCTXIFG));             // wait until last SPI-Transmission is finished       UCB1TXBUF = txdata;                         // send 8 clocks "txdata" and SPI-clocks       while (!(UCB1IFG & UCRXIFG));           // wait until one byte is received       rxdata = UCB1RXBUF;         return rxdata;   }

 

/*char RxTxSPI1(unsigned char c)   //发送接收程序 { //////   while (!(UCB1IFG&UCTXIFG));           // USCI_B1 TX buffer ready? //   SPI1Rxflg=0;    UCB1TXBUF=c;    while(!SPI1Rxflg);    SPI1Rxflg=0;    return UCB1RXBUF; }    TxSPI1(char c)   //发送程序 {    UCB1TXBUF=c; } char RxSPI1()    //接收程序 {     char temp;     temp= UCB1RXBUF;     return temp; }  */

void MemEnable()       //发送器件写操作命令 {   P3OUT &=~BIT6;   TransceiveSPI1(WREN_CMD);   P3OUT |=BIT6; }

void MemDisable()      //发送器件写器件禁止 {   P3OUT &=~BIT6;   TransceiveSPI1(WRDI_CMD);  // if(TxFlg==1)   P3OUT |=BIT6;

}

void WrMemStatReg(unsigned char c)//写状态寄存器 {   MemEnable();   P3OUT &=~BIT6;  // TxFlg=0;   TransceiveSPI1(WRSR_CMD);

  TransceiveSPI1(c);    P3OUT |=BIT6; }

unsigned char RdMemStatReg()//读寄存器 { //  unsigned char temp;   P3OUT &=~BIT6;   TransceiveSPI1(RDSR_CMD);   temp1=TransceiveSPI1(DUMY_CMD); //  =RxSPI1();   P3OUT |=BIT6;   return temp1; }

void  WrMemData(long int  addr, unsigned char c)//写一个字节数据到指定地址 {   P3OUT &=~BIT6;   TransceiveSPI1(WREN_CMD);

   // MemEnable();  // P3OUT &=0xBF;  // TxFlg=0;

  TransceiveSPI1(WRITE_CMD);   TransceiveSPI1((addr&0xff0000)>>16);   TransceiveSPI1((addr&0x00ff00)>>8);   TransceiveSPI1(addr&0x0000ff);     TransceiveSPI1(c);   P3OUT |=BIT6; }

unsigned char RdMemData(long int addr)//从指定地址读一个字节 { //  unsigned char temp;   P3OUT &=~BIT6;   TransceiveSPI1(READ_CMD);   TransceiveSPI1((addr&0xff0000)>>16);   TransceiveSPI1((addr&0x00ff00)>>8);   TransceiveSPI1(addr&0x0000ff);   temp=TransceiveSPI1(DUMY_CMD);    // TxSPI1(DUMY_CMD); //  temp=RxSPI1();

  P3OUT |=BIT6;   return temp; }

Lina Lian:

Jiejie Dai,

你好!按照你的描述,你应该并没有成功控制FM25H20。建议您先让msp430SPI输出数据用示波器观察,根据FM25H20的数据手册上的时序要求,看看你编写的时序是否符合?

确定了这一点之后,还需要遵循FM25H20的读写操作流程,下面是我在网上查到的。你检查一下你的主程序,是不是符合下面的操作流程?

写操作    FM25H20写操作先发送WREN指令,再发送WRITE指令。WRITE指令后接3个字节的地址,这24位地址中的高6位为任意码,低18位地址为要写入的首字节数据的有效地址,该地址后面为要写入的数据。若输人的数据大于1个,那么第一个数据后的数据存储地址由FM25H20内部依次增加给出。当地址达到3FFFFH时,地址计数器置为00000H,输入数据是以最高有效位(MSB)在前,最低有效位(LSB)在后的顺序传输的。读操作    在S信号下降沿发送READ指令,在READ指令后紧接发送3个字节的地址。当发送完指令和地址后,可忽略数据线操作。数据总线等待8个时钟信号,依次读取数据。当地址达到3FFFFH时,地址计数器置为00000H,输入数据是以MSB在前,LSB在后的顺序传输的。

上述两点都符合了,还是不可以的话,换个FM25H20试试。

总之,一步一步排查问题,看看到底哪里出问题了。

希望对你有帮助!

Jiejie Dai:

回复 Lina Lian:

通过示波器观测,MSP430 SIMO输出数据波形正确,CLK时钟信号正常,片选CS信号正常,WP和Hold引脚输出设置为高电平,

我的思路是msp430输出一个数据到FM25H20的某一地址,例如0x0002ff,然后从该地址读取数据,如果发送的数据和读回的数据相等,

则表示通信正常。现在的情况时msp430可以发送,SIMO数据正常,而FM25地址读取的数据一直为0xFF,用示波器观测,输出无信号。

msp收发都未采用中断模式。

Jiejie Dai:

回复 Lina Lian:

通过示波器观测,MSP430 SIMO输出数据波形正确,CLK时钟信号正常,片选CS信号正常,WP和Hold引脚输出设置为高电平,

我的思路是msp430输出一个数据到FM25H20的某一地址,例如0x0002ff,然后从该地址读取数据,如果发送的数据和读回的数据相等,

则表示通信正常。现在的情况时msp430可以发送,SIMO数据正常,而FM25地址读取的数据一直为0xFF,用示波器观测,输出无信号。

msp收发都未采用中断模式。

Lina Lian:

回复 Jiejie Dai:

Jiejie Dai,

你的验证思路是没有问题的。据你的描述,目前这只是完成了第一步,表明你的MSP430 SPI设置正确。接着查第二步,看看是否遵循FM25H20的读写操作流程。

O(∩_∩)O~

Jiejie Dai:

回复 Lina Lian:

真的非常感谢您耐心的回答及帮我查阅的资料,心存感激和感恩。

对FM25H20的读写操作,首先发送op-code,代码如下。片选CS信号由msp430控制,当对FM25进行操作是,片选信号拉低,发送op-code,然后发送地址,发送或接受数据,操作完成后,片选信号拉低。我现在不确定是什么地方出现纰漏或者还有我没考虑到的方面

void MemEnable()       //发送器件写操作命令

 {   P3OUT &=~BIT6;  

 TransceiveSPI1(WREN_CMD);  

P3OUT |=BIT6; }

void MemDisable()      //发送器件写器件禁止

 {   P3OUT &=~BIT6;

  TransceiveSPI1(WRDI_CMD);  

  P3OUT |=BIT6;

}

void WrMemStatReg(unsigned char c)//写状态寄存器

 {   MemEnable();  

 P3OUT &=~BIT6;    

TransceiveSPI1(WRSR_CMD);

  TransceiveSPI1(c);   

P3OUT |=BIT6; }

unsigned char RdMemStatReg()//读寄存器

 {

   P3OUT &=~BIT6;  

TransceiveSPI1(RDSR_CMD);

  temp1=TransceiveSPI1(DUMY_CMD);

  P3OUT |=BIT6;  

 return temp1; }

void  WrMemData(long int  addr, unsigned char c)//写一个字节数据到指定地址

 {   P3OUT &=~BIT6;

  TransceiveSPI1(WREN_CMD);

     TransceiveSPI1(WRITE_CMD);  

TransceiveSPI1((addr&0xff0000)>>16);  

TransceiveSPI1((addr&0x00ff00)>>8);  

 TransceiveSPI1(addr&0x0000ff);    

TransceiveSPI1(c);  

 P3OUT |=BIT6; }

unsigned char RdMemData(long int addr)//从指定地址读一个字节

 { 

 P3OUT &=~BIT6;  

 TransceiveSPI1(READ_CMD);  

 TransceiveSPI1((addr&0xff0000)>>16);  

 TransceiveSPI1((addr&0x00ff00)>>8);  

 TransceiveSPI1(addr&0x0000ff);

  temp=TransceiveSPI1(DUMY_CMD);

  P3OUT |=BIT6;  

 return temp; }

Lina Lian:

回复 Jiejie Dai:

Jiejie Dai,

在读数据时, 数据总线等待8个时钟信号,依次读取数据。而在你的读取字节函数中,如下所示,

Jiejie Dai temp=TransceiveSPI1(DUMY_CMD);

你直接返回的是temp,并没有等待8个时钟信号。在这下面再加一句

 temp=TransceiveSPI1(DUMY_CMD);

第一个用于等待,第二句用于读回数据。

你试试看行不行?

希望对你有帮助!O(∩_∩)O~

Jiejie Dai:

回复 Lina Lian:

Lina Lian

Jiejie Dai,

在读数据时, 数据总线等待8个时钟信号,依次读取数据。而在你的读取字节函数中,如下所示,

Jiejie Dai temp=TransceiveSPI1(DUMY_CMD);

你直接返回的是temp,并没有等待8个时钟信号。在这下面再加一句

 temp=TransceiveSPI1(DUMY_CMD);

第一个用于等待,第二句用于读回数据。

你试试看行不行?

希望对你有帮助!O(∩_∩)O~

Jiejie Dai:

回复 Lina Lian:

Lina Lian

Jiejie Dai,

我下载了FM25H20的数据手册看了一下,对读取数据的控制,中文表述有误,你原来的理解应该是正确的。如下图所示,应该发完地址后,即可直接读数,datasheet中原文表述为:

After the op-code and address are complete, the D line is ignored. The bus master issues 8 clocks, with one bit read out for each.

故不需要等待8个时钟周期。

我看了你的SPI的程序,有以下几个建议:

1. 建议你把SPI读,写函数分开写,不要用一个TransceiveSPI1综合所有,对于FM25H20的操作而言,要不只需读,要不只需写,我没有看到需要同时读和写的。

2.建议P1OUT的状态控制只控制有LED灯的那个端口,例如: P1OUT |= BIT0; P1OUT &= ~BIT0;

3. 注意, 上电1ms后才可将S拉低。原文为:

The FM25H20 is not accessible for a period of time(1 ms) after power up. Users must comply with thetiming parameter tPU, which is the minimum timefrom VDD (min) to the first /S low.

4. 严格用波器检查一下所有SPI操作是否符合数据手册11页对时序的要求。

5.验证一下MSP430的SPI是否可成功发送和接收。

希望对你有帮助!O(∩_∩)O~

camera freak:

回复 Jiejie Dai:

您好,我现在也在做FM25H20的测试,读出来的数也是FF 

希望您能指点下,给出您宝贵的经验。

邮箱:freak.zhou@linkhope.co

谢谢!

赞(0)
未经允许不得转载:TI中文支持网 » msp430F5438 spi与铁电存储器FM25H20
分享到: 更多 (0)