我用STM32F429与AT45DB321通讯,配置好SPI后,读取321的ID,读出来的数据都是FF是怎么回事呢 spi代码如下
- #include "spi.h"
- void SPIx_Init(void);
- uint8_t SPIx_ReadByte(void);
- uint8_t SPIx_SendByte(uint8_t byte);
- void SPIx_Init(void)
- {
- GPIO_InitTypeDef GPIO_InitStructure;
- SPI_InitTypeDef SPI_InitStructure;
-
- RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);//ʹÄÜGPIOBʱÖÓ
- RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE);//ʹÄÜSPI1ʱÖÓ
-
- //GPIOB13,14,15³õʼ»¯ÉèÖÃ
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13|GPIO_Pin_14|GPIO_Pin_15;//PB3~5¸´Óù¦ÄÜÊä³ö
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;//¸´Óù¦ÄÜ
- GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//ÍÆÍìÊä³ö
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100MHz
- GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//ÉÏÀ
- GPIO_Init(GPIOB, &GPIO_InitStructure);//³õʼ»¯
-
- GPIO_PinAFConfig(GPIOB,GPIO_PinSource13,GPIO_AF_SPI2); //PB13¸´ÓÃΪ SPI2
- GPIO_PinAFConfig(GPIOB,GPIO_PinSource14,GPIO_AF_SPI2); //PB14¸´ÓÃΪ SPI2
- GPIO_PinAFConfig(GPIOB,GPIO_PinSource15,GPIO_AF_SPI2); //PB51¸´ÓÃΪ 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ÍâÉè
-
- }
- /*******************************************************************************
- * Function Name : SPIx_ReadByte
- * Description : Reads a byte from the SPI Flash.
- * This function must be used only if the Start_Read_Sequence
- * function has been previously called.
- * Input : None
- * Output : None
- * Return : Byte Read from the SPI Flash.
- *******************************************************************************/
- uint8_t SPIx_ReadByte(void)
- {
- return (SPIx_SendByte(Dummy_Byte));
- }
- /*******************************************************************************
- * Function Name : SPIx_SendByte
- * Description : Sends a byte through the SPI interface and return the byte
- * received from the SPI bus.
- * Input : byte : byte to send.
- * Output : None
- * Return : The value of the received byte.
- *******************************************************************************/
- uint8_t SPIx_SendByte(uint8_t byte)
- {
- /* Loop while DR register in not emplty */
- while(SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE) == RESET);
-
- /* Send byte through the SPI1 peripheral */
- SPI_I2S_SendData(SPI2, byte);
-
- /* Wait to receive a byte */
- while(SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_RXNE) == RESET);
-
- /* Return the byte read from the SPI bus */
- return SPI_I2S_ReceiveData(SPI2);
- }
复制代码 SPI头文件代码
- #ifndef __SPI_H
- #define __SPI_H
- #include "sys.h"
- #include "delay.h"
- #define Dummy_Byte 0xA5
- extern void SPIx_Init(void);
- extern uint8_t SPIx_ReadByte(void);
- extern uint8_t SPIx_SendByte(uint8_t byte);
- #endif
复制代码 读状态
- /*******************************************************************************
- Ãû ³Æ£º uint8_t AT45_GetStatus(void)
- ¹¦ ÄÜ£º ¶ÁÈ¡ flash ״̬¼Ä´æÆ÷
- ÊäÈë²ÎÊý£º ÎÞ
- Êä³ö²ÎÊý£º ÎÞ
- ·µ »Ø£º µ±Ç°×´Ì¬
- Æä Ëü£º ÎÞ
- *******************************************************************************/
- uint8_t AT45_GetStatus(void)
- {
- uint8_t state;
- AT45_Chip_Select_ENABLE();
- SPIx_SendByte(AT45_CMD_READ_STATUS);
-
- state = SPIx_SendByte(Dummy_Byte);
- AT45_Chip_Select_DISABLE();
- if(state & 0x80)
- {
- return 1;
- }
- else
- {
- return 0;
- }
- }
复制代码 读ID
- void AT45DBXX_Read_ID(u8 *IData)
- {
-
- uint8_t state;
-
- do{
- state = AT45_GetStatus();
- }while(!state);
- AT45_Chip_Select_ENABLE();
- SPIx_SendByte(Read_ID);
- IData[0]= SPIx_SendByte(0x00);
- IData[1]= SPIx_SendByte(0x00);
- IData[2]= SPIx_SendByte(0x00);
- IData[3]= SPIx_SendByte(0x00);
- AT45_Chip_Select_DISABLE();
- }
复制代码 AT45DBXX_Read_ID(ID); 函数调用读取,调试发现ID的内容都是FF
|
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;//PB13~15¸´Óù¦ÄÜÊä³ö
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;//
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//ÍÆÍìÊä³ö
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//50MHz
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//ÉÏÀ
GPIO_Init(GPIOB, &GPIO_InitStructure);
}
一页的数据是528个字节,那就是528个数,比我想从第一页的第12个数开始读,连续读取100个,这种情况是最简单的,应该是直接读取就行,调用函数把第一页的数据都读到缓冲区,然后从缓冲区的第12项开始读,连续读100个数(一个for循环读取),
第二种情况 :从第一页的第12个数开始读,连续读528个字节,这种情况相对复杂,首先要判断从第12个开始+528的情况是不是大于一页,很显然大于1页的数据了,那就要读两次缓冲区,第一次读缓冲区从第12个字开始读,一直读到结尾,放在一个数组内,第二次读的时候从第二页的第0个字节开始读,读取528+12-528=12个,第二页只需要读取12个就可以了,然后把数组1和数组2合并
第三种情况:从第一页的第12个数开始读,连续读取1100个字节的数据,这种情况更加复杂,首先要判断12+1100的情况÷528的整数是几,很显然整数是2 ,余数是56,这样的话就需要读次缓冲区,第一次读从第12个开始,一直读到结尾,第二次读需要读取整页的数据,第三次的话需要读取56个数据,最后把三个数组合成一个返回。
如果有再多的数据基本上都和第三组相同了
应用的时候我们常常要写入不定量的数据,直接调用“页写入”函数并不是特别方便,
所以我们在它的基础上编写了“不定量数据写入”的函数,基实现见代码清单 24-12。
代码清单 24-12 不定量数据写入
1 /**
2 * @brief 对 FLASH 写入数据,调用本函数写入数据前需要先擦除扇区
3 * @param pBuffer,要写入数据的指针
4 * @param WriteAddr,写入地址
5 * @param NumByteToWrite,写入数据长度
6 * @retval 无
7 */
8 void SPI_FLASH_BufferWrite(u8* pBuffer, u32 WriteAddr, u16 NumByteToWrite)
9 {
10 u8 NumOfPage = 0, NumOfSingle = 0, Addr = 0, count = 0, temp = 0;
11
12 /*mod 运算求余,若 writeAddr 是 SPI_FLASH_PageSize 整数倍,运算结果 Addr 值为
0*/
13 Addr = WriteAddr % SPI_FLASH_PageSize;
15 /*差 count 个数据值,刚好可以对齐到页地址*/
16 count = SPI_FLASH_PageSize - Addr;
17 /*计算出要写多少整数页*/
18 NumOfPage = NumByteToWrite / SPI_FLASH_PageSize;
19 /*mod 运算求余,计算出剩余不满一页的字节数*/
20 NumOfSingle = NumByteToWrite % SPI_FLASH_PageSize;
21
22 /* Addr=0,则 WriteAddr 刚好按页对齐 aligned */
23 if (Addr == 0)
24 {
25 /* NumByteToWrite < SPI_FLASH_PageSize */
26 if (NumOfPage == 0)
27 {
28 SPI_FLASH_PageWrite(pBuffer, WriteAddr, NumByteToWrite);
29 }
30 else /* NumByteToWrite > SPI_FLASH_PageSize */
31 {
32 /*先把整数页都写了*/
33 while (NumOfPage--)
34 {
35 SPI_FLASH_PageWrite(pBuffer, WriteAddr, SPI_FLASH_PageSize);
36 WriteAddr += SPI_FLASH_PageSize;
37 pBuffer += SPI_FLASH_PageSize;
38 }
39
40 /*若有多余的不满一页的数据,把它写完*/
41 SPI_FLASH_PageWrite(pBuffer, WriteAddr, NumOfSingle);
42 }
43 }
44 /* 若地址与 SPI_FLASH_PageSize 不对齐 */
45 else
46 {
47 /* NumByteToWrite < SPI_FLASH_PageSize */
48 if (NumOfPage == 0)
49 {
50 /*当前页剩余的 count 个位置比 NumOfSingle 小,写不完*/
51 if (NumOfSingle > count)
52 {
53 temp = NumOfSingle - count;
54
55 /*先写满当前页*/
56 SPI_FLASH_PageWrite(pBuffer, WriteAddr, count);
57 WriteAddr += count;
58 pBuffer += count;
59
60 /*再写剩余的数据*/
61 SPI_FLASH_PageWrite(pBuffer, WriteAddr, temp);
62 }
63 else /*当前页剩余的 count 个位置能写完 NumOfSingle 个数据*/
64 {
65 SPI_FLASH_PageWrite(pBuffer, WriteAddr, NumByteToWrite);
66 }
67 }
68 else /* NumByteToWrite > SPI_FLASH_PageSize */
69 {
70 /*地址不对齐多出的 count 分开处理,不加入这个运算*/
71 NumByteToWrite -= count;
72 NumOfPage = NumByteToWrite / SPI_FLASH_PageSize;
73 NumOfSingle = NumByteToWrite % SPI_FLASH_PageSize;
74
75 SPI_FLASH_PageWrite(pBuffer, WriteAddr, count);
76 WriteAddr += count;
77 pBuffer += count;
78
79 /*把整数页都写了*/
80 while (NumOfPage--)
81 {
82 SPI_FLASH_PageWrite(pBuffer, WriteAddr, SPI_FLASH_PageSize);
83 WriteAddr += SPI_FLASH_PageSize;
84 pBuffer += SPI_FLASH_PageSize;
85 }
86 /*若有多余的不满一页的数据,把它写完*/
87 if (NumOfSingle != 0)
88 {
89 SPI_FLASH_PageWrite(pBuffer, WriteAddr, NumOfSingle);
90 }
91 }
92 }
93 }
分页(本型号芯片每页 8个字节),见表 23-2。通过“整除”计算要写入的数据
NumByteToWrite 能写满多少“完整的页”,计算得的值存储在 NumOfPage 中,但有时数
据不是刚好能写满完整页的,会多一点出来,通过“求余”计算得出“不满一页的数据个
数”就存储在 NumOfSingle 中。计算后通过按页传输 NumOfPage 次整页数据及最后的
NumOfSing 个数据,使用页传输,比之前的单个字节数据传输要快很多。
除了基本的分页传输,还要考虑首地址的问题,见表 23-3。若首地址不是刚好对齐到
页的首地址,会需要一个 count值,用于存储从该首地址开始写满该地址所在的页,还能
写多少个数据。实际传输时,先把这部分 count个数据先写入,填满该页,然后把剩余的
数据(NumByteToWrite-count),再重复上述求出 NumOPage及 NumOfSingle的过程,按页
传输到 EEPROM。
1. 若 writeAddress=16,计算得 Addr=16%8= 0 ,count=8-0= 8;
2. 同时,若 NumOfPage=22,计算得 NumOfPage=22/8= 2,NumOfSingle=22%8= 6。
4. 若 writeAddress=17,计算得 Addr=17%8= 1,count=8-1= 7;
5. 同时,若 NumOfPage=22,
6. 先把 count 去掉,特殊处理,计算得新的 NumOfPage=22-7= 15
7. 计算得 NumOfPage=15/8= 1,NumOfSingle=15%8= 7。