本帖最后由 giveup 于 2016-5-31 08:03 编辑
采用STM32CubeMX 配置一块STM32F407VET6的核心板,通过I2C1读写AT24C08 EEPROM。可以选择BSP方式,或者到HAL库中挑选BSP驱动,效果一样。因为我的工程已经初始化过了,所以采用后种方式。
采用默认值配置I2C1,选中NVIC Settings中的 I2C1 event interrupt和 I2C1 error interrupt。生成工程模板。将AT24C98N EEPROM连接到PB6,PB7。器件A0,A1,A2引脚悬空,地址为0。
在安装库中复制eeprom的BSP驱动,应该都一样。如复制下列4个文件到工程目录下:
STM32Cube/Repository/STM32Cube_FW_F4_V1.12.0/Drivers/BSP/STM324xG_EVAL/stm324xg_eval_eeprom.c
STM32Cube/Repository/STM32Cube_FW_F4_V1.12.0/Drivers/BSP/STM324xG_EVAL/stm324xg_eval_eeprom.h
STM32Cube/Repository/STM32Cube_FW_F4_V1.12.0/Drivers/BSP/STM324xG_EVAL/stm324xg_eval.c
STM32Cube/Repository/STM32Cube_FW_F4_V1.12.0/Drivers/BSP/STM324xG_EVAL/stm324xg_eval.h
stm324xg_eval.c和stm324xg_eval.h中保留和EEPROM相关内容即可。
重点的问题是,这个驱动支持的是M24C64 EEPROM,和AT24C08 EEPROM有一定差异,需要修改部分内容才能使用。主要体现在读写页面尺寸、容量和器件地址表示不一致。
根据手册,AT24C04~AT24C32的内存地址是分为两部分,除低八位外,高3位占用了器件的地址。如AT24C08,内存大小为1024字节,地址为10位,高2位占用了器件地址A1,A0。M24C64 EEPROM的内存地址为16位,和AT24C32以上的EEPROM保持一致。
因此,主要修改点为:
1。修改页面尺寸与地址大小
stm324xg_eval_eeprom.h中,修改定义:
#define EEPROM_PAGESIZE 16
#define EEPROM_MAX_SIZE 0x400 /* 8Kbit */
添加定义
#define EEPROM_MEMADD_SIZE I2C_MEMADD_SIZE_8BIT
#define MEMADD_MSB_MASK 0x3
2。修改读写函数
2.1 读操作部分修改逻辑:
该部分的逻辑是 BSP_EEPROM_ReadBuffer 经过 EEPROM_IO_ReadData 调用I2Cx_ReadMultiple完成实际读写。
因为读函数采用连续读方式,只要设定了正确的内存起始地址,就能正常完成读操作。因此,修改只涉及到BSP_EEPROM_ReadBuffer和EEPROM_IO_ReadData两个函数。具体修改如下,红色部分是增加和修改的:
- uint32_t BSP_EEPROM_ReadBuffer(uint8_t* pBuffer, uint16_t ReadAddr, uint16_t* NumByteToRead) {
- uint32_t buffersize = *NumByteToRead;
- /* Set the pointer to the Number of data to be read. This pointer will be used
- by the DMA Transfer Completer interrupt Handler in order to reset the
- variable to 0. User should check on this variable in order to know if the
- DMA transfer has been complete or not. */
- EEPROMDataRead = *NumByteToRead;
- <font color="Red">uint16_t A_EEPROMAddress = EEPROMAddress;
- uint8_t A2A1A0 = (uint8_t) ((ReadAddr >> 8) & MEMADD_MSB_MASK);
- A_EEPROMAddress = A_EEPROMAddress | (A2A1A0<<1);</font>
- if (EEPROM_IO_ReadData(<font color="Red">A_EEPROMAddress</font>, ReadAddr, pBuffer, buffersize) != HAL_OK) {
- BSP_EEPROM_TIMEOUT_UserCallback();
- return EEPROM_FAIL;
- }
- /* If all operations OK, return EEPROM_OK (0) */
- return EEPROM_OK;
- }
复制代码
将I2C_MEMADD_SIZE_16BIT替换为上面新增加的EEPROM_MEMADD_SIZE定义:
- HAL_StatusTypeDef EEPROM_IO_ReadData(uint16_t DevAddress, uint16_t MemAddress, uint8_t* pBuffer, uint32_t BufferSize)
- {
- return
- (I2Cx_ReadMultiple(DevAddress, MemAddress, <font color="Red">EEPROM_MEMADD_SIZE</font>, pBuffer, BufferSize));
- }
复制代码
2.2写操作部分函数修改逻辑:
写操作调用关系是BSP_EEPROM_WriteBuffer负责将写地址分页,并完成页面对齐后,调用BSP_EEPROM_WritePage经过EEPROM_IO_WriteData完成实际写操作。修改部分只涉及到后边两个函数,具体见下面红色部分:
- uint32_t BSP_EEPROM_WritePage(uint8_t* pBuffer, uint16_t WriteAddr, uint8_t* NumByteToWrite) {
- uint32_t buffersize = *NumByteToWrite;
- uint32_t status = EEPROM_OK;
- /* Set the pointer to the Number of data to be written. This pointer will be used
- by the DMA Transfer Completer interrupt Handler in order to reset the
- variable to 0. User should check on this variable in order to know if the
- DMA transfer has been complete or not. */
- EEPROMDataWrite = *NumByteToWrite;
- <font color="Red"> uint16_t A_EEPROMAddress = EEPROMAddress;
- uint8_t A2A1A0 = (uint8_t) ((WriteAddr >> 8) & MEMADD_MSB_MASK);
- A_EEPROMAddress = A_EEPROMAddress | (A2A1A0<<1);</font>
- if (EEPROM_IO_WriteData(<font color="Red">A_EEPROMAddress</font>, WriteAddr, pBuffer, buffersize) != HAL_OK) {
- BSP_EEPROM_TIMEOUT_UserCallback();
- status = EEPROM_FAIL;
- }
- if (BSP_EEPROM_WaitEepromStandbyState() != EEPROM_OK) {
- return EEPROM_FAIL;
- }
- /* If all operations OK, return EEPROM_OK (0) */
- return status;
- }
复制代码
具体写操作修改和读操作差不多:
- HAL_StatusTypeDef EEPROM_IO_WriteData(uint16_t DevAddress, uint16_t MemAddress, uint8_t* pBuffer, uint32_t BufferSize)
- {
- return
- (I2Cx_WriteMultiple(DevAddress, MemAddress,<font color="Red"> EEPROM_MEMADD_SIZE</font>, pBuffer, BufferSize));
- }
复制代码
3. 初始化及其他操作修改。STM32CubeMX已经正确生成了初始化代码,因此除了下面的两个,大部分BSP的初始化代码都可以删除。
- void EEPROM_IO_Init(void)
- {
- I2Cx_Init();
- }
复制代码 修改为MX的初始化代码
- void EEPROM_IO_Init(void)
- {
- MX_I2C1_Init();
- }
复制代码
修改函数,取消一些不必要的调用:
- uint32_t BSP_EEPROM_Init(void) {
- /* I2C Initialization */
- <font color="Red">// EEPROM_IO_Init();</font>
- /* Select the EEPROM address for A01 and check if OK */
- EEPROMAddress = EEPROM_I2C_ADDRESS_A01;
- if (EEPROM_IO_IsDeviceReady(EEPROMAddress, EEPROM_MAX_TRIALS) != HAL_OK) {
- // /* Select the EEPROM address for A02 and check if OK */
- // EEPROMAddress = EEPROM_I2C_ADDRESS_A02;
- // if(EEPROM_IO_IsDeviceReady(EEPROMAddress, EEPROM_MAX_TRIALS) != HAL_OK)
- // {
- return EEPROM_FAIL;
- // }
- }
- return EEPROM_OK;
- }
复制代码
另外,需要将stm324xg_eval.c中的 heval_I2c 变量实例替换为hi2c1。可以用查找替换或者宏定义。
4. 使用例子
4.1 初始化
在main.c的
- /* USER CODE BEGIN 2 */
- BSP_EEPROM_Init();
- /* USER CODE END 2 */
复制代码 或者其他适当地方添加初始化设置,完成EEPROM地址的设定。
4.2使用可以参考相应代码。如:
- #define EEPROM_CFG_ADDRESS 0x120 //和页面对齐
- __IO uint8_t EEPROMConnected = 1;
- typedef struct {
- uint16_t valide;
- uint8_t databuf[16];
- }CfgData;
- CfgData cfg; //全局的一个结构变量
- /**
- * @brief 从EEPROM 中读出参数
- * @param 无
- * @retval 0成功 其他失败: 1 通信错误 2 无效设置
- */
- uint8_t read_cfg_eeprom(void) {
- CfgData cfg_read;
- uint16_t readSize= (uint16_t) sizeof(CfgData);
- EEPROMConnected = 1; //超时回调函数设定
- /* Wait for EEPROM standby state */
- BSP_EEPROM_WaitEepromStandbyState();
- /* Read old parameter in EEPROM */
- if (EEPROMConnected == 1) {
- /* Set the Number of data to be read */
- memset((uint8_t*)&cfg_read,0,readSize);
- /* Read from I2C EEPROM from EEPROM_CFG_ADDRESS */
- if (BSP_EEPROM_ReadBuffer((uint8_t*)&cfg_read, EEPROM_CFG_ADDRESS, &readSize) != EEPROM_OK) {
- return 1; //通信错误
- }
- if (cfg_read.valide == 0x55aa) { //有效的
- memcpy((void*)&cfg, (void *)&cfg_read, sizeof(CfgData));
- return 0; //正常
- }
- }
- return 2; //无效设置
- }
- /**
- * @brief 保存参数到 EEPROM 中
- * @param 无
- * @retval 0成功 其他失败
- */
- uint8_t save_cfg2eeprom(void) {
- EEPROMConnected = 1;
- /* Wait for EEPROM standby state */
- BSP_EEPROM_WaitEepromStandbyState();
- /* Write new parameter in EEPROM */
- if (EEPROMConnected == 1) {
- /* Write on I2C EEPROM to EEPROM_CFG_ADDRESS */
- if (BSP_EEPROM_WriteBuffer((uint8_t*)&cfg, EEPROM_CFG_ADDRESS, (uint16_t) sizeof(CfgData)) == EEPROM_OK) {
- return 0;
- }
- }
- return 1;
- }
- /**
- * @brief Basic management of the timeout situation.
- * @param None.
- * @retval None
- */
- void BSP_EEPROM_TIMEOUT_UserCallback(void) {
- EEPROMConnected = 0;
- }
复制代码 经过调试并下载到核心板运行,测试结果正常。所用软件环境:
STM32CubeMX 4.15.0
STM32Cube_FW_F4_V1.12.0
GNU ARM C/C++ for eclipse 2.5.1.201604190915
eclipse 4.4.2 luna
Debian sid: Linux Debian 4.5.0-2-686-pae #1 SMP Debian 4.5.4-1 (2016-05-16) i686 GNU/Linux
|