#include "hard_flash_at45db.h" #include "board.h" #include "hpm_spi_drv.h" #include "hpm_clock_drv.h" #include "hpm_gpio_drv.h" // 后续具体的IO宏都放到board头文件里 #ifndef GD25Q16_FLASH /* 使用 SPI2 作为示例,你可以根据需要修改 */ #define AT45DB_SPI_BASE HPM_SPI2 #define AT45DB_CS_GPIO_PTR HPM_GPIO0 /* GPIO 控制器基地址 */ #define AT45DB_CS_PORT 1 /* GPIOB = 1 */ #define AT45DB_CS_PIN 12 /* PIN12 */ /******************SPI时钟频率*******************/ #define AT45DB_CLK_FRE 21000000 /* CS 控制宏 */ #define AT45DB_CS_SELECT() gpio_write_pin(AT45DB_CS_GPIO_PTR, AT45DB_CS_PORT, AT45DB_CS_PIN, 0) #define AT45DB_CS_DESELECT() gpio_write_pin(AT45DB_CS_GPIO_PTR, AT45DB_CS_PORT, AT45DB_CS_PIN, 1) /* 静态变量 */ static uint32_t spi_clk_freq; /** * @brief SPI 读写一个字节 */ static uint8_t spi_readwrite_byte(uint8_t byte) { uint8_t rx_byte = 0; spi_control_config_t control_config; /* 配置传输控制 */ spi_master_get_default_control_config(&control_config); control_config.common_config.trans_mode = spi_trans_write_read_together; control_config.master_config.cmd_enable = false; control_config.master_config.addr_enable = false; /* 执行传输 */ spi_transfer(AT45DB_SPI_BASE, &control_config, NULL, NULL, &byte, 1, &rx_byte, 1); return rx_byte; } /** * @brief 初始化 AT45DB 的 SPI 接口 */ void at45db_init(void) { spi_timing_config_t timing_config = {0}; spi_format_config_t format_config = {0}; /* 初始化 SPI 时钟和引脚 */ spi_clk_freq = board_init_spi_clock(AT45DB_SPI_BASE); board_init_spi_pins(AT45DB_SPI_BASE); /* 配置 CS 引脚 */ AT45DB_CS_DESELECT(); /* CS 默认高电平 */ /* 3. 配置 SPI 时序(主模式)*/ spi_master_get_default_timing_config(&timing_config); timing_config.master_config.clk_src_freq_in_hz = spi_clk_freq; timing_config.master_config.sclk_freq_in_hz = AT45DB_CLK_FRE; spi_master_timing_init(AT45DB_SPI_BASE, &timing_config); /* 4. 配置 SPI 格式 */ spi_master_get_default_format_config(&format_config); format_config.common_config.data_len_in_bits = 8; /* 8位数据 */ format_config.common_config.mode = spi_master_mode; /* 主机模式 */ format_config.common_config.cpol = spi_sclk_low_idle; /* CPOL=0:空闲时低电平 */ format_config.common_config.cpha = spi_sclk_sampling_odd_clk_edges; /* CPHA=0:第一个边沿采样 */ spi_format_init(AT45DB_SPI_BASE, &format_config); } /** * @brief 查询 AT45DB 是否准备好 * @return 1: 准备好, 0: 忙 */ uint8_t at45db_is_busy(void) { uint8_t status_reg; AT45DB_CS_SELECT(); spi_readwrite_byte(AT45DB_READ_STATE_REGISTER); status_reg = spi_readwrite_byte(0x00); AT45DB_CS_DESELECT(); return (status_reg & 0x80) ? 1 : 0; } /** * @brief 检查 AT45DB 是否存在 * @return 1: 存在, 0: 不存在 */ uint8_t at45db_check(void) { uint8_t buf[3]; AT45DB_CS_SELECT(); spi_readwrite_byte(0x9F); /* 读ID命令 */ buf[0] = spi_readwrite_byte(0); buf[1] = spi_readwrite_byte(0); buf[2] = spi_readwrite_byte(0); AT45DB_CS_DESELECT(); /* AT45DB161 的 ID 是 0x1F, 0x26, 0x00 */ if ((buf[0] == 0x1F) && (buf[1] == 0x26) && (buf[2] == 0x00)) { return 1; } return 0; } /** * @brief 读一页数据 * @param page 页地址 (0-4096) * @param pdata 数据缓冲区 */ void at45db_read_page(uint16_t page, uint8_t *pdata) { int i; if (page > 4096) return; /* 等待芯片就绪 */ while (at45db_is_busy() == 0); AT45DB_CS_SELECT(); spi_readwrite_byte(AT45DB_MM_PAGE_READ); spi_readwrite_byte((int8_t)(page >> 6)); /* A20 - A9 */ spi_readwrite_byte((int8_t)(page << 2)); spi_readwrite_byte(0x00); /* 3字节地址 */ /* 4个 dummy 字节 */ spi_readwrite_byte(0x00); spi_readwrite_byte(0x00); spi_readwrite_byte(0x00); spi_readwrite_byte(0x00); /* 读取数据 */ for (i = 0; i < 512; i++) { *pdata++ = spi_readwrite_byte(0x00); } AT45DB_CS_DESELECT(); } /** * @brief 写一页数据 * @param page 页地址 (0-4095) * @param data 要写入的数据 */ void at45db_write_page(uint16_t page, uint8_t *data) { uint16_t i; if (page > 4095) return; /* 等待芯片就绪 */ while (at45db_is_busy() == 0); /* 步骤1:将数据写入 buffer2 */ AT45DB_CS_SELECT(); spi_readwrite_byte(AT45DB_BUFFER_2_WRITE); spi_readwrite_byte(0x00); spi_readwrite_byte(0x00); spi_readwrite_byte(0x00); for (i = 0; i < 512; i++) { spi_readwrite_byte(data[i]); } AT45DB_CS_DESELECT(); /* 等待写入完成 */ while (at45db_is_busy() == 0); /* 步骤2:将 buffer2 的内容编程到主存储器 */ AT45DB_CS_SELECT(); spi_readwrite_byte(AT45DB_B2_TO_MM_PAGE_PROG_WITH_ERASE); spi_readwrite_byte((uint8_t)(page >> 6)); spi_readwrite_byte((uint8_t)(page << 2)); spi_readwrite_byte(0x00); AT45DB_CS_DESELECT(); } /** * @brief 在一页内写入部分数据 * @param page 页地址 * @param data 数据 * @param len 长度 */ void at45db_write_bytes_on_one_page(uint16_t page, uint8_t *data, uint16_t len) { uint16_t i; if (page > 4095 || len > 512) return; /* 等待芯片就绪 */ while (at45db_is_busy() == 0); /* 将数据写入 buffer2 */ AT45DB_CS_SELECT(); spi_readwrite_byte(AT45DB_BUFFER_2_WRITE); spi_readwrite_byte(0x00); spi_readwrite_byte(0x00); spi_readwrite_byte(0x00); for (i = 0; i < len; i++) { spi_readwrite_byte(data[i]); } AT45DB_CS_DESELECT(); /* 等待写入完成 */ while (at45db_is_busy() == 0); /* 编程到主存储器 */ AT45DB_CS_SELECT(); spi_readwrite_byte(AT45DB_B2_TO_MM_PAGE_PROG_WITH_ERASE); spi_readwrite_byte((uint8_t)(page >> 6)); spi_readwrite_byte((uint8_t)(page << 2)); spi_readwrite_byte(0x00); AT45DB_CS_DESELECT(); } /** * @brief 从任意地址读取多个字节 * @param addr 起始地址 (0-4096*512) * @param pdata 数据缓冲区 * @param len 要读取的字节数 */ void at45db_read_bytes(uint32_t addr, uint8_t *pdata, uint16_t len) { int i, j, k; uint8_t temp[512]; uint16_t page, offset; if (addr > 4096 * 512) return; page = addr / 512; offset = addr % 512; at45db_read_page(page++, temp); for (i = offset; (len != 0) && (i < 512); len--, i++) { *pdata++ = temp[i]; } if ((i == 512) && (len != 0)) { if (len > 512) { for (k = 0; k < len / 512; k++) { at45db_read_page(page++, temp); for (j = 0; j < 512; j++) { *pdata++ = temp[j]; } } len -= 512 * k; } if (len != 0) { at45db_read_page(page, temp); for (j = 0; j < len; j++) { *pdata++ = temp[j]; } } } } /** * @brief 从任意地址写入多个字节 * @param addr 起始地址 (0-4096*512) * @param pdata 要写入的数据 * @param len 要写入的字节数 */ void at45db_write_bytes(uint32_t addr, uint8_t *pdata, uint16_t len) { uint8_t temp[512]; uint16_t page, offset; uint16_t i, j, k; if (addr > 4096 * 512) return; page = addr / 512; offset = addr % 512; at45db_read_page(page, temp); for (i = offset; (len != 0) && (i < 512); len--, i++) { temp[i] = *pdata++; } at45db_write_page(page++, temp); if ((i == 512) && (len != 0)) { if (len > 512) { for (k = 0; k < len / 512; k++) { for (j = 0; j < 512; j++) { temp[j] = *pdata++; } at45db_write_page(page++, temp); } len -= 512 * k; } if (len != 0) { at45db_read_page(page, temp); for (j = 0; j < len; j++) { temp[j] = *pdata++; } at45db_write_page(page, temp); } } } /** * @brief 写入浮点数 */ void at45db_write_float(uint32_t addr, float value) { f_bytes data; data.value = value; at45db_write_bytes(addr, &data.byte[0], 4); } /** * @brief 读取浮点数 */ float at45db_read_float(uint32_t addr) { f_bytes data; data.value = 0; at45db_read_bytes(addr, &data.byte[0], 4); return data.value; } /** * @brief 写入16位整数 */ void at45db_write_int16(uint32_t addr, int16_t value) { i_bytes data; data.value = value; at45db_write_bytes(addr, &data.byte[0], 2); } /** * @brief 读取16位整数 */ int16_t at45db_read_int16(uint32_t addr) { i_bytes data; data.value = 0; at45db_read_bytes(addr, &data.byte[0], 2); return data.value; } #endif