test_spi.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361
  1. /*
  2. * Copyright (c) 2022-2024, Xiaohua Semiconductor Co., Ltd.
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. *
  6. * Change Logs:
  7. * Date Author Notes
  8. * 2024-12-30 CDT first version
  9. */
  10. /*
  11. * 程序清单:这是一个 SPI 设备使用例程
  12. * 例程导出了 spi_w25q_sample 命令到控制终端
  13. * 命令调用格式:spi_w25q_sample spix0
  14. * 命令解释:命令第二个参数是要使用的SPI设备名称,为空则使用默认的SPI设备
  15. * 程序功能:通过SPI设备读取 w25q 的 ID 数据
  16. */
  17. #include <rtthread.h>
  18. #include <rtdevice.h>
  19. #include "board_config.h"
  20. #include <string.h>
  21. #if defined(BSP_USING_SPI)
  22. #include "drv_spi.h"
  23. #define W25Q_FLAG_BUSY (0x01)
  24. #define W25Q_WR_ENABLE (0x06)
  25. #define W25Q_SECTOR_ERASE (0x20)
  26. #define W25Q_RD_STATUS_REG1 (0x05)
  27. #define W25Q_PAGE_PROGRAM (0x02)
  28. #define W25Q_STD_RD (0x03)
  29. #define W25Q_PAGE_SIZE (256UL)
  30. #define W25Q_SECTOR_SIZE (1024UL * 4UL)
  31. #define W25Q_PAGE_PER_SECTOR (W25Q_SECTOR_SIZE / W25Q_PAGE_SIZE)
  32. #define W25Q_MAX_ADDR (0x800000UL)
  33. #define W25Q_SPI_WR_RD_ADDR 0x4000
  34. #if defined (HC32F460) || defined (HC32F4A0) || defined (HC32F472) || defined (HC32F448) || defined (HC32F4A8)
  35. #define W25Q_SPI_DATA_BUF_LEN 0x2000
  36. #elif defined (HC32F334)
  37. #define W25Q_SPI_DATA_BUF_LEN 0x1000
  38. #endif
  39. #if defined(HC32F4A0) || defined(HC32F448) || defined(HC32F4A8)
  40. #define SPI_CS_PORT SPI1_CS_PORT
  41. #define SPI_CS_PIN SPI1_CS_PIN
  42. #define SPI_CS_PORT_PIN GET_PIN(C, 7)
  43. #define W25Q_SPI_BUS_NAME "spi1"
  44. #define W25Q_SPI_DEVICE_NAME "spi10"
  45. #elif defined(HC32F472)
  46. #define SPI_CS_PORT SPI1_CS_PORT
  47. #define SPI_CS_PIN SPI1_CS_PIN
  48. #define SPI_CS_PORT_PIN GET_PIN(B, 12)
  49. #define W25Q_SPI_BUS_NAME "spi1"
  50. #define W25Q_SPI_DEVICE_NAME "spi10"
  51. #elif defined(HC32F460)
  52. #define SPI_CS_PORT SPI3_CS_PORT
  53. #define SPI_CS_PIN SPI3_CS_PIN
  54. #define SPI_CS_PORT_PIN GET_PIN(C, 7)
  55. #define W25Q_SPI_BUS_NAME "spi3"
  56. #define W25Q_SPI_DEVICE_NAME "spi30"
  57. #elif defined(HC32F334)
  58. #define SPI_CS_PORT SPI1_CS_PORT
  59. #define SPI_CS_PIN SPI1_CS_PIN
  60. #define SPI_CS_PORT_PIN GET_PIN(C, 1)
  61. #define W25Q_SPI_BUS_NAME "spi1"
  62. #define W25Q_SPI_DEVICE_NAME "spi10"
  63. #endif
  64. struct rt_spi_device *spi_dev_w25q; /* SPI 设备句柄 */
  65. static uint8_t u8WrBuf[W25Q_SPI_DATA_BUF_LEN];
  66. static uint8_t u8RdBuf[W25Q_SPI_DATA_BUF_LEN];
  67. static int rt_hw_spi_flash_init(void)
  68. {
  69. if (RT_EOK != rt_hw_spi_device_attach(W25Q_SPI_BUS_NAME, W25Q_SPI_DEVICE_NAME, SPI_CS_PORT_PIN))
  70. {
  71. rt_kprintf("Failed to attach the spi device.");
  72. return -RT_ERROR;
  73. }
  74. return RT_EOK;
  75. }
  76. /* 导出到自动初始化 */
  77. INIT_COMPONENT_EXPORT(rt_hw_spi_flash_init);
  78. void w25q_read_uid(struct rt_spi_device *device)
  79. {
  80. rt_uint8_t w25x_read_uid = 0x4B; /* 命令 */
  81. rt_uint8_t u8UID[8] = {0};
  82. rt_uint8_t txBuf[5] = {0};
  83. memset(txBuf, 0xFF, 5);
  84. txBuf[0] = w25x_read_uid;
  85. /* 方式1:使用 rt_spi_send_then_recv()发送命令读取ID */
  86. if (RT_EOK != rt_spi_send_then_recv(device, txBuf, 5, u8UID, 8))
  87. {
  88. rt_kprintf("spi get uid failed!\n");
  89. }
  90. else
  91. {
  92. rt_kprintf("w25q UID is: %02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x\r\n",
  93. u8UID[0], u8UID[1], u8UID[2], u8UID[3], u8UID[4], u8UID[5], u8UID[6], u8UID[7]);
  94. }
  95. /* 方式2:使用 rt_spi_transfer_message()发送命令读取ID */
  96. struct rt_spi_message msg1, msg2;
  97. msg1.send_buf = txBuf;
  98. msg1.recv_buf = RT_NULL;
  99. msg1.length = 5;
  100. msg1.cs_take = 1;
  101. msg1.cs_release = 0;
  102. msg1.next = &msg2;
  103. msg2.send_buf = RT_NULL;
  104. msg2.recv_buf = u8UID;
  105. msg2.length = 8;
  106. msg2.cs_take = 0;
  107. msg2.cs_release = 1;
  108. msg2.next = RT_NULL;
  109. rt_spi_transfer_message(device, &msg1);
  110. rt_kprintf("use rt_spi_transfer_message() read w25q ID is: UID is: %02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x\r\n",
  111. u8UID[0], u8UID[1], u8UID[2], u8UID[3], u8UID[4], u8UID[5], u8UID[6], u8UID[7]);
  112. }
  113. int32_t w25q_check_process_done(struct rt_spi_device *device, uint32_t u32Timeout)
  114. {
  115. __IO uint32_t u32Count = 0U;
  116. int32_t i32Ret = LL_ERR_TIMEOUT;
  117. rt_uint8_t rxBuf[5] = {0};
  118. rt_uint8_t txBuf[5] = {0};
  119. txBuf[0] = W25Q_RD_STATUS_REG1;
  120. while (u32Count < u32Timeout)
  121. {
  122. if (RT_EOK != rt_spi_send_then_recv(device, txBuf, 1, rxBuf, 1))
  123. {
  124. rt_kprintf("spi get SR failed!\n");
  125. }
  126. else
  127. {
  128. if (W25Q_FLAG_BUSY != (rxBuf[0] & W25Q_FLAG_BUSY))
  129. {
  130. i32Ret = LL_OK;
  131. break;
  132. }
  133. }
  134. rt_thread_mdelay(1);
  135. u32Count++;
  136. }
  137. return i32Ret;
  138. }
  139. int32_t w25q_read_data(struct rt_spi_device *device, uint32_t u32Addr, uint8_t *pu8ReadBuf, uint32_t u32Size)
  140. {
  141. int32_t i32Ret = LL_OK;
  142. rt_uint8_t txBuf[5] = {0};
  143. txBuf[0] = W25Q_STD_RD;
  144. txBuf[1] = (u32Addr >> 16) & 0xFFU;
  145. txBuf[2] = (u32Addr >> 8) & 0xFFU;
  146. txBuf[3] = u32Addr & 0xFFU;
  147. if (RT_EOK != rt_spi_send_then_recv(device, txBuf, 4, pu8ReadBuf, u32Size))
  148. {
  149. i32Ret = LL_ERR;
  150. }
  151. return i32Ret;
  152. }
  153. int32_t w25q_write_data(struct rt_spi_device *device, uint32_t u32Addr, uint8_t *pu8WriteBuf, uint32_t u32Size)
  154. {
  155. int32_t i32Ret = LL_OK;
  156. uint32_t u32TempSize, u32AddrOffset = 0U;
  157. uint8_t w25q_txBuf[W25Q_PAGE_SIZE + 10];
  158. if ((u32Addr % W25Q_PAGE_SIZE) != 0U)
  159. {
  160. return LL_ERR_INVD_PARAM;
  161. }
  162. while (u32Size != 0UL)
  163. {
  164. if (u32Size >= W25Q_PAGE_SIZE)
  165. {
  166. u32TempSize = W25Q_PAGE_SIZE;
  167. }
  168. else
  169. {
  170. u32TempSize = u32Size;
  171. }
  172. w25q_txBuf[0] = W25Q_WR_ENABLE;
  173. if (1 != rt_spi_send(device, w25q_txBuf, 1))
  174. {
  175. rt_kprintf("spi send cmd failed!\n");
  176. }
  177. w25q_txBuf[0] = W25Q_PAGE_PROGRAM;
  178. w25q_txBuf[1] = (u32Addr >> 16) & 0xFFU;
  179. w25q_txBuf[2] = (u32Addr >> 8) & 0xFFU;
  180. w25q_txBuf[3] = u32Addr & 0xFFU;
  181. memcpy(&w25q_txBuf[4], &pu8WriteBuf[u32AddrOffset], u32TempSize);
  182. if ((u32TempSize + 4) != rt_spi_send(device, w25q_txBuf, u32TempSize + 4))
  183. {
  184. rt_kprintf("spi send addr failed!\n");
  185. }
  186. i32Ret = w25q_check_process_done(device, 500U);
  187. if (i32Ret != LL_OK)
  188. {
  189. break;
  190. }
  191. u32Addr += u32TempSize;
  192. u32AddrOffset += u32TempSize;
  193. u32Size -= u32TempSize;
  194. }
  195. return i32Ret;
  196. }
  197. int32_t w25q_erase_sector(struct rt_spi_device *device, uint32_t u32Addr, uint32_t u32Size)
  198. {
  199. uint8_t txBuf[10];
  200. uint32_t u32SectorNum, u32Cnt;
  201. int32_t i32Ret = LL_OK;
  202. if ((u32Addr % W25Q_SECTOR_SIZE) != 0U)
  203. {
  204. return LL_ERR_INVD_PARAM;
  205. }
  206. u32SectorNum = u32Size / W25Q_SECTOR_SIZE;
  207. if ((u32Size % W25Q_SECTOR_SIZE) != 0U)
  208. {
  209. u32SectorNum += 1;
  210. }
  211. for (u32Cnt = 0; u32Cnt < u32SectorNum; u32Cnt++)
  212. {
  213. txBuf[0] = W25Q_WR_ENABLE;
  214. if (1 != rt_spi_send(device, txBuf, 1))
  215. {
  216. rt_kprintf("spi send cmd failed!\n");
  217. }
  218. txBuf[0] = W25Q_SECTOR_ERASE;
  219. txBuf[1] = (u32Addr >> 16) & 0xFFU;
  220. txBuf[2] = (u32Addr >> 8) & 0xFFU;
  221. txBuf[3] = u32Addr & 0xFFU;
  222. if (4 != rt_spi_send(device, txBuf, 4))
  223. {
  224. rt_kprintf("spi send addr failed!\n");
  225. }
  226. if (LL_OK != w25q_check_process_done(device, 500U))
  227. {
  228. i32Ret = LL_ERR;
  229. break;
  230. }
  231. u32Addr += W25Q_SECTOR_SIZE;
  232. }
  233. return i32Ret;
  234. }
  235. void w25q_write_read_data(struct rt_spi_device *device, uint32_t u32Addr)
  236. {
  237. uint32_t u32Cnt;
  238. for (u32Cnt = 0; u32Cnt < W25Q_SPI_DATA_BUF_LEN; u32Cnt++)
  239. {
  240. u8WrBuf[u32Cnt] = u32Cnt & 0xFFUL;
  241. u8RdBuf[u32Cnt] = 0U;
  242. }
  243. if (LL_OK != w25q_erase_sector(device, u32Addr, W25Q_SPI_DATA_BUF_LEN))
  244. {
  245. rt_kprintf("spi erase sector failed!\n");
  246. }
  247. if (LL_OK != w25q_write_data(device, u32Addr, u8WrBuf, W25Q_SPI_DATA_BUF_LEN))
  248. {
  249. rt_kprintf("spi write data failed!\n");
  250. }
  251. if (LL_OK != w25q_read_data(device, u32Addr, u8RdBuf, W25Q_SPI_DATA_BUF_LEN))
  252. {
  253. rt_kprintf("spi read data failed!\n");
  254. }
  255. if (memcmp(u8WrBuf, u8RdBuf, W25Q_SPI_DATA_BUF_LEN) == 0)
  256. {
  257. rt_kprintf("spi write and read test ok! addr=%06x\n", u32Addr);
  258. }
  259. else
  260. {
  261. rt_kprintf("spi write and read failed!\n");
  262. }
  263. }
  264. static void spi_thread_entry(void *parameter)
  265. {
  266. uint32_t u32Addr = W25Q_SPI_WR_RD_ADDR;
  267. struct rt_spi_configuration cfg;
  268. cfg.data_width = 8;
  269. cfg.mode = RT_SPI_MASTER | RT_SPI_MODE_0 | RT_SPI_MSB;
  270. cfg.max_hz = 80 * 1000 * 1000; /* 80M */
  271. rt_spi_configure(spi_dev_w25q, &cfg);
  272. /* 读取UID */
  273. w25q_read_uid(spi_dev_w25q);
  274. while (1)
  275. {
  276. /* 读写对比数据 */
  277. w25q_write_read_data(spi_dev_w25q, u32Addr);
  278. u32Addr += W25Q_SPI_DATA_BUF_LEN;
  279. if (u32Addr >= (W25Q_MAX_ADDR - W25Q_SPI_DATA_BUF_LEN))
  280. {
  281. u32Addr = W25Q_SPI_WR_RD_ADDR;
  282. }
  283. rt_thread_mdelay(500);
  284. }
  285. }
  286. static void spi_w25q_sample(int argc, char *argv[])
  287. {
  288. char name[RT_NAME_MAX];
  289. if (argc == 2)
  290. {
  291. rt_strncpy(name, argv[1], RT_NAME_MAX);
  292. }
  293. else
  294. {
  295. rt_strncpy(name, W25Q_SPI_DEVICE_NAME, RT_NAME_MAX);
  296. }
  297. /* 查找 spi 设备获取设备句柄 */
  298. spi_dev_w25q = (struct rt_spi_device *)rt_device_find(name);
  299. if (!spi_dev_w25q)
  300. {
  301. rt_kprintf("spi sample run failed! can't find %s device!\n", name);
  302. }
  303. else
  304. {
  305. /* 创建 线程 */
  306. rt_thread_t thread = rt_thread_create("spi", spi_thread_entry, RT_NULL, 2048, 15, 10);
  307. /* 创建成功则启动线程 */
  308. if (thread != RT_NULL)
  309. {
  310. rt_thread_startup(thread);
  311. }
  312. }
  313. }
  314. /* 导出到 msh 命令列表中 */
  315. MSH_CMD_EXPORT(spi_w25q_sample, spi w25q sample);
  316. #endif