1 /*
2 * <h2><center>© COPYRIGHT 2014 STMicroelectronics</center></h2>
3 *
4 * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
5 * You may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at:
7 *
8 * http://www.st.com/software_license_agreement_liberty_v2
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "spi.h"
18 #include "w25qxx.h"
19 #include "stm32f4xx_conf.h"
20 #include "prt_task.h"
21
22 #define BUFFER_SIZE 4096
23
24 u16 W25X_TYPE = W25Q128;
25
W25qxxInit(void)26 void W25qxxInit(void)
27 {
28 GPIO_InitTypeDef gpioInitStruct;
29
30 RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOG, ENABLE);
31 RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);
32
33 gpioInitStruct.GPIO_PuPd = GPIO_PuPd_UP;
34 gpioInitStruct.GPIO_Pin = GPIO_Pin_14;
35 gpioInitStruct.GPIO_Speed = GPIO_Speed_100MHz;
36 gpioInitStruct.GPIO_Mode = GPIO_Mode_OUT;
37 gpioInitStruct.GPIO_OType = GPIO_OType_PP;
38 GPIO_Init(GPIOB, &gpioInitStruct);
39
40 gpioInitStruct.GPIO_Pin = GPIO_Pin_7;
41 GPIO_Init(GPIOG, &gpioInitStruct);
42
43 GPIO_SetBits(GPIOG,GPIO_Pin_7);
44 W25X_CS = 1; /* 1, register status */
45 Spi1Init();
46 Spi1SetSpeed(SPI_BaudRatePrescaler_4);
47 W25X_TYPE = W25qxxReadID();
48 }
49
W25qxxReadSR(void)50 u8 W25qxxReadSR(void)
51 {
52 u8 byte = 0;
53 W25X_CS = 0; /* 0, register status */
54 Spi1ReadWriteByte(W25X_READSTATUSREG);
55 byte = Spi1ReadWriteByte(0Xff);
56 W25X_CS = 1; /* 1, register status */
57 return byte;
58 }
59
W25qxxWriteSR(u8 sr)60 void W25qxxWriteSR(u8 sr)
61 {
62 W25X_CS = 0; /* 0, register status */
63 Spi1ReadWriteByte(W25X_WRITESTATUSREG);
64 Spi1ReadWriteByte(sr);
65 W25X_CS = 1; /* 1, register status */
66 }
67
W25qxxWriteEnable(void)68 void W25qxxWriteEnable(void)
69 {
70 W25X_CS = 0; /* 0, register status */
71 Spi1ReadWriteByte(W25X_WRITEENABLE);
72 W25X_CS = 1; /* 1, register status */
73 }
74
W25qxxWriteDisable(void)75 void W25qxxWriteDisable(void)
76 {
77 W25X_CS = 0; /* 0, register status */
78 Spi1ReadWriteByte(W25X_WRITEDISABLE);
79 W25X_CS = 1; /* 1, register status */
80 }
81
W25qxxReadID(void)82 u16 W25qxxReadID(void)
83 {
84 u16 tmp = 0;
85 W25X_CS = 0; /* 0, register status */
86 Spi1ReadWriteByte(0x90);
87 Spi1ReadWriteByte(0x00);
88 Spi1ReadWriteByte(0x00);
89 Spi1ReadWriteByte(0x00);
90 tmp |= Spi1ReadWriteByte(0xFF) << 8;
91 tmp |= Spi1ReadWriteByte(0xFF);
92 W25X_CS = 1; /* 1, register status */
93 return tmp;
94 }
95
W25qxxRead(u8 * pBuffer,u32 readAddr,u16 NumByteToRead)96 void W25qxxRead(u8 *pBuffer, u32 readAddr, u16 NumByteToRead)
97 {
98 W25X_CS = 0; /* 0, register status */
99 Spi1ReadWriteByte(W25X_READDATA);
100 Spi1ReadWriteByte((u8)((readAddr) >> 16));
101 Spi1ReadWriteByte((u8)((readAddr) >> 8));
102 Spi1ReadWriteByte((u8)readAddr);
103 for(u16 i = 0; i < NumByteToRead; i++) {
104 pBuffer[i] = Spi1ReadWriteByte(0XFF);
105 }
106 W25X_CS = 1; /* 1, register status */
107 }
108
W25qxxWritePage(u8 * pBuffer,u32 writeAddr,u16 numByteToWrite)109 void W25qxxWritePage(u8 *pBuffer, u32 writeAddr, u16 numByteToWrite)
110 {
111 W25qxxWriteEnable();
112 W25X_CS = 0; /* 0, register status */
113 Spi1ReadWriteByte(W25X_PAGEPROGRAM);
114 Spi1ReadWriteByte((u8)((writeAddr) >> 16));
115 Spi1ReadWriteByte((u8)((writeAddr) >> 8));
116 Spi1ReadWriteByte((u8)writeAddr);
117 for(u16 i = 0; i < numByteToWrite; i++) {
118 Spi1ReadWriteByte(pBuffer[i]);
119 }
120 W25X_CS = 1; /* 1, register status */
121 W25qxxWaitBusy();
122 }
123
W25qxxWriteNoCheck(u8 * pBuffer,u32 writeAddr,u16 numByteToWrite)124 void W25qxxWriteNoCheck(u8 *pBuffer, u32 writeAddr, u16 numByteToWrite)
125 {
126 u16 pageRemain;
127 pageRemain = 256 - writeAddr % 256;
128 if (numByteToWrite <= pageRemain) {
129 pageRemain = numByteToWrite;
130 }
131 while(1) {
132 W25qxxWritePage(pBuffer, writeAddr, pageRemain);
133 if(numByteToWrite == pageRemain) {
134 break;
135 } else {
136 pBuffer += pageRemain;
137 writeAddr += pageRemain;
138 numByteToWrite -= pageRemain;
139 if (numByteToWrite > 256) {
140 pageRemain = 256;
141 }else {
142 pageRemain = numByteToWrite;
143 }
144 }
145 }
146 }
147
148 u8 w25qxxBuffer[BUFFER_SIZE];
W25qxxWrite(u8 * pBuffer,u32 writeAddr,u16 numByteToWrite)149 void W25qxxWrite(u8 *pBuffer, u32 writeAddr, u16 numByteToWrite)
150 {
151 u16 i;
152 u32 secPos;
153 u16 secOff;
154 u16 secRemain;
155 u8 *w25qxxBuf = w25qxxBuffer;
156
157 secPos = writeAddr / BUFFER_SIZE;
158 secOff = writeAddr % BUFFER_SIZE;
159 secRemain = BUFFER_SIZE - secOff;
160
161 if(numByteToWrite <= secRemain) {
162 secRemain = numByteToWrite;
163 }
164 while(1) {
165 W25qxxRead(w25qxxBuf, secPos * BUFFER_SIZE, BUFFER_SIZE);
166 for(i = 0; i < secRemain; i++) {
167 if(w25qxxBuf[secOff + i] != 0XFF) {
168 break;
169 }
170 }
171 if( i < secRemain) {
172 W25qxxEraseSector(secPos);
173 for(i = 0; i < secRemain; i++) {
174 w25qxxBuf[i + secOff] = pBuffer[i];
175 }
176 W25qxxWriteNoCheck(w25qxxBuf, secPos * BUFFER_SIZE, BUFFER_SIZE);
177 } else {
178 W25qxxWriteNoCheck(pBuffer, writeAddr, secRemain);
179 }
180 if(numByteToWrite==secRemain) {
181 break;
182 } else {
183 secPos++;
184 secOff = 0;
185 pBuffer += secRemain;
186 writeAddr += secRemain;
187 numByteToWrite -= secRemain;
188 if(numByteToWrite > BUFFER_SIZE) {
189 secRemain = BUFFER_SIZE;
190 } else {
191 secRemain = numByteToWrite;
192 }
193 }
194 }
195 }
196
W25qxxEraseChip(void)197 void W25qxxEraseChip(void)
198 {
199 W25qxxWriteEnable();
200 W25qxxWaitBusy();
201 W25X_CS = 0; /* 0, register status */
202 Spi1ReadWriteByte(W25X_CHIPERASE);
203 W25X_CS = 1; /* 1, register status */
204 W25qxxWaitBusy();
205 }
206
W25qxxEraseSector(u32 dstAddr)207 void W25qxxEraseSector(u32 dstAddr)
208 {
209 printf("fe:%x\r\n", dstAddr);
210 dstAddr *= BUFFER_SIZE;
211 W25qxxWriteEnable();
212 W25qxxWaitBusy();
213 W25X_CS = 0; /* 0, register status */
214 Spi1ReadWriteByte(W25X_SECTORERASE);
215 Spi1ReadWriteByte((u8)((dstAddr) >> 16));
216 Spi1ReadWriteByte((u8)((dstAddr) >> 8));
217 Spi1ReadWriteByte((u8)dstAddr);
218 W25X_CS = 1; /* 1, register status */
219 W25qxxWaitBusy();
220 }
221
W25qxxWaitBusy(void)222 void W25qxxWaitBusy(void)
223 {
224 while ((W25qxxReadSR() & 0x01) == 0x01);
225 }
226
W25qxxPowerDown(void)227 void W25qxxPowerDown(void)
228 {
229 W25X_CS = 0; /* 0, register status */
230 Spi1ReadWriteByte(W25X_POWERDOWN);
231 W25X_CS = 1; /* 1, register status */
232 PRT_TaskDelay(3); /* 3, number of delayed ticks */
233 }
234
W25qxxWakeup(void)235 void W25qxxWakeup(void)
236 {
237 W25X_CS = 0; /* 0, register status */
238 Spi1ReadWriteByte(W25X_RELEASEPOWERDOWN);
239 W25X_CS = 1; /* 1, register status */
240 PRT_TaskDelay(3); /* 3, number of delayed ticks */
241 }
242