This repository has been archived on 2025-02-28. You can view files and clone it, but cannot push or open issues or pull requests.
controller-hd/User/board/src/eeprom_m95.c

340 lines
11 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* @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;
}
}
}