340 lines
11 KiB
C
340 lines
11 KiB
C
/**
|
||
* @file eeprom_m95.c
|
||
* @author xxx
|
||
* @date 2023-08-30 08:58:43
|
||
* @brief 用于实现M95 EEPROM相关的读写操作
|
||
* @copyright Copyright (c) 2023 by xxx, All Rights Reserved.
|
||
*/
|
||
|
||
#include "eeprom_m95.h"
|
||
#include "spis.h"
|
||
#include "delay.h"
|
||
#include "entity.h"
|
||
#include "board.h"
|
||
#include "diagnosis.h"
|
||
|
||
#define M95_SPI SPI1
|
||
#define M95_DMA DMA1
|
||
#define M95_DMA_RX_CHANNEL LL_DMA_CHANNEL_2
|
||
#define M95_DMA_TX_CHANNEL LL_DMA_CHANNEL_3
|
||
|
||
#define EEPROM_M95_1_CS_PORT EE1_CS_GPIO_Port
|
||
#define EEPROM_M95_1_CS_PIN EE1_CS_Pin
|
||
#define EEPROM_M95_2_CS_PORT EE2_CS_GPIO_Port
|
||
#define EEPROM_M95_2_CS_PIN EE2_CS_Pin
|
||
|
||
// 下面宏定义为2个EEPROM_M95的引脚定义
|
||
#define EEPROM_M95_MOSI_PORT SPI_MOSI_GPIO_Port
|
||
#define EEPROM_M95_MOSI_PIN SPI_MOSI_Pin
|
||
#define EEPROM_M95_MISO_PORT SPI_MISO_GPIO_Port
|
||
#define EEPROM_M95_MISO_PIN SPI_MISO_Pin
|
||
#define EEPROM_M95_SCK_PORT SPI_CLK_GPIO_Port
|
||
#define EEPROM_M95_SCK_PIN SPI_CLK_Pin
|
||
|
||
__IO m95_number_e current_m95_number;
|
||
m95_number_t eeprom_m95s[M95_MAX];
|
||
|
||
static void write_enable(spi_t *eeprom_m95_spi); // 写使能
|
||
static void write_disable(spi_t *eeprom_m95_spi); // 写保护
|
||
static uint8_t read_status(spi_t *eeprom_m95_spi); // 读状态
|
||
static void eeprom_m95_ready(m95_number_e num); // 等待就绪
|
||
|
||
// DMA TX回调函数
|
||
static void dma_tx_cb(spi_t *handle)
|
||
{
|
||
DMA_ClEAR_FLAG(handle->dma, 3, handle->tx_dma_ok);
|
||
}
|
||
|
||
// DMA RX回调函数
|
||
static void dma_rx_cb(spi_t *handle)
|
||
{
|
||
DMA_ClEAR_FLAG(handle->dma, 2, handle->rx_dma_ok);
|
||
}
|
||
|
||
/**
|
||
* @brief 初始化EEPROM_M95eeprom_m95s
|
||
* @param {m95_number_e} num
|
||
* @return {*}
|
||
* @note 初始化函数对板卡上不同的芯片定义了块大小
|
||
*/
|
||
void eeprom_m95_init(m95_number_e num)
|
||
{
|
||
DBG_ASSERT(num < M95_MAX __DBG_LINE);
|
||
current_m95_number = num;
|
||
spi_gpio_group_t gpios;
|
||
spi_t *eeprom_m95_spi;
|
||
// 128 byte
|
||
if (num == M95_1)
|
||
{
|
||
// 创建CS引脚
|
||
gpios.cs = gpio_create(EEPROM_M95_1_CS_PORT, EEPROM_M95_1_CS_PIN);
|
||
// 设置页面大小
|
||
eeprom_m95s[num].page_size = M95_PAGE_SIZE_128;
|
||
// 设置总大小
|
||
eeprom_m95s[num].total_size = _M95512_;
|
||
|
||
eeprom_m95s[num].address_bytes = 2;
|
||
}
|
||
// 256 byte
|
||
else if (num == M95_2)
|
||
{
|
||
// 创建CS引脚
|
||
gpios.cs = gpio_create(EEPROM_M95_2_CS_PORT, EEPROM_M95_2_CS_PIN);
|
||
// 设置页面大小
|
||
eeprom_m95s[num].page_size = M95_PAGE_SIZE_256;
|
||
// 设置总大小
|
||
eeprom_m95s[num].total_size = _M95M02_;
|
||
|
||
eeprom_m95s[num].address_bytes = 3;
|
||
}
|
||
else
|
||
{
|
||
DBG_ASSERT(FALSE __DBG_LINE);
|
||
}
|
||
|
||
eeprom_m95s[num].rxbuf = (uint8_t *)osel_mem_alloc(eeprom_m95s[num].page_size + (eeprom_m95s[num].address_bytes + 1) * 2);
|
||
eeprom_m95s[num].txbuf = (uint8_t *)osel_mem_alloc(eeprom_m95s[num].page_size + eeprom_m95s[num].address_bytes + 1);
|
||
|
||
gpios.mosi = gpio_create(SPI_MOSI_GPIO_Port, SPI_MOSI_Pin);
|
||
gpios.sck = gpio_create(SPI_CLK_GPIO_Port, SPI_CLK_Pin);
|
||
gpios.miso = gpio_create(SPI_MISO_GPIO_Port, SPI_MISO_Pin);
|
||
gpios.rst = gpio_create(NULL, 0);
|
||
gpios.rdy = gpio_create(NULL, 0);
|
||
|
||
// 创建SPI对象
|
||
eeprom_m95_spi = spi_create(SPI_TYPE_NORMAL, gpios, 0);
|
||
DBG_ASSERT(eeprom_m95_spi != NULL __DBG_LINE);
|
||
|
||
// 使能SPI
|
||
eeprom_m95_spi->interface.hardware_enable(eeprom_m95_spi, M95_SPI);
|
||
eeprom_m95_spi->interface.dma_enable(eeprom_m95_spi, M95_DMA, M95_DMA_RX_CHANNEL, dma_rx_cb, M95_DMA_TX_CHANNEL, dma_tx_cb);
|
||
eeprom_m95s[num].num = num;
|
||
eeprom_m95s[num].spi = eeprom_m95_spi;
|
||
// 这里需要设置,否则读出的数据不对
|
||
eeprom_m95_spi->gpios.cs->reset(*eeprom_m95_spi->gpios.cs);
|
||
delay_tick(10);
|
||
eeprom_m95_spi->gpios.cs->set(*eeprom_m95_spi->gpios.cs);
|
||
delay_tick(10);
|
||
|
||
// eeprom_m95_test(num);
|
||
}
|
||
|
||
/**
|
||
* @brief 反初始化EEPROM_M95
|
||
* @param {m95_number_e} num
|
||
* @return {*}
|
||
* @note
|
||
*/
|
||
void eeprom_m95_dinit(m95_number_e num)
|
||
{
|
||
LL_SPI_Disable(M95_SPI);
|
||
GPIO_SET_ANALOG(eeprom_m95s[num].spi->gpios.mosi->port, eeprom_m95s[num].spi->gpios.mosi->pin);
|
||
GPIO_SET_ANALOG(eeprom_m95s[num].spi->gpios.miso->port, eeprom_m95s[num].spi->gpios.miso->pin);
|
||
GPIO_SET_ANALOG(eeprom_m95s[num].spi->gpios.sck->port, eeprom_m95s[num].spi->gpios.sck->pin);
|
||
GPIO_SET_ANALOG(eeprom_m95s[num].spi->gpios.cs->port, eeprom_m95s[num].spi->gpios.cs->pin);
|
||
}
|
||
|
||
/**
|
||
* @brief M95 EEPROM使能
|
||
* @return {*}
|
||
* @note
|
||
*/
|
||
void eeprom_m95_enable(void)
|
||
{
|
||
LL_SPI_Enable(M95_SPI);
|
||
}
|
||
|
||
/**
|
||
* @brief M95 EEPROM失能
|
||
* @return {*}
|
||
* @note
|
||
*/
|
||
void eeprom_m95_disable(void)
|
||
{
|
||
LL_SPI_Disable(M95_SPI);
|
||
}
|
||
|
||
/**
|
||
* @brief 读取M95 EEPROM内存数据
|
||
* @param num EEPROM模块编号(0或1)
|
||
* @param read_addr 要读取的地址
|
||
* @param data 存储读取数据的缓冲区
|
||
* @param length 要读取的数据长度
|
||
* @return {*}
|
||
*/
|
||
void eeprom_m95_read(m95_number_e num, uint32_t read_addr, uint8_t *data, uint16_t length)
|
||
{
|
||
current_m95_number = num;
|
||
spi_t *eeprom_m95_spi = eeprom_m95s[num].spi; // 获取EEPROM模块的SPI配置
|
||
eeprom_m95_spi->gpios.cs->reset(*eeprom_m95_spi->gpios.cs); // 设置CS引脚为低电平,准备开始SPI通信
|
||
eeprom_m95_spi->interface.u.normal.spi_send(eeprom_m95_spi, M95_CMD_READ); // 发送读取命令
|
||
if (eeprom_m95s[num].address_bytes == 2)
|
||
{
|
||
eeprom_m95_spi->interface.u.normal.spi_send(eeprom_m95_spi, read_addr >> 8); // 发送高位地址
|
||
eeprom_m95_spi->interface.u.normal.spi_send(eeprom_m95_spi, read_addr); // 发送低位地址
|
||
}
|
||
else
|
||
{
|
||
eeprom_m95_spi->interface.u.normal.spi_send(eeprom_m95_spi, read_addr >> 16);
|
||
eeprom_m95_spi->interface.u.normal.spi_send(eeprom_m95_spi, read_addr >> 8);
|
||
eeprom_m95_spi->interface.u.normal.spi_send(eeprom_m95_spi, read_addr);
|
||
}
|
||
for (uint16_t i = 0; i < length; i++) // 循环读取数据
|
||
{
|
||
data[i] = eeprom_m95_spi->interface.u.normal.spi_send(eeprom_m95_spi, M95_DUMMY_BYTE); // 发送空字节,读取实际数据
|
||
}
|
||
eeprom_m95_spi->gpios.cs->set(*eeprom_m95_spi->gpios.cs); // 设置CS引脚为高电平,完成SPI通信
|
||
}
|
||
|
||
/**
|
||
* @brief 向M95 EEPROM内存写入数据
|
||
* @param num EEPROM模块编号(0或1)
|
||
* @param write_addr 要写入的地址
|
||
* @param data 包含要写入数据的缓冲区
|
||
* @param length 要写入的数据长度
|
||
* @return {*}
|
||
*/
|
||
void eeprom_m95_write(m95_number_e num, uint32_t write_addr, uint8_t *data, uint16_t length)
|
||
{
|
||
current_m95_number = num;
|
||
spi_t *eeprom_m95_spi = eeprom_m95s[num].spi;
|
||
uint32_t page_size = eeprom_m95s[num].page_size;
|
||
DBG_ASSERT(eeprom_m95_spi != NULL __DBG_LINE);
|
||
write_enable(eeprom_m95_spi); // 写入使能命令
|
||
eeprom_m95_spi->gpios.cs->reset(*eeprom_m95_spi->gpios.cs); // 设置CS引脚为低电平,准备开始SPI通信
|
||
eeprom_m95_spi->interface.u.normal.spi_send(eeprom_m95_spi, M95_CMD_WRITE); // 发送写入命令
|
||
|
||
if (eeprom_m95s[num].address_bytes == 2)
|
||
{
|
||
eeprom_m95_spi->interface.u.normal.spi_send(eeprom_m95_spi, write_addr >> 8); // 发送高位地址
|
||
eeprom_m95_spi->interface.u.normal.spi_send(eeprom_m95_spi, write_addr); // 发送低位地址
|
||
}
|
||
else
|
||
{
|
||
eeprom_m95_spi->interface.u.normal.spi_send(eeprom_m95_spi, write_addr >> 16);
|
||
eeprom_m95_spi->interface.u.normal.spi_send(eeprom_m95_spi, write_addr >> 8);
|
||
eeprom_m95_spi->interface.u.normal.spi_send(eeprom_m95_spi, write_addr);
|
||
}
|
||
|
||
while (length--)
|
||
{
|
||
eeprom_m95_spi->interface.u.normal.spi_send(eeprom_m95_spi, *data); // 发送一个字节数据
|
||
data++;
|
||
write_addr++;
|
||
if (((write_addr % page_size) == 0) && (length > 0))
|
||
{
|
||
// 一页写完
|
||
eeprom_m95_spi->gpios.cs->set(*eeprom_m95_spi->gpios.cs); // 设置CS引脚为高电平,完成SPI通信
|
||
eeprom_m95_ready(num);
|
||
|
||
write_enable(eeprom_m95_spi); // 写入使能命令
|
||
eeprom_m95_spi->gpios.cs->reset(*eeprom_m95_spi->gpios.cs); // 设置CS引脚为低电平,准备开始SPI通信
|
||
eeprom_m95_spi->interface.u.normal.spi_send(eeprom_m95_spi, M95_CMD_WRITE); // 发送写入命令
|
||
if (eeprom_m95s[num].address_bytes == 2)
|
||
{
|
||
eeprom_m95_spi->interface.u.normal.spi_send(eeprom_m95_spi, write_addr >> 8); // 发送高位地址
|
||
eeprom_m95_spi->interface.u.normal.spi_send(eeprom_m95_spi, write_addr); // 发送低位地址
|
||
}
|
||
else
|
||
{
|
||
eeprom_m95_spi->interface.u.normal.spi_send(eeprom_m95_spi, write_addr >> 16);
|
||
eeprom_m95_spi->interface.u.normal.spi_send(eeprom_m95_spi, write_addr >> 8);
|
||
eeprom_m95_spi->interface.u.normal.spi_send(eeprom_m95_spi, write_addr);
|
||
}
|
||
}
|
||
}
|
||
eeprom_m95_spi->gpios.cs->set(*eeprom_m95_spi->gpios.cs); // 设置CS引脚为高电平,完成SPI通信
|
||
eeprom_m95_ready(num);
|
||
write_disable(eeprom_m95_spi);
|
||
}
|
||
|
||
/**
|
||
* @brief 用于M95 EEPROM测试
|
||
* @param {m95_number_e} num
|
||
* @return {*}
|
||
* @note
|
||
*/
|
||
void eeprom_m95_test(m95_number_e num)
|
||
{
|
||
#define TEST_LEN 10
|
||
DBG_ASSERT(eeprom_m95s[num].spi != NULL __DBG_LINE);
|
||
uint16_t test_address = 0;
|
||
uint8_t buf[TEST_LEN];
|
||
buf[0] = 0xA5;
|
||
buf[1] = 0xC8;
|
||
buf[2] = 0x00;
|
||
buf[3] = 0x03;
|
||
buf[4] = num;
|
||
buf[5] = 0xaa;
|
||
buf[6] = 0xbb;
|
||
buf[TEST_LEN - 1] = 0xce;
|
||
eeprom_m95_write(num, test_address, buf, TEST_LEN);
|
||
osel_memset(buf, 0, ARRAY_LEN(buf));
|
||
eeprom_m95_read(num, test_address, buf, TEST_LEN);
|
||
|
||
__NOP();
|
||
}
|
||
|
||
/**
|
||
* @brief M95 EEPROM写使能
|
||
* @param {spi_t} *eeprom_m95_spi
|
||
* @return {*}
|
||
* @note
|
||
*/
|
||
static void write_enable(spi_t *eeprom_m95_spi)
|
||
{
|
||
eeprom_m95_spi->gpios.cs->reset(*eeprom_m95_spi->gpios.cs);
|
||
eeprom_m95_spi->interface.u.normal.spi_send(eeprom_m95_spi, M95_CMD_WREN);
|
||
eeprom_m95_spi->gpios.cs->set(*eeprom_m95_spi->gpios.cs);
|
||
}
|
||
|
||
/**
|
||
* @brief M95 EEPROM写保护
|
||
* @param {spi_t} *eeprom_m95_spi
|
||
* @return {*}
|
||
* @note
|
||
*/
|
||
static void write_disable(spi_t *eeprom_m95_spi)
|
||
{
|
||
eeprom_m95_spi->gpios.cs->reset(*eeprom_m95_spi->gpios.cs);
|
||
eeprom_m95_spi->interface.u.normal.spi_send(eeprom_m95_spi, M95_CMD_WRDI);
|
||
eeprom_m95_spi->gpios.cs->set(*eeprom_m95_spi->gpios.cs);
|
||
}
|
||
|
||
/**
|
||
* @brief M95 EEPROM读状态
|
||
* @param {spi_t} *eeprom_m95_spi
|
||
* @return {*}
|
||
* @note
|
||
*/
|
||
static uint8_t read_status(spi_t *eeprom_m95_spi)
|
||
{
|
||
uint8_t data;
|
||
eeprom_m95_spi->gpios.cs->reset(*eeprom_m95_spi->gpios.cs);
|
||
eeprom_m95_spi->interface.u.normal.spi_send(eeprom_m95_spi, M95_CMD_RDSR);
|
||
data = eeprom_m95_spi->interface.u.normal.spi_send(eeprom_m95_spi, M95_DUMMY_BYTE);
|
||
eeprom_m95_spi->gpios.cs->set(*eeprom_m95_spi->gpios.cs);
|
||
|
||
return data;
|
||
}
|
||
|
||
/**
|
||
* @brief M95 EEPROM等待就绪
|
||
* @param {m95_number_e} num
|
||
* @return {*}
|
||
* @note
|
||
*/
|
||
static void eeprom_m95_ready(m95_number_e num)
|
||
{
|
||
spi_t *eeprom_m95_spi = eeprom_m95s[num].spi;
|
||
uint16_t count = 0;
|
||
while (read_status(eeprom_m95_spi) & 0x01)
|
||
{
|
||
if (count++ > 2000)
|
||
{
|
||
__NOP();
|
||
break;
|
||
}
|
||
}
|
||
}
|