1 /******************************************************************************************************************************************
2 * 文件名称: SWM341_sfc.c
3 * 功能说明: SWM341单片机的SFC(Serial Flash Controller)模块驱动库
4 * 技术支持: http://www.synwit.com.cn/e/tool/gbook/?bid=1
5 * 注意事项:
6 * 版本日期: V1.1.0 2017年10月25日
7 * 升级记录:
8 *
9 *
10 *******************************************************************************************************************************************
11 * @attention
12 *
13 * THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS WITH CODING INFORMATION
14 * REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE TIME. AS A RESULT, SYNWIT SHALL NOT BE HELD LIABLE
15 * FOR ANY DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE CONTENT
16 * OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING INFORMATION CONTAINED HEREIN IN CONN-
17 * -ECTION WITH THEIR PRODUCTS.
18 *
19 * COPYRIGHT 2012 Synwit Technology
20 *******************************************************************************************************************************************/
21 #include "SWM341.h"
22 #include "SWM341_sfc.h"
23
24
25 /******************************************************************************************************************************************
26 * 函数名称: SFC_Init()
27 * 功能说明: SFC(Serial Flash Controller)初始化
28 * 输 入: SFC_InitStructure * initStruct SFC初始化配置值
29 * 输 出: 无
30 * 注意事项: 无
31 ******************************************************************************************************************************************/
SFC_Init(SFC_InitStructure * initStruct)32 void SFC_Init(SFC_InitStructure * initStruct)
33 {
34 SYS->CLKEN1 |= (1 << SYS_CLKEN1_SFC_Pos);
35
36 *((__IO uint32_t *)((uint32_t )&SFC->CFG + 0x3F4)) = 7;
37
38 SFC->CFG &= ~(SFC_CFG_CLKDIV_Msk | SFC_CFG_DATA4L_RD_Msk | SFC_CFG_DATA4L_PP_Msk);
39 SFC->CFG |= (initStruct->ClkDiv << SFC_CFG_CLKDIV_Pos) |
40 (initStruct->Width_Read << SFC_CFG_DATA4L_RD_Pos) |
41 (initStruct->Width_PageProgram << SFC_CFG_DATA4L_PP_Pos);
42
43 SFC->CFG |= (1 << SFC_CFG_CMDWREN_Pos);
44 SFC->CMDAHB &= ~(SFC_CMDAHB_READ_Msk | SFC_CMDAHB_PP_Msk);
45 SFC->CMDAHB |= (initStruct->Cmd_Read << SFC_CMDAHB_READ_Pos) |
46 (initStruct->Cmd_PageProgram << SFC_CMDAHB_PP_Pos);
47 SFC->CFG &= ~(1 << SFC_CFG_CMDWREN_Pos);
48
49 SFC->TIM &= ~(SFC_TIM_WIP_CHK_ITV_Msk | SFC_TIM_WIP_CHK_LMT_Msk);
50 SFC->TIM |= ((CyclesPerUs / 10) << SFC_TIM_WIP_CHK_ITV_Pos) | //2048 * (CyclesPerUs / 10) / CyclesPerUs us = 0.2 ms
51 (255 << SFC_TIM_WIP_CHK_LMT_Pos);
52
53 if((initStruct->Width_Read == SFC_RDWIDTH_4) || (initStruct->Width_PageProgram == SFC_PPWIDTH_4))
54 {
55 if(SFC_QuadState() == 0)
56 SFC_QuadSwitch(1);
57 }
58 }
59
60 /******************************************************************************************************************************************
61 * 函数名称: SFC_ReadJEDEC()
62 * 功能说明: 读取 JEDEC ID
63 * 输 入: 无
64 * 输 出: uint32_t JEDEC ID
65 * 注意事项: 无
66 ******************************************************************************************************************************************/
SFC_ReadJEDEC(void)67 uint32_t SFC_ReadJEDEC(void)
68 {
69 SFC->CFG &= ~SFC_CFG_CMDTYPE_Msk;
70 SFC->CFG |= (1 << SFC_CFG_CMDWREN_Pos) |
71 (2 << SFC_CFG_CMDTYPE_Pos);
72 SFC->CMD = SFC_CMD_READ_JEDEC;
73
74 SFC->GO = 1;
75 __DSB(); __ISB();
76 while(SFC->GO) __NOP();
77
78 return SFC->DATA;
79 }
80
81 /******************************************************************************************************************************************
82 * 函数名称: SFC_Erase()
83 * 功能说明: SPI Flash扇区擦除,每个扇区4K字节
84 * 输 入: uint32_t addr 要擦除扇区的地址,必须4K对齐,即addr%4096 == 0
85 * uint8_t wait 1 等待 Flash 完成擦除操作后再返回 0 发出擦除命令后立即返回
86 * 输 出: 无
87 * 注意事项: 无
88 ******************************************************************************************************************************************/
SFC_Erase(uint32_t addr,uint8_t wait)89 void SFC_Erase(uint32_t addr, uint8_t wait)
90 {
91 SFC_EraseEx(addr, SFC_CMD_ERASE_SECTOR, wait);
92 }
93
94 /******************************************************************************************************************************************
95 * 函数名称: SFC_EraseEx()
96 * 功能说明: SPI Flash擦除,通过提供不同的命令码支持片擦、块擦、扇区擦
97 * 输 入: uint32_t addr 要擦除的块的地址,当 addr == 0xFFFFFFFF 时,执行片擦
98 * uint8_t cmd 擦除命令码,有些SPI Flash支持多种大小的块的擦除,不同块大大小使用不同命令码
99 * uint8_t wait 1 等待 Flash 完成擦除操作后再返回 0 发出擦除命令后立即返回
100 * 输 出: 无
101 * 注意事项: 无
102 ******************************************************************************************************************************************/
SFC_EraseEx(uint32_t addr,uint8_t cmd,uint8_t wait)103 void SFC_EraseEx(uint32_t addr, uint8_t cmd, uint8_t wait)
104 {
105 uint8_t type = (addr == 0xFFFFFFFF) ? 5 : 7;
106
107 SFC->ADDR = addr;
108
109 SFC->CFG &= ~SFC_CFG_CMDTYPE_Msk;
110 SFC->CFG |= (1 << SFC_CFG_WREN_Pos) |
111 (1 << SFC_CFG_CMDWREN_Pos) |
112 (type << SFC_CFG_CMDTYPE_Pos);
113 SFC->CMD = cmd;
114
115 SFC->GO = 1;
116 __DSB(); __ISB();
117 while(SFC->GO) __NOP();
118
119 SFC->CFG &= ~SFC_CFG_WREN_Msk;
120
121 if(wait)
122 while(SFC_FlashBusy()) __NOP();
123 }
124
125 /******************************************************************************************************************************************
126 * 函数名称: SFC_Write()
127 * 功能说明: SPI Flash数据写入
128 * 输 入: uint32_t addr 数据要写入到Flash中的地址,字对齐
129 * uint32_t buff[] 要写入Flash中的数据
130 * uint32_t cnt 要写的数据的个数,以字为单位,最大64
131 * 输 出: 无
132 * 注意事项: 要写入的数据必须全部在同一页内,即addr/256 == (addr+(cnt-1)*4)/256
133 * 当 cnt > 4 时,LCD_DCLK 输出可能出现间断(|__| ̄|__| ̄|__| ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄|__| ̄|__| ̄|__|),这种情况下有些屏幕会显示异常,遇
134 * 到这种情况,可通过以 cnt = 4 多次调用 SFC_Write() 解决
135 ******************************************************************************************************************************************/
SFC_Write(uint32_t addr,uint32_t buff[],uint32_t cnt)136 void SFC_Write(uint32_t addr, uint32_t buff[], uint32_t cnt)
137 {
138 SFC->CFG |= (1 << SFC_CFG_WREN_Pos);
139 for(int i = 0; i < cnt; i++)
140 *((volatile unsigned int *)(0x70000000+addr+i*4)) = buff[i];
141
142 while(SFC->SR & SFC_SR_BUSY_Msk) __NOP();
143 SFC->CFG &= ~SFC_CFG_WREN_Msk;
144 }
145
146
147 #define IOSPI_CS_Low() GPIO_ClrBit(GPIOD, PIN6); __NOP(); __NOP(); __NOP(); __NOP()
148 #define IOSPI_CS_High() __NOP(); __NOP(); __NOP(); __NOP(); GPIO_SetBit(GPIOD, PIN6)
149 #define IOSPI_CLK_Low() GPIO_ClrBit(GPIOD, PIN5); __NOP(); __NOP()
150 #define IOSPI_CLK_High() __NOP(); __NOP(); GPIO_SetBit(GPIOD, PIN5)
151 #define IOSPI_MOSI_Low() GPIO_ClrBit(GPIOD, PIN8)
152 #define IOSPI_MOSI_High() GPIO_SetBit(GPIOD, PIN8)
153 #define IOSPI_MISO_Value() GPIO_GetBit(GPIOD, PIN7)
154
IOSPI_ReadWrite(uint8_t data)155 static uint8_t IOSPI_ReadWrite(uint8_t data)
156 {
157 uint8_t val = 0;
158
159 for(int i = 0; i < 8; i++)
160 {
161 IOSPI_CLK_Low();
162
163 if(data & (1 << (7 - i)))
164 IOSPI_MOSI_High();
165 else
166 IOSPI_MOSI_Low();
167
168 IOSPI_CLK_High();
169
170 val = (val << 1) | IOSPI_MISO_Value();
171 }
172
173 return val;
174 }
175
176 /******************************************************************************************************************************************
177 * 函数名称: SFC_GPIOWrite()
178 * 功能说明: SFC 写入较慢,大量写入时,建议用 GPIO 模拟 SPI 写入
179 * 输 入: uint32_t addr 数据要写入到Flash中的地址,字对齐
180 * uint32_t buff[] 要写入Flash中的数据
181 * uint32_t cnt 要写的数据的个数,以字为单位,最大64
182 * 输 出: 无
183 * 注意事项: 执行此函数前需要将相应引脚切到 GPIO 功能,使用完后再次将相应引脚切换回 SFC 功能,以便使用 SFC 擦除、读取功能
184 ******************************************************************************************************************************************/
SFC_GPIOWrite(uint32_t addr,uint32_t buff[],uint32_t cnt)185 void SFC_GPIOWrite(uint32_t addr, uint32_t buff[], uint32_t cnt)
186 {
187 IOSPI_CS_Low();
188 IOSPI_ReadWrite(SFC_CMD_WRITE_ENABLE);
189 IOSPI_CS_High();
190
191 IOSPI_CS_Low();
192 IOSPI_ReadWrite(SFC_CMD_PAGE_PROGRAM);
193 IOSPI_ReadWrite(addr >> 16);
194 IOSPI_ReadWrite(addr >> 8);
195 IOSPI_ReadWrite(addr);
196
197 for(int i = 0; i < cnt * 4; i++)
198 {
199 IOSPI_ReadWrite(((uint8_t *)buff)[i]);
200 }
201 IOSPI_CS_High();
202
203 int busy;
204 do {
205 IOSPI_CS_Low();
206 IOSPI_ReadWrite(SFC_CMD_READ_STATUS_REG1);
207 busy = IOSPI_ReadWrite(0xFF) & (1 << SFC_STATUS_REG_BUSY_Pos);
208 IOSPI_CS_High();
209 } while(busy);
210 }
211
212
213 /******************************************************************************************************************************************
214 * 函数名称: SFC_Read()
215 * 功能说明: SPI Flash数据读取
216 * 输 入: uint32_t addr 要读取的数据在Flash中的地址,字对齐
217 * uint32_t buff[] 读取到的数据存入buff指向的内存
218 * uint32_t cnt 要读取的数据的个数,以字为单位
219 * 输 出: 无
220 * 注意事项: 无
221 ******************************************************************************************************************************************/
SFC_Read(uint32_t addr,uint32_t buff[],uint32_t cnt)222 void SFC_Read(uint32_t addr, uint32_t buff[], uint32_t cnt)
223 {
224 for(int i = 0; i < cnt; i++)
225 buff[i] = *((volatile unsigned int *)(0x70000000+addr+i*4));
226 }
227
228
229 /******************************************************************************************************************************************
230 * 函数名称: SFC_ReadStatusReg()
231 * 功能说明: SPI Flash读取状态寄存器
232 * 输 入: uint8_t cmd 读取使用的命令码
233 * 输 出: uint8_t 读到的状态寄存器值
234 * 注意事项: 无
235 ******************************************************************************************************************************************/
SFC_ReadStatusReg(uint8_t cmd)236 uint8_t SFC_ReadStatusReg(uint8_t cmd)
237 {
238 SFC->CFG &= ~SFC_CFG_CMDTYPE_Msk;
239 SFC->CFG |= (1 << SFC_CFG_CMDWREN_Pos) |
240 (1 << SFC_CFG_CMDTYPE_Pos);
241 SFC->CMD = cmd;
242
243 SFC->GO = 1;
244 __DSB(); __ISB();
245 while(SFC->GO) __NOP();
246
247 return SFC->DATA;
248 }
249
250
251 /******************************************************************************************************************************************
252 * 函数名称: SFC_WriteStatusReg()
253 * 功能说明: SPI Flash写入状态寄存器
254 * 输 入: uint8_t cmd 写入使用的命令码
255 * uint16_t reg 要写入的状态寄存器值
256 * 输 出: 无
257 * 注意事项: 无
258 ******************************************************************************************************************************************/
SFC_WriteStatusReg(uint8_t cmd,uint16_t reg)259 void SFC_WriteStatusReg(uint8_t cmd, uint16_t reg)
260 {
261 SFC->CFG &= ~SFC_CFG_CMDTYPE_Msk;
262 SFC->CFG |= (1 << SFC_CFG_WREN_Pos) |
263 (1 << SFC_CFG_CMDWREN_Pos) |
264 (6 << SFC_CFG_CMDTYPE_Pos);
265 SFC->CMD = cmd;
266
267 SFC->DATA = reg;
268
269 SFC->GO = 1;
270 __DSB(); __ISB();
271 while(SFC->GO) __NOP();
272 }
273
274
275 /******************************************************************************************************************************************
276 * 函数名称: SFC_QuadSwitch()
277 * 功能说明: SPI Flash Quad模式开关
278 * 输 入: uint8_t on 1 开启 Quad 模式 0 关闭 Quad 模式
279 * 输 出: 无
280 * 注意事项: 无
281 ******************************************************************************************************************************************/
SFC_QuadSwitch(uint8_t on)282 void SFC_QuadSwitch(uint8_t on)
283 {
284 uint16_t reg = (SFC_ReadStatusReg(SFC_CMD_READ_STATUS_REG2) << 8) |
285 (SFC_ReadStatusReg(SFC_CMD_READ_STATUS_REG1) << 0);
286
287 if(on)
288 reg |= (1 << SFC_STATUS_REG_QUAD_Pos);
289 else
290 reg &=~(1 << SFC_STATUS_REG_QUAD_Pos);
291
292 SFC_WriteStatusReg(SFC_CMD_WRITE_STATUS_REG1, reg);
293 }
294
295
296 /******************************************************************************************************************************************
297 * 函数名称: SFC_QuadState()
298 * 功能说明: SPI Flash Quad模式开关状态查询
299 * 输 入: 无
300 * 输 出: 1 Quad 模式开启 0 Quad 模式关闭
301 * 注意事项: 无
302 ******************************************************************************************************************************************/
SFC_QuadState(void)303 uint8_t SFC_QuadState(void)
304 {
305 uint8_t reg = SFC_ReadStatusReg(SFC_CMD_READ_STATUS_REG2);
306
307 if(reg & (1 << (SFC_STATUS_REG_QUAD_Pos - 8)))
308 return 1;
309 else
310 return 0;
311 }
312
313 /******************************************************************************************************************************************
314 * 函数名称: SFC_FlashBusy()
315 * 功能说明: SPI Flash Page Program、Sector Erase、Block Erase、Chip Erase 忙查询
316 * 输 入: 无
317 * 输 出: 1 Flash 正在执行 Erase/Write 操作 0 Flash 已完成 Erase/Write 操作
318 * 注意事项: 无
319 ******************************************************************************************************************************************/
SFC_FlashBusy(void)320 uint8_t SFC_FlashBusy(void)
321 {
322 uint8_t reg = SFC_ReadStatusReg(SFC_CMD_READ_STATUS_REG1);
323
324 if(reg & (1 << SFC_STATUS_REG_BUSY_Pos))
325 return 1;
326 else
327 return 0;
328 }
329