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