hard_flash_at45db.c 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353
  1. #include "hard_flash_at45db.h"
  2. #include "board.h"
  3. #include "hpm_spi_drv.h"
  4. #include "hpm_clock_drv.h"
  5. #include "hpm_gpio_drv.h"
  6. // 后续具体的IO宏都放到board头文件里
  7. #ifndef GD25Q16_FLASH
  8. /* 使用 SPI2 作为示例,你可以根据需要修改 */
  9. #define AT45DB_SPI_BASE HPM_SPI2
  10. #define AT45DB_CS_GPIO_PTR HPM_GPIO0 /* GPIO 控制器基地址 */
  11. #define AT45DB_CS_PORT 1 /* GPIOB = 1 */
  12. #define AT45DB_CS_PIN 12 /* PIN12 */
  13. /******************SPI时钟频率*******************/
  14. #define AT45DB_CLK_FRE 21000000
  15. /* CS 控制宏 */
  16. #define AT45DB_CS_SELECT() gpio_write_pin(AT45DB_CS_GPIO_PTR, AT45DB_CS_PORT, AT45DB_CS_PIN, 0)
  17. #define AT45DB_CS_DESELECT() gpio_write_pin(AT45DB_CS_GPIO_PTR, AT45DB_CS_PORT, AT45DB_CS_PIN, 1)
  18. /* 静态变量 */
  19. static uint32_t spi_clk_freq;
  20. /**
  21. * @brief SPI 读写一个字节
  22. */
  23. static uint8_t spi_readwrite_byte(uint8_t byte)
  24. {
  25. uint8_t rx_byte = 0;
  26. spi_control_config_t control_config;
  27. /* 配置传输控制 */
  28. spi_master_get_default_control_config(&control_config);
  29. control_config.common_config.trans_mode = spi_trans_write_read_together;
  30. control_config.master_config.cmd_enable = false;
  31. control_config.master_config.addr_enable = false;
  32. /* 执行传输 */
  33. spi_transfer(AT45DB_SPI_BASE,
  34. &control_config,
  35. NULL, NULL,
  36. &byte, 1,
  37. &rx_byte, 1);
  38. return rx_byte;
  39. }
  40. /**
  41. * @brief 初始化 AT45DB 的 SPI 接口
  42. */
  43. void at45db_init(void)
  44. {
  45. spi_timing_config_t timing_config = {0};
  46. spi_format_config_t format_config = {0};
  47. /* 初始化 SPI 时钟和引脚 */
  48. spi_clk_freq = board_init_spi_clock(AT45DB_SPI_BASE);
  49. board_init_spi_pins(AT45DB_SPI_BASE);
  50. /* 配置 CS 引脚 */
  51. AT45DB_CS_DESELECT(); /* CS 默认高电平 */
  52. /* 3. 配置 SPI 时序(主模式)*/
  53. spi_master_get_default_timing_config(&timing_config);
  54. timing_config.master_config.clk_src_freq_in_hz = spi_clk_freq;
  55. timing_config.master_config.sclk_freq_in_hz = AT45DB_CLK_FRE;
  56. spi_master_timing_init(AT45DB_SPI_BASE, &timing_config);
  57. /* 4. 配置 SPI 格式 */
  58. spi_master_get_default_format_config(&format_config);
  59. format_config.common_config.data_len_in_bits = 8; /* 8位数据 */
  60. format_config.common_config.mode = spi_master_mode; /* 主机模式 */
  61. format_config.common_config.cpol = spi_sclk_low_idle; /* CPOL=0:空闲时低电平 */
  62. format_config.common_config.cpha = spi_sclk_sampling_odd_clk_edges; /* CPHA=0:第一个边沿采样 */
  63. spi_format_init(AT45DB_SPI_BASE, &format_config);
  64. }
  65. /**
  66. * @brief 查询 AT45DB 是否准备好
  67. * @return 1: 准备好, 0: 忙
  68. */
  69. uint8_t at45db_is_busy(void)
  70. {
  71. uint8_t status_reg;
  72. AT45DB_CS_SELECT();
  73. spi_readwrite_byte(AT45DB_READ_STATE_REGISTER);
  74. status_reg = spi_readwrite_byte(0x00);
  75. AT45DB_CS_DESELECT();
  76. return (status_reg & 0x80) ? 1 : 0;
  77. }
  78. /**
  79. * @brief 检查 AT45DB 是否存在
  80. * @return 1: 存在, 0: 不存在
  81. */
  82. uint8_t at45db_check(void)
  83. {
  84. uint8_t buf[3];
  85. AT45DB_CS_SELECT();
  86. spi_readwrite_byte(0x9F); /* 读ID命令 */
  87. buf[0] = spi_readwrite_byte(0);
  88. buf[1] = spi_readwrite_byte(0);
  89. buf[2] = spi_readwrite_byte(0);
  90. AT45DB_CS_DESELECT();
  91. /* AT45DB161 的 ID 是 0x1F, 0x26, 0x00 */
  92. if ((buf[0] == 0x1F) && (buf[1] == 0x26) && (buf[2] == 0x00)) {
  93. return 1;
  94. }
  95. return 0;
  96. }
  97. /**
  98. * @brief 读一页数据
  99. * @param page 页地址 (0-4096)
  100. * @param pdata 数据缓冲区
  101. */
  102. void at45db_read_page(uint16_t page, uint8_t *pdata)
  103. {
  104. int i;
  105. if (page > 4096) return;
  106. /* 等待芯片就绪 */
  107. while (at45db_is_busy() == 0);
  108. AT45DB_CS_SELECT();
  109. spi_readwrite_byte(AT45DB_MM_PAGE_READ);
  110. spi_readwrite_byte((int8_t)(page >> 6)); /* A20 - A9 */
  111. spi_readwrite_byte((int8_t)(page << 2));
  112. spi_readwrite_byte(0x00); /* 3字节地址 */
  113. /* 4个 dummy 字节 */
  114. spi_readwrite_byte(0x00);
  115. spi_readwrite_byte(0x00);
  116. spi_readwrite_byte(0x00);
  117. spi_readwrite_byte(0x00);
  118. /* 读取数据 */
  119. for (i = 0; i < 512; i++) {
  120. *pdata++ = spi_readwrite_byte(0x00);
  121. }
  122. AT45DB_CS_DESELECT();
  123. }
  124. /**
  125. * @brief 写一页数据
  126. * @param page 页地址 (0-4095)
  127. * @param data 要写入的数据
  128. */
  129. void at45db_write_page(uint16_t page, uint8_t *data)
  130. {
  131. uint16_t i;
  132. if (page > 4095) return;
  133. /* 等待芯片就绪 */
  134. while (at45db_is_busy() == 0);
  135. /* 步骤1:将数据写入 buffer2 */
  136. AT45DB_CS_SELECT();
  137. spi_readwrite_byte(AT45DB_BUFFER_2_WRITE);
  138. spi_readwrite_byte(0x00);
  139. spi_readwrite_byte(0x00);
  140. spi_readwrite_byte(0x00);
  141. for (i = 0; i < 512; i++) {
  142. spi_readwrite_byte(data[i]);
  143. }
  144. AT45DB_CS_DESELECT();
  145. /* 等待写入完成 */
  146. while (at45db_is_busy() == 0);
  147. /* 步骤2:将 buffer2 的内容编程到主存储器 */
  148. AT45DB_CS_SELECT();
  149. spi_readwrite_byte(AT45DB_B2_TO_MM_PAGE_PROG_WITH_ERASE);
  150. spi_readwrite_byte((uint8_t)(page >> 6));
  151. spi_readwrite_byte((uint8_t)(page << 2));
  152. spi_readwrite_byte(0x00);
  153. AT45DB_CS_DESELECT();
  154. }
  155. /**
  156. * @brief 在一页内写入部分数据
  157. * @param page 页地址
  158. * @param data 数据
  159. * @param len 长度
  160. */
  161. void at45db_write_bytes_on_one_page(uint16_t page, uint8_t *data, uint16_t len)
  162. {
  163. uint16_t i;
  164. if (page > 4095 || len > 512) return;
  165. /* 等待芯片就绪 */
  166. while (at45db_is_busy() == 0);
  167. /* 将数据写入 buffer2 */
  168. AT45DB_CS_SELECT();
  169. spi_readwrite_byte(AT45DB_BUFFER_2_WRITE);
  170. spi_readwrite_byte(0x00);
  171. spi_readwrite_byte(0x00);
  172. spi_readwrite_byte(0x00);
  173. for (i = 0; i < len; i++) {
  174. spi_readwrite_byte(data[i]);
  175. }
  176. AT45DB_CS_DESELECT();
  177. /* 等待写入完成 */
  178. while (at45db_is_busy() == 0);
  179. /* 编程到主存储器 */
  180. AT45DB_CS_SELECT();
  181. spi_readwrite_byte(AT45DB_B2_TO_MM_PAGE_PROG_WITH_ERASE);
  182. spi_readwrite_byte((uint8_t)(page >> 6));
  183. spi_readwrite_byte((uint8_t)(page << 2));
  184. spi_readwrite_byte(0x00);
  185. AT45DB_CS_DESELECT();
  186. }
  187. /**
  188. * @brief 从任意地址读取多个字节
  189. * @param addr 起始地址 (0-4096*512)
  190. * @param pdata 数据缓冲区
  191. * @param len 要读取的字节数
  192. */
  193. void at45db_read_bytes(uint32_t addr, uint8_t *pdata, uint16_t len)
  194. {
  195. int i, j, k;
  196. uint8_t temp[512];
  197. uint16_t page, offset;
  198. if (addr > 4096 * 512) return;
  199. page = addr / 512;
  200. offset = addr % 512;
  201. at45db_read_page(page++, temp);
  202. for (i = offset; (len != 0) && (i < 512); len--, i++) {
  203. *pdata++ = temp[i];
  204. }
  205. if ((i == 512) && (len != 0)) {
  206. if (len > 512) {
  207. for (k = 0; k < len / 512; k++) {
  208. at45db_read_page(page++, temp);
  209. for (j = 0; j < 512; j++) {
  210. *pdata++ = temp[j];
  211. }
  212. }
  213. len -= 512 * k;
  214. }
  215. if (len != 0) {
  216. at45db_read_page(page, temp);
  217. for (j = 0; j < len; j++) {
  218. *pdata++ = temp[j];
  219. }
  220. }
  221. }
  222. }
  223. /**
  224. * @brief 从任意地址写入多个字节
  225. * @param addr 起始地址 (0-4096*512)
  226. * @param pdata 要写入的数据
  227. * @param len 要写入的字节数
  228. */
  229. void at45db_write_bytes(uint32_t addr, uint8_t *pdata, uint16_t len)
  230. {
  231. uint8_t temp[512];
  232. uint16_t page, offset;
  233. uint16_t i, j, k;
  234. if (addr > 4096 * 512) return;
  235. page = addr / 512;
  236. offset = addr % 512;
  237. at45db_read_page(page, temp);
  238. for (i = offset; (len != 0) && (i < 512); len--, i++) {
  239. temp[i] = *pdata++;
  240. }
  241. at45db_write_page(page++, temp);
  242. if ((i == 512) && (len != 0)) {
  243. if (len > 512) {
  244. for (k = 0; k < len / 512; k++) {
  245. for (j = 0; j < 512; j++) {
  246. temp[j] = *pdata++;
  247. }
  248. at45db_write_page(page++, temp);
  249. }
  250. len -= 512 * k;
  251. }
  252. if (len != 0) {
  253. at45db_read_page(page, temp);
  254. for (j = 0; j < len; j++) {
  255. temp[j] = *pdata++;
  256. }
  257. at45db_write_page(page, temp);
  258. }
  259. }
  260. }
  261. /**
  262. * @brief 写入浮点数
  263. */
  264. void at45db_write_float(uint32_t addr, float value)
  265. {
  266. f_bytes data;
  267. data.value = value;
  268. at45db_write_bytes(addr, &data.byte[0], 4);
  269. }
  270. /**
  271. * @brief 读取浮点数
  272. */
  273. float at45db_read_float(uint32_t addr)
  274. {
  275. f_bytes data;
  276. data.value = 0;
  277. at45db_read_bytes(addr, &data.byte[0], 4);
  278. return data.value;
  279. }
  280. /**
  281. * @brief 写入16位整数
  282. */
  283. void at45db_write_int16(uint32_t addr, int16_t value)
  284. {
  285. i_bytes data;
  286. data.value = value;
  287. at45db_write_bytes(addr, &data.byte[0], 2);
  288. }
  289. /**
  290. * @brief 读取16位整数
  291. */
  292. int16_t at45db_read_int16(uint32_t addr)
  293. {
  294. i_bytes data;
  295. data.value = 0;
  296. at45db_read_bytes(addr, &data.byte[0], 2);
  297. return data.value;
  298. }
  299. #endif