]> git.sur5r.net Git - freertos/blob - FreeRTOS/Demo/CORTEX_STM32F103_Keil/spi_flash.c
Add FreeRTOS-Plus directory.
[freertos] / FreeRTOS / Demo / CORTEX_STM32F103_Keil / spi_flash.c
1 /******************** (C) COPYRIGHT 2007 STMicroelectronics ********************\r
2 * File Name          : spi_flash.c\r
3 * Author             : MCD Application Team\r
4 * Date First Issued  : 02/05/2007\r
5 * Description        : This file provides a set of functions needed to manage the\r
6 *                      communication between SPI peripheral and SPI M25P64 FLASH.\r
7 ********************************************************************************\r
8 * History:\r
9 * 04/02/2007: V0.2\r
10 * 02/05/2007: V0.1\r
11 ********************************************************************************\r
12 * THE PRESENT SOFTWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS\r
13 * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE TIME.\r
14 * AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY DIRECT,\r
15 * INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE\r
16 * CONTENT OF SUCH SOFTWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING\r
17 * INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.\r
18 *******************************************************************************/\r
19 \r
20 /* Includes ------------------------------------------------------------------*/\r
21 #include "spi_flash.h"\r
22 \r
23 /* Private typedef -----------------------------------------------------------*/\r
24 #define SPI_FLASH_PageSize 256\r
25 \r
26 #define WRITE      0x02  /* Write to Memory instruction */\r
27 #define WRSR       0x01  /* Write Status Register instruction */ \r
28 #define WREN       0x06  /* Write enable instruction */\r
29 \r
30 #define READ       0x03  /* Read from Memory instruction */\r
31 #define RDSR       0x05  /* Read Status Register instruction  */\r
32 #define RDID       0x9F  /* Read identification */\r
33 #define SE         0xD8  /* Sector Erase instruction */\r
34 #define BE         0xC7  /* Bulk Erase instruction */\r
35 \r
36 #define WIP_Flag   0x01  /* Write In Progress (WIP) flag */\r
37 \r
38 #define Dummy_Byte 0xA5\r
39 \r
40 /* Private define ------------------------------------------------------------*/\r
41 /* Private macro -------------------------------------------------------------*/\r
42 /* Private variables ---------------------------------------------------------*/\r
43 /* Private function prototypes -----------------------------------------------*/\r
44 /* Private functions ---------------------------------------------------------*/\r
45 \r
46 /*******************************************************************************\r
47 * Function Name  : SPI_FLASH_Init\r
48 * Description    : Initializes the peripherals used by the SPI FLASH driver.\r
49 * Input          : None\r
50 * Output         : None\r
51 * Return         : None\r
52 *******************************************************************************/\r
53 void SPI_FLASH_Init(void)\r
54 {\r
55   SPI_InitTypeDef  SPI_InitStructure;\r
56   GPIO_InitTypeDef GPIO_InitStructure;\r
57    \r
58   /* Enable SPI1 and GPIOA clocks */\r
59   RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1 | RCC_APB2Periph_GPIOA, ENABLE);\r
60   \r
61   /* Configure SPI1 pins: NSS, SCK, MISO and MOSI */\r
62   GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7;\r
63   GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;\r
64   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;\r
65   GPIO_Init(GPIOA, &GPIO_InitStructure);\r
66 \r
67   /* Configure PA.4 as Output push-pull, used as Flash Chip select */\r
68   GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;\r
69   GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;\r
70   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;\r
71   GPIO_Init(GPIOA, &GPIO_InitStructure);\r
72 \r
73   /* Deselect the FLASH: Chip Select high */\r
74   SPI_FLASH_ChipSelect(High);\r
75 \r
76   /* SPI1 configuration */ \r
77   SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;\r
78   SPI_InitStructure.SPI_Mode = SPI_Mode_Master;\r
79   SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;\r
80   SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;\r
81   SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;\r
82   SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;\r
83   SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_4;\r
84   SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;\r
85   SPI_InitStructure.SPI_CRCPolynomial = 7;\r
86   SPI_Init(SPI1, &SPI_InitStructure);\r
87   \r
88   /* Enable SPI1  */\r
89   SPI_Cmd(SPI1, ENABLE);   \r
90 }\r
91 \r
92 /*******************************************************************************\r
93 * Function Name  : SPI_FLASH_SectorErase\r
94 * Description    : Erases the specified FLASH sector.\r
95 * Input          : SectorAddr: address of the sector to erase.\r
96 * Output         : None\r
97 * Return         : None\r
98 *******************************************************************************/\r
99 void SPI_FLASH_SectorErase(u32 SectorAddr)\r
100 {\r
101   /* Send write enable instruction */\r
102   SPI_FLASH_WriteEnable();\r
103                         \r
104   /* Sector Erase */ \r
105   /* Select the FLASH: Chip Select low */\r
106   SPI_FLASH_ChipSelect(Low);            \r
107   /* Send Sector Erase instruction  */\r
108   SPI_FLASH_SendByte(SE);\r
109   /* Send SectorAddr high nibble address byte */\r
110   SPI_FLASH_SendByte((SectorAddr & 0xFF0000) >> 16);\r
111   /* Send SectorAddr medium nibble address byte */\r
112   SPI_FLASH_SendByte((SectorAddr & 0xFF00) >> 8);\r
113   /* Send SectorAddr low nibble address byte */\r
114   SPI_FLASH_SendByte(SectorAddr & 0xFF);\r
115   /* Deselect the FLASH: Chip Select high */\r
116   SPI_FLASH_ChipSelect(High);   \r
117 \r
118   /* Wait the end of Flash writing */\r
119   SPI_FLASH_WaitForWriteEnd();  \r
120 }\r
121 \r
122 /*******************************************************************************\r
123 * Function Name  : SPI_FLASH_BulkErase\r
124 * Description    : Erases the entire FLASH.\r
125 * Input          : None\r
126 * Output         : None\r
127 * Return         : None\r
128 *******************************************************************************/\r
129 void SPI_FLASH_BulkErase(void)\r
130 {       \r
131   /* Send write enable instruction */\r
132   SPI_FLASH_WriteEnable();      \r
133         \r
134   /* Bulk Erase */ \r
135   /* Select the FLASH: Chip Select low */\r
136   SPI_FLASH_ChipSelect(Low);            \r
137   /* Send Bulk Erase instruction  */\r
138   SPI_FLASH_SendByte(BE);\r
139   /* Deselect the FLASH: Chip Select high */\r
140   SPI_FLASH_ChipSelect(High);   \r
141                 \r
142   /* Wait the end of Flash writing */\r
143   SPI_FLASH_WaitForWriteEnd();          \r
144 }\r
145 \r
146 /*******************************************************************************\r
147 * Function Name  : SPI_FLASH_PageWrite\r
148 * Description    : Writes more than one byte to the FLASH with a single WRITE\r
149 *                  cycle(Page WRITE sequence). The number of byte can't exceed\r
150 *                  the FLASH page size.\r
151 * Input          : - pBuffer : pointer to the buffer  containing the data to be \r
152 *                    written to the FLASH.\r
153 *                  - WriteAddr : FLASH's internal address to write to.\r
154 *                  - NumByteToWrite : number of bytes to write to the FLASH,\r
155 *                    must be equal or less than "SPI_FLASH_PageSize" value. \r
156 * Output         : None\r
157 * Return         : None\r
158 *******************************************************************************/\r
159 void SPI_FLASH_PageWrite(u8* pBuffer, u32 WriteAddr, u16 NumByteToWrite)\r
160 {\r
161   /* Enable the write access to the FLASH */\r
162   SPI_FLASH_WriteEnable();              \r
163   \r
164   /* Select the FLASH: Chip Select low */\r
165   SPI_FLASH_ChipSelect(Low);       \r
166   /* Send "Write to Memory " instruction */    \r
167   SPI_FLASH_SendByte(WRITE);    \r
168   /* Send WriteAddr high nibble address byte to write to */\r
169   SPI_FLASH_SendByte((WriteAddr & 0xFF0000) >> 16);\r
170   /* Send WriteAddr medium nibble address byte to write to */\r
171   SPI_FLASH_SendByte((WriteAddr & 0xFF00) >> 8);  \r
172   /* Send WriteAddr low nibble address byte to write to */\r
173   SPI_FLASH_SendByte(WriteAddr & 0xFF);             \r
174   \r
175   /* while there is data to be written on the FLASH */\r
176   while(NumByteToWrite--) \r
177   {\r
178     /* Send the current byte */                 \r
179     SPI_FLASH_SendByte(*pBuffer);                      \r
180     /* Point on the next byte to be written */\r
181     pBuffer++; \r
182   }             \r
183   \r
184   /* Deselect the FLASH: Chip Select high */\r
185   SPI_FLASH_ChipSelect(High);\r
186   \r
187   /* Wait the end of Flash writing */\r
188   SPI_FLASH_WaitForWriteEnd();  \r
189 }\r
190 \r
191 /*******************************************************************************\r
192 * Function Name  : SPI_FLASH_BufferWrite\r
193 * Description    : Writes block of data to the FLASH. In this function, the\r
194 *                  number of WRITE cycles are reduced, using Page WRITE sequence.\r
195 * Input          : - pBuffer : pointer to the buffer  containing the data to be \r
196 *                    written to the FLASH.\r
197 *                  - WriteAddr : FLASH's internal address to write to.\r
198 *                  - NumByteToWrite : number of bytes to write to the FLASH.\r
199 * Output         : None\r
200 * Return         : None\r
201 *******************************************************************************/\r
202 void SPI_FLASH_BufferWrite(u8* pBuffer, u32 WriteAddr, u16 NumByteToWrite)\r
203 {\r
204   u8 NumOfPage = 0, NumOfSingle = 0, Addr = 0, count = 0, temp = 0;\r
205 \r
206   Addr = WriteAddr % SPI_FLASH_PageSize;\r
207   count = SPI_FLASH_PageSize - Addr;\r
208   NumOfPage =  NumByteToWrite / SPI_FLASH_PageSize;\r
209   NumOfSingle = NumByteToWrite % SPI_FLASH_PageSize;\r
210   \r
211   if(Addr == 0) /* WriteAddr is SPI_FLASH_PageSize aligned  */\r
212   {\r
213     if(NumOfPage == 0) /* NumByteToWrite < SPI_FLASH_PageSize */\r
214     {\r
215       SPI_FLASH_PageWrite(pBuffer, WriteAddr, NumByteToWrite);\r
216     }\r
217     else /* NumByteToWrite > SPI_FLASH_PageSize */ \r
218     {\r
219       while(NumOfPage--)\r
220       {\r
221         SPI_FLASH_PageWrite(pBuffer, WriteAddr, SPI_FLASH_PageSize);\r
222         WriteAddr +=  SPI_FLASH_PageSize;\r
223         pBuffer += SPI_FLASH_PageSize;  \r
224       }    \r
225      \r
226       SPI_FLASH_PageWrite(pBuffer, WriteAddr, NumOfSingle);      \r
227    }\r
228   }\r
229   else /* WriteAddr is not SPI_FLASH_PageSize aligned  */\r
230   {\r
231     if(NumOfPage== 0) /* NumByteToWrite < SPI_FLASH_PageSize */\r
232     {\r
233       if(NumOfSingle > count) /* (NumByteToWrite + WriteAddr) > SPI_FLASH_PageSize */\r
234       {\r
235         temp = NumOfSingle - count;\r
236         \r
237         SPI_FLASH_PageWrite(pBuffer, WriteAddr, count);\r
238         WriteAddr +=  count;\r
239         pBuffer += count; \r
240         \r
241         SPI_FLASH_PageWrite(pBuffer, WriteAddr, temp);          \r
242       }\r
243       else\r
244       {\r
245         SPI_FLASH_PageWrite(pBuffer, WriteAddr, NumByteToWrite);\r
246       }\r
247     }\r
248     else /* NumByteToWrite > SPI_FLASH_PageSize */\r
249     {\r
250       NumByteToWrite -= count;\r
251       NumOfPage =  NumByteToWrite / SPI_FLASH_PageSize;\r
252       NumOfSingle = NumByteToWrite % SPI_FLASH_PageSize;        \r
253       \r
254       SPI_FLASH_PageWrite(pBuffer, WriteAddr, count);\r
255       WriteAddr +=  count;\r
256       pBuffer += count;  \r
257      \r
258       while(NumOfPage--)\r
259       {\r
260         SPI_FLASH_PageWrite(pBuffer, WriteAddr, SPI_FLASH_PageSize);\r
261         WriteAddr +=  SPI_FLASH_PageSize;\r
262         pBuffer += SPI_FLASH_PageSize;  \r
263       }\r
264       \r
265       if(NumOfSingle != 0)\r
266       {\r
267         SPI_FLASH_PageWrite(pBuffer, WriteAddr, NumOfSingle);\r
268       }\r
269     }\r
270   }             \r
271 }\r
272 \r
273 /*******************************************************************************\r
274 * Function Name  : SPI_FLASH_BufferRead\r
275 * Description    : Reads a block of data from the FLASH.\r
276 * Input          : - pBuffer : pointer to the buffer that receives the data read \r
277 *                    from the FLASH.\r
278 *                  - ReadAddr : FLASH's internal address to read from.\r
279 *                  - NumByteToRead : number of bytes to read from the FLASH.\r
280 * Output         : None\r
281 * Return         : None\r
282 *******************************************************************************/\r
283 void SPI_FLASH_BufferRead(u8* pBuffer, u32 ReadAddr, u16 NumByteToRead)\r
284 {\r
285   /* Select the FLASH: Chip Select low */\r
286   SPI_FLASH_ChipSelect(Low);       \r
287   \r
288   /* Send "Read from Memory " instruction */\r
289   SPI_FLASH_SendByte(READ);      \r
290   \r
291   /* Send ReadAddr high nibble address byte to read from */\r
292   SPI_FLASH_SendByte((ReadAddr & 0xFF0000) >> 16);\r
293   /* Send ReadAddr medium nibble address byte to read from */\r
294   SPI_FLASH_SendByte((ReadAddr& 0xFF00) >> 8);  \r
295   /* Send ReadAddr low nibble address byte to read from */\r
296   SPI_FLASH_SendByte(ReadAddr & 0xFF);     \r
297         \r
298   while(NumByteToRead--) /* while there is data to be read */\r
299   {\r
300     /* Read a byte from the FLASH */                    \r
301     *pBuffer = SPI_FLASH_SendByte(Dummy_Byte);   \r
302     /* Point to the next location where the byte read will be saved */\r
303     pBuffer++;\r
304   }     \r
305   \r
306   /* Deselect the FLASH: Chip Select high */\r
307   SPI_FLASH_ChipSelect(High);           \r
308 }\r
309 \r
310 /*******************************************************************************\r
311 * Function Name  : SPI_FLASH_ReadID\r
312 * Description    : Reads FLASH identification.\r
313 * Input          : None\r
314 * Output         : None\r
315 * Return         : FLASH identification\r
316 *******************************************************************************/\r
317 u32 SPI_FLASH_ReadID(void)\r
318 {        \r
319   u32 Temp = 0, Temp0 = 0, Temp1 = 0, Temp2 = 0;\r
320 \r
321   /* Select the FLASH: Chip Select low */\r
322   SPI_FLASH_ChipSelect(Low);       \r
323   \r
324   /* Send "RDID " instruction */\r
325   SPI_FLASH_SendByte(0x9F);\r
326 \r
327   /* Read a byte from the FLASH */                      \r
328   Temp0 = SPI_FLASH_SendByte(Dummy_Byte);\r
329 \r
330   /* Read a byte from the FLASH */                      \r
331   Temp1 = SPI_FLASH_SendByte(Dummy_Byte);\r
332 \r
333   /* Read a byte from the FLASH */                      \r
334   Temp2 = SPI_FLASH_SendByte(Dummy_Byte);\r
335 \r
336   /* Deselect the FLASH: Chip Select high */\r
337   SPI_FLASH_ChipSelect(High);\r
338          \r
339   Temp = (Temp0 << 16) | (Temp1 << 8) | Temp2;\r
340 \r
341   return Temp;\r
342 }\r
343 \r
344 /*******************************************************************************\r
345 * Function Name  : SPI_FLASH_StartReadSequence\r
346 * Description    : Initiates a read data byte (READ) sequence from the Flash.\r
347 *                  This is done by driving the /CS line low to select the device,\r
348 *                  then the READ instruction is transmitted followed by 3 bytes\r
349 *                  address. This function exit and keep the /CS line low, so the\r
350 *                  Flash still being selected. With this technique the whole\r
351 *                  content of the Flash is read with a single READ instruction.\r
352 * Input          : - ReadAddr : FLASH's internal address to read from.\r
353 * Output         : None\r
354 * Return         : None\r
355 *******************************************************************************/\r
356 void SPI_FLASH_StartReadSequence(u32 ReadAddr)\r
357 {\r
358   /* Select the FLASH: Chip Select low */\r
359   SPI_FLASH_ChipSelect(Low);       \r
360   \r
361   /* Send "Read from Memory " instruction */\r
362   SPI_FLASH_SendByte(READ);      \r
363 \r
364 /* Send the 24-bit address of the address to read from -----------------------*/  \r
365   /* Send ReadAddr high nibble address byte */\r
366   SPI_FLASH_SendByte((ReadAddr & 0xFF0000) >> 16);\r
367   /* Send ReadAddr medium nibble address byte */\r
368   SPI_FLASH_SendByte((ReadAddr& 0xFF00) >> 8);  \r
369   /* Send ReadAddr low nibble address byte */\r
370   SPI_FLASH_SendByte(ReadAddr & 0xFF);  \r
371 }\r
372 \r
373 /*******************************************************************************\r
374 * Function Name  : SPI_FLASH_ReadByte\r
375 * Description    : Reads a byte from the SPI Flash.\r
376 *                  This function must be used only if the Start_Read_Sequence\r
377 *                  function has been previously called.\r
378 * Input          : None\r
379 * Output         : None\r
380 * Return         : Byte Read from the SPI Flash.\r
381 *******************************************************************************/\r
382 u8 SPI_FLASH_ReadByte(void)\r
383 {\r
384   return (SPI_FLASH_SendByte(Dummy_Byte));\r
385 }\r
386 \r
387 /*******************************************************************************\r
388 * Function Name  : SPI_FLASH_ChipSelect\r
389 * Description    : Selects or deselects the FLASH.\r
390 * Input          : State : level to be applied on the FLASH's ChipSelect pin.\r
391 * Output         : None\r
392 * Return         : None\r
393 *******************************************************************************/\r
394 void SPI_FLASH_ChipSelect(u8 State)\r
395 {\r
396   /* Set High or low the chip select line on PA.4 pin */\r
397   GPIO_WriteBit(GPIOA, GPIO_Pin_4, (BitAction)State);\r
398 }\r
399 \r
400 /*******************************************************************************\r
401 * Function Name  : SPI_FLASH_SendByte\r
402 * Description    : Sends a byte through the SPI interface and return the byte \r
403 *                  received from the SPI bus.\r
404 * Input          : byte : byte to send.\r
405 * Output         : None\r
406 * Return         : The value of the received byte.\r
407 *******************************************************************************/\r
408 u8 SPI_FLASH_SendByte(u8 byte)\r
409 {\r
410   /* Loop while DR register in not emplty */\r
411   while(SPI_GetFlagStatus(SPI1, SPI_FLAG_TXE) == RESET); \r
412 \r
413   /* Send byte through the SPI1 peripheral */   \r
414   SPI_SendData(SPI1, byte);     \r
415 \r
416   /* Wait to receive a byte */\r
417   while(SPI_GetFlagStatus(SPI1, SPI_FLAG_RXNE) == RESET);\r
418 \r
419   /* Return the byte read from the SPI bus */  \r
420   return SPI_ReceiveData(SPI1); \r
421 }\r
422 \r
423 /*******************************************************************************\r
424 * Function Name  : SPI_FLASH_SendHalfWord\r
425 * Description    : Sends a Half Word through the SPI interface and return the  \r
426 *                  Half Word received from the SPI bus.\r
427 * Input          : Half Word : Half Word to send.\r
428 * Output         : None\r
429 * Return         : The value of the received Half Word.\r
430 *******************************************************************************/\r
431 u16 SPI_FLASH_SendHalfWord(u16 HalfWord)\r
432 {\r
433   /* Loop while DR register in not emplty */\r
434   while(SPI_GetFlagStatus(SPI1, SPI_FLAG_TXE) == RESET); \r
435 \r
436   /* Send Half Word through the SPI1 peripheral */      \r
437   SPI_SendData(SPI1, HalfWord); \r
438 \r
439   /* Wait to receive a Half Word */\r
440   while(SPI_GetFlagStatus(SPI1, SPI_FLAG_RXNE) == RESET);\r
441 \r
442   /* Return the Half Word read from the SPI bus */  \r
443   return SPI_ReceiveData(SPI1); \r
444 }\r
445 \r
446 /*******************************************************************************\r
447 * Function Name  : SPI_FLASH_WriteEnable\r
448 * Description    : Enables the write access to the FLASH.\r
449 * Input          : None\r
450 * Output         : None\r
451 * Return         : None\r
452 *******************************************************************************/\r
453 void SPI_FLASH_WriteEnable(void)  \r
454 {\r
455   /* Select the FLASH: Chip Select low */\r
456   SPI_FLASH_ChipSelect(Low);    \r
457   \r
458   /* Send "Write Enable" instruction */\r
459   SPI_FLASH_SendByte(WREN);\r
460   \r
461   /* Deselect the FLASH: Chip Select high */\r
462   SPI_FLASH_ChipSelect(High);   \r
463 }\r
464 \r
465 /*******************************************************************************\r
466 * Function Name  : SPI_FLASH_WaitForWriteEnd\r
467 * Description    : Polls the status of the Write In Progress (WIP) flag in the  \r
468 *                  FLASH's status  register  and  loop  until write  opertaion\r
469 *                  has completed.  \r
470 * Input          : None\r
471 * Output         : None\r
472 * Return         : None\r
473 *******************************************************************************/\r
474 void SPI_FLASH_WaitForWriteEnd(void) \r
475 {\r
476   u8 FLASH_Status = 0;\r
477   \r
478   /* Select the FLASH: Chip Select low */\r
479   SPI_FLASH_ChipSelect(Low);\r
480         \r
481   /* Send "Read Status Register" instruction */\r
482   SPI_FLASH_SendByte(RDSR);\r
483   \r
484   /* Loop as long as the memory is busy with a write cycle */           \r
485   do\r
486   {     \r
487          \r
488     /* Send a dummy byte to generate the clock needed by the FLASH \r
489     and put the value of the status register in FLASH_Status variable */\r
490     FLASH_Status = SPI_FLASH_SendByte(Dummy_Byte);  \r
491                                                                                                                                         \r
492   } while((FLASH_Status & WIP_Flag) == SET); /* Write in progress */  \r
493 \r
494   /* Deselect the FLASH: Chip Select high */\r
495   SPI_FLASH_ChipSelect(High);           \r
496 }\r
497 \r
498 /******************* (C) COPYRIGHT 2007 STMicroelectronics *****END OF FILE****/\r