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
谢谢!