SWM341_sfc.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328
  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. * 函数名称: SFC_Init()
  25. * 功能说明: SFC(Serial Flash Controller)初始化
  26. * 输 入: SFC_InitStructure * initStruct SFC初始化配置值
  27. * 输 出: 无
  28. * 注意事项: 无
  29. ******************************************************************************************************************************************/
  30. void SFC_Init(SFC_InitStructure * initStruct)
  31. {
  32. SYS->CLKEN1 |= (1 << SYS_CLKEN1_SFC_Pos);
  33. *((__IO uint32_t *)((uint32_t )&SFC->CFG + 0x3F4)) = 7;
  34. SFC->CFG &= ~(SFC_CFG_CLKDIV_Msk | SFC_CFG_DATA4L_RD_Msk | SFC_CFG_DATA4L_PP_Msk);
  35. SFC->CFG |= (initStruct->ClkDiv << SFC_CFG_CLKDIV_Pos) |
  36. (initStruct->Width_Read << SFC_CFG_DATA4L_RD_Pos) |
  37. (initStruct->Width_PageProgram << SFC_CFG_DATA4L_PP_Pos);
  38. SFC->CFG |= (1 << SFC_CFG_CMDWREN_Pos);
  39. SFC->CMDAHB &= ~(SFC_CMDAHB_READ_Msk | SFC_CMDAHB_PP_Msk);
  40. SFC->CMDAHB |= (initStruct->Cmd_Read << SFC_CMDAHB_READ_Pos) |
  41. (initStruct->Cmd_PageProgram << SFC_CMDAHB_PP_Pos);
  42. SFC->CFG &= ~(1 << SFC_CFG_CMDWREN_Pos);
  43. SFC->TIM &= ~(SFC_TIM_WIP_CHK_ITV_Msk | SFC_TIM_WIP_CHK_LMT_Msk);
  44. SFC->TIM |= ((CyclesPerUs / 10) << SFC_TIM_WIP_CHK_ITV_Pos) | //2048 * (CyclesPerUs / 10) / CyclesPerUs us = 0.2 ms
  45. (255 << SFC_TIM_WIP_CHK_LMT_Pos);
  46. if((initStruct->Width_Read == SFC_RDWIDTH_4) || (initStruct->Width_PageProgram == SFC_PPWIDTH_4))
  47. {
  48. if(SFC_QuadState() == 0)
  49. SFC_QuadSwitch(1);
  50. }
  51. }
  52. /******************************************************************************************************************************************
  53. * 函数名称: SFC_ReadJEDEC()
  54. * 功能说明: 读取 JEDEC ID
  55. * 输 入: 无
  56. * 输 出: uint32_t JEDEC ID
  57. * 注意事项: 无
  58. ******************************************************************************************************************************************/
  59. uint32_t SFC_ReadJEDEC(void)
  60. {
  61. SFC->CFG &= ~SFC_CFG_CMDTYPE_Msk;
  62. SFC->CFG |= (1 << SFC_CFG_CMDWREN_Pos) |
  63. (2 << SFC_CFG_CMDTYPE_Pos);
  64. SFC->CMD = SFC_CMD_READ_JEDEC;
  65. SFC->GO = 1;
  66. __DSB(); __ISB();
  67. while(SFC->GO) __NOP();
  68. return SFC->DATA;
  69. }
  70. /******************************************************************************************************************************************
  71. * 函数名称: SFC_Erase()
  72. * 功能说明: SPI Flash扇区擦除,每个扇区4K字节
  73. * 输 入: uint32_t addr 要擦除扇区的地址,必须4K对齐,即addr%4096 == 0
  74. * uint8_t wait 1 等待 Flash 完成擦除操作后再返回 0 发出擦除命令后立即返回
  75. * 输 出: 无
  76. * 注意事项: 无
  77. ******************************************************************************************************************************************/
  78. void SFC_Erase(uint32_t addr, uint8_t wait)
  79. {
  80. SFC_EraseEx(addr, SFC_CMD_ERASE_SECTOR, wait);
  81. }
  82. /******************************************************************************************************************************************
  83. * 函数名称: SFC_EraseEx()
  84. * 功能说明: SPI Flash擦除,通过提供不同的命令码支持片擦、块擦、扇区擦
  85. * 输 入: uint32_t addr 要擦除的块的地址,当 addr == 0xFFFFFFFF 时,执行片擦
  86. * uint8_t cmd 擦除命令码,有些SPI Flash支持多种大小的块的擦除,不同块大大小使用不同命令码
  87. * uint8_t wait 1 等待 Flash 完成擦除操作后再返回 0 发出擦除命令后立即返回
  88. * 输 出: 无
  89. * 注意事项: 无
  90. ******************************************************************************************************************************************/
  91. void SFC_EraseEx(uint32_t addr, uint8_t cmd, uint8_t wait)
  92. {
  93. uint8_t type = (addr == 0xFFFFFFFF) ? 5 : 7;
  94. SFC->ADDR = addr;
  95. SFC->CFG &= ~SFC_CFG_CMDTYPE_Msk;
  96. SFC->CFG |= (1 << SFC_CFG_WREN_Pos) |
  97. (1 << SFC_CFG_CMDWREN_Pos) |
  98. (type << SFC_CFG_CMDTYPE_Pos);
  99. SFC->CMD = cmd;
  100. SFC->GO = 1;
  101. __DSB(); __ISB();
  102. while(SFC->GO) __NOP();
  103. SFC->CFG &= ~SFC_CFG_WREN_Msk;
  104. if(wait)
  105. while(SFC_FlashBusy()) __NOP();
  106. }
  107. /******************************************************************************************************************************************
  108. * 函数名称: SFC_Write()
  109. * 功能说明: SPI Flash数据写入
  110. * 输 入: uint32_t addr 数据要写入到Flash中的地址,字对齐
  111. * uint32_t buff[] 要写入Flash中的数据
  112. * uint32_t cnt 要写的数据的个数,以字为单位,最大64
  113. * 输 出: 无
  114. * 注意事项: 要写入的数据必须全部在同一页内,即addr/256 == (addr+(cnt-1)*4)/256
  115. * 当 cnt > 4 时,LCD_DCLK 输出可能出现间断(|__| ̄|__| ̄|__| ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄|__| ̄|__| ̄|__|),这种情况下有些屏幕会显示异常,遇
  116. * 到这种情况,可通过以 cnt = 4 多次调用 SFC_Write() 解决
  117. ******************************************************************************************************************************************/
  118. void SFC_Write(uint32_t addr, uint32_t buff[], uint32_t cnt)
  119. {
  120. SFC->CFG |= (1 << SFC_CFG_WREN_Pos);
  121. for(int i = 0; i < cnt; i++)
  122. *((volatile unsigned int *)(0x70000000+addr+i*4)) = buff[i];
  123. while(SFC->SR & SFC_SR_BUSY_Msk) __NOP();
  124. SFC->CFG &= ~SFC_CFG_WREN_Msk;
  125. }
  126. #define IOSPI_CS_Low() GPIO_ClrBit(GPIOD, PIN6); __NOP(); __NOP(); __NOP(); __NOP()
  127. #define IOSPI_CS_High() __NOP(); __NOP(); __NOP(); __NOP(); GPIO_SetBit(GPIOD, PIN6)
  128. #define IOSPI_CLK_Low() GPIO_ClrBit(GPIOD, PIN5); __NOP(); __NOP()
  129. #define IOSPI_CLK_High() __NOP(); __NOP(); GPIO_SetBit(GPIOD, PIN5)
  130. #define IOSPI_MOSI_Low() GPIO_ClrBit(GPIOD, PIN8)
  131. #define IOSPI_MOSI_High() GPIO_SetBit(GPIOD, PIN8)
  132. #define IOSPI_MISO_Value() GPIO_GetBit(GPIOD, PIN7)
  133. static uint8_t IOSPI_ReadWrite(uint8_t data)
  134. {
  135. uint8_t val = 0;
  136. for(int i = 0; i < 8; i++)
  137. {
  138. IOSPI_CLK_Low();
  139. if(data & (1 << (7 - i)))
  140. IOSPI_MOSI_High();
  141. else
  142. IOSPI_MOSI_Low();
  143. IOSPI_CLK_High();
  144. val = (val << 1) | IOSPI_MISO_Value();
  145. }
  146. return val;
  147. }
  148. /******************************************************************************************************************************************
  149. * 函数名称: SFC_GPIOWrite()
  150. * 功能说明: SFC 写入较慢,大量写入时,建议用 GPIO 模拟 SPI 写入
  151. * 输 入: uint32_t addr 数据要写入到Flash中的地址,字对齐
  152. * uint32_t buff[] 要写入Flash中的数据
  153. * uint32_t cnt 要写的数据的个数,以字为单位,最大64
  154. * 输 出: 无
  155. * 注意事项: 执行此函数前需要将相应引脚切到 GPIO 功能,使用完后再次将相应引脚切换回 SFC 功能,以便使用 SFC 擦除、读取功能
  156. ******************************************************************************************************************************************/
  157. void SFC_GPIOWrite(uint32_t addr, uint32_t buff[], uint32_t cnt)
  158. {
  159. IOSPI_CS_Low();
  160. IOSPI_ReadWrite(SFC_CMD_WRITE_ENABLE);
  161. IOSPI_CS_High();
  162. IOSPI_CS_Low();
  163. IOSPI_ReadWrite(SFC_CMD_PAGE_PROGRAM);
  164. IOSPI_ReadWrite(addr >> 16);
  165. IOSPI_ReadWrite(addr >> 8);
  166. IOSPI_ReadWrite(addr);
  167. for(int i = 0; i < cnt * 4; i++)
  168. {
  169. IOSPI_ReadWrite(((uint8_t *)buff)[i]);
  170. }
  171. IOSPI_CS_High();
  172. int busy;
  173. do {
  174. IOSPI_CS_Low();
  175. IOSPI_ReadWrite(SFC_CMD_READ_STATUS_REG1);
  176. busy = IOSPI_ReadWrite(0xFF) & (1 << SFC_STATUS_REG_BUSY_Pos);
  177. IOSPI_CS_High();
  178. } while(busy);
  179. }
  180. /******************************************************************************************************************************************
  181. * 函数名称: SFC_Read()
  182. * 功能说明: SPI Flash数据读取
  183. * 输 入: uint32_t addr 要读取的数据在Flash中的地址,字对齐
  184. * uint32_t buff[] 读取到的数据存入buff指向的内存
  185. * uint32_t cnt 要读取的数据的个数,以字为单位
  186. * 输 出: 无
  187. * 注意事项: 无
  188. ******************************************************************************************************************************************/
  189. void SFC_Read(uint32_t addr, uint32_t buff[], uint32_t cnt)
  190. {
  191. for(int i = 0; i < cnt; i++)
  192. buff[i] = *((volatile unsigned int *)(0x70000000+addr+i*4));
  193. }
  194. /******************************************************************************************************************************************
  195. * 函数名称: SFC_ReadStatusReg()
  196. * 功能说明: SPI Flash读取状态寄存器
  197. * 输 入: uint8_t cmd 读取使用的命令码
  198. * 输 出: uint8_t 读到的状态寄存器值
  199. * 注意事项: 无
  200. ******************************************************************************************************************************************/
  201. uint8_t SFC_ReadStatusReg(uint8_t cmd)
  202. {
  203. SFC->CFG &= ~SFC_CFG_CMDTYPE_Msk;
  204. SFC->CFG |= (1 << SFC_CFG_CMDWREN_Pos) |
  205. (1 << SFC_CFG_CMDTYPE_Pos);
  206. SFC->CMD = cmd;
  207. SFC->GO = 1;
  208. __DSB(); __ISB();
  209. while(SFC->GO) __NOP();
  210. return SFC->DATA;
  211. }
  212. /******************************************************************************************************************************************
  213. * 函数名称: SFC_WriteStatusReg()
  214. * 功能说明: SPI Flash写入状态寄存器
  215. * 输 入: uint8_t cmd 写入使用的命令码
  216. * uint16_t reg 要写入的状态寄存器值
  217. * 输 出: 无
  218. * 注意事项: 无
  219. ******************************************************************************************************************************************/
  220. void SFC_WriteStatusReg(uint8_t cmd, uint16_t reg)
  221. {
  222. SFC->CFG &= ~SFC_CFG_CMDTYPE_Msk;
  223. SFC->CFG |= (1 << SFC_CFG_WREN_Pos) |
  224. (1 << SFC_CFG_CMDWREN_Pos) |
  225. (6 << SFC_CFG_CMDTYPE_Pos);
  226. SFC->CMD = cmd;
  227. SFC->DATA = reg;
  228. SFC->GO = 1;
  229. __DSB(); __ISB();
  230. while(SFC->GO) __NOP();
  231. }
  232. /******************************************************************************************************************************************
  233. * 函数名称: SFC_QuadSwitch()
  234. * 功能说明: SPI Flash Quad模式开关
  235. * 输 入: uint8_t on 1 开启 Quad 模式 0 关闭 Quad 模式
  236. * 输 出: 无
  237. * 注意事项: 无
  238. ******************************************************************************************************************************************/
  239. void SFC_QuadSwitch(uint8_t on)
  240. {
  241. uint16_t reg = (SFC_ReadStatusReg(SFC_CMD_READ_STATUS_REG2) << 8) |
  242. (SFC_ReadStatusReg(SFC_CMD_READ_STATUS_REG1) << 0);
  243. if(on)
  244. reg |= (1 << SFC_STATUS_REG_QUAD_Pos);
  245. else
  246. reg &=~(1 << SFC_STATUS_REG_QUAD_Pos);
  247. SFC_WriteStatusReg(SFC_CMD_WRITE_STATUS_REG1, reg);
  248. }
  249. /******************************************************************************************************************************************
  250. * 函数名称: SFC_QuadState()
  251. * 功能说明: SPI Flash Quad模式开关状态查询
  252. * 输 入: 无
  253. * 输 出: 1 Quad 模式开启 0 Quad 模式关闭
  254. * 注意事项: 无
  255. ******************************************************************************************************************************************/
  256. uint8_t SFC_QuadState(void)
  257. {
  258. uint8_t reg = SFC_ReadStatusReg(SFC_CMD_READ_STATUS_REG2);
  259. if(reg & (1 << (SFC_STATUS_REG_QUAD_Pos - 8)))
  260. return 1;
  261. else
  262. return 0;
  263. }
  264. /******************************************************************************************************************************************
  265. * 函数名称: SFC_FlashBusy()
  266. * 功能说明: SPI Flash Page Program、Sector Erase、Block Erase、Chip Erase 忙查询
  267. * 输 入: 无
  268. * 输 出: 1 Flash 正在执行 Erase/Write 操作 0 Flash 已完成 Erase/Write 操作
  269. * 注意事项: 无
  270. ******************************************************************************************************************************************/
  271. uint8_t SFC_FlashBusy(void)
  272. {
  273. uint8_t reg = SFC_ReadStatusReg(SFC_CMD_READ_STATUS_REG1);
  274. if(reg & (1 << SFC_STATUS_REG_BUSY_Pos))
  275. return 1;
  276. else
  277. return 0;
  278. }