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