关于EEPROM(AT24C32)的调试总结与分析

因项目用到的AT24C32存在两批不一样的芯片,一批是ATML还没被microchip收购时候买的芯片,一批是microchip收购了ATML之后买的芯片;他们的数据手册上关于写周期是这么描述的:ATML的写周期时间是最大10ms,microchip的写周期是最大5ms;

在实际的使用中,一般都是使用单字节写入的方式进行操作,即使需要连续写入也只是利用for循环调用单字节写入的形式,或,其他的方式调用单字节写入函数的方式进行;为了减少不必要的延时导致CPU被占用,项目采用的是软定时2ms调度的方式进行EEPROM的读写操作,这样在写周期的时候系统不会阻塞,可以执行其他的任务。重点注意一下这个2ms ,这个2ms就是实际的写周期时间,一直以来使用ATML的芯片都没有出现问题,(提醒一下数据手册上ATML的写周期时间最大是10ms);然而,当换成microchip生产的芯片之后,这个2ms就不够用了,在进行连续大量的写入操作的时候会写入失败!就是这么操蛋,改成5ms就可以了。

你以为这就结束了,必不可能这么简单呀。在项目中,对EEPROM进行大量读写的情况在首次上电和恢复默认值操作的时候,这个程序里是写成了先写入,写入完成之后全部读出进行一一校对,再根据校对结果判定是不是写入成功。这样其实就有个问题,在恢复默认值的时候,一直在while(判定结果),while里面有超时判定,校对失败和超时都会输ERROR。但是在以前使用2ms的写周期,现在变成了5ms,这就导致了时间直接加长了2.5倍。在项目中对时间的要求又很高,不允许时间变长2.5倍怎么办?

然后看了各种资料,最后在官方资料中找到一种解决方案,在写周期时间内进行轮询应答的方式来检测EEPROM是否可以操作了。

轮询应答的代码是这样的,

然后在需要进行读写操作的时候调用这个函数,看看EEPROM是不是准备好了;然后我在项目直接将EEPROM的任务调度时间间隔改成1ms,进入任务后先判断EEPROM是否准备好,准备好了就进行读写操作,否则就直接return;这样处理之后,时间就和原来的差不多了,虽然还是比原来的时间要多一点,但是在可接受的范围了。系统调度的时间间隔其实是为了解决这个写周期时间的,意思就是说读取EEPROM的数据时,其实可以在us级的时间间隔内进行连续读取,因此如果还想减少这个恢复默认值的任务所占用的时间,可以将任务调度的时间放到100us这个数量级,也就是更快的查询EEPROM的状态,进而间接的减少连续读写过程中的字节与字节之间的时间间隔,这样整体的时间占用会更少。(相当对提高了判断时间间隔,这样读取和写入的时间都会有影响)

问:为什么不用页写?

答:其实一开始我想的也是使用页写,但是项目写入的数据不是连续地址,这是其一,其二是如果采用页写,程序得大改,做市场级产品的人都应该明白,大改意味着什么?想想美国现在的核系统为什么仍在使用二战时期的计算机和系统?

最后:

如果你对EEPROM的操作有什么经验或者对我这个处理方式有另类的处理方式,请给我发消息~ 期待与你交流!

  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是使用STM32F103与AT24C02之间通过IIC通信的程序,实现向EEPROM中写入字符串,并通过USART串口将读取到的内容发送到PC机上的串口调试助手: ```c #include "stm32f10x.h" #include "stm32f10x_gpio.h" #include "stm32f10x_i2c.h" #include "stm32f10x_usart.h" #include "stdio.h" #define I2C1_SLAVE_ADDRESS7 0xA0 void I2C_Configuration(void); void USART_Configuration(void); void Delay(__IO uint32_t nCount); int main(void) { uint8_t buff[] = "Hello, World!"; uint8_t read_buff[20]; int i; USART_Configuration(); I2C_Configuration(); /* Start Transfer */ I2C_GenerateSTART(I2C1, ENABLE); /* Test on EV5 and clear it */ while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT)); /* Send EEPROM address for write */ I2C_Send7bitAddress(I2C1, I2C1_SLAVE_ADDRESS7, I2C_Direction_Transmitter); /* Test on EV6 and clear it */ while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)); /* Write to EEPROM */ for (i = 0; i < sizeof(buff); i++) { I2C_SendData(I2C1, buff[i]); /* Test on EV8 and clear it */ while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED)); } /* Send Stop */ I2C_GenerateSTOP(I2C1, ENABLE); /* Wait for EEPROM to finish writing */ Delay(0xFFFF); /* Start Transfer */ I2C_GenerateSTART(I2C1, ENABLE); /* Test on EV5 and clear it */ while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT)); /* Send EEPROM address for read */ I2C_Send7bitAddress(I2C1, I2C1_SLAVE_ADDRESS7, I2C_Direction_Receiver); /* Test on EV6 and clear it */ while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED)); /* Read from EEPROM */ for (i = 0; i < sizeof(read_buff); i++) { /* Test on EV7 and clear it */ while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_RECEIVED)); read_buff[i] = I2C_ReceiveData(I2C1); } /* Send Stop */ I2C_GenerateSTOP(I2C1, ENABLE); /* Send received data to USART */ for (i = 0; i < sizeof(read_buff); i++) { USART_SendData(USART1, read_buff[i]); while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET); } while(1) {} } void I2C_Configuration(void) { I2C_InitTypeDef I2C_InitStructure; GPIO_InitTypeDef GPIO_InitStructure; /* Enable GPIOB clock */ RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); /* Configure I2C1 pins: SCL and SDA */ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD; GPIO_Init(GPIOB, &GPIO_InitStructure); /* Enable I2C1 clock */ RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE); /* I2C1 configuration */ I2C_InitStructure.I2C_Mode = I2C_Mode_I2C; I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2; I2C_InitStructure.I2C_OwnAddress1 = 0x00; I2C_InitStructure.I2C_Ack = I2C_Ack_Enable; I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit; I2C_InitStructure.I2C_ClockSpeed = 100000; /* Apply I2C1 configuration after enabling it */ I2C_Init(I2C1, &I2C_InitStructure); I2C_Cmd(I2C1, ENABLE); } void USART_Configuration(void) { USART_InitTypeDef USART_InitStructure; GPIO_InitTypeDef GPIO_InitStructure; /* Enable GPIOA clock */ RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); /* Enable USART1 clock */ RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE); /* Configure USART1 pins: TX and RX */ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_10; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_Init(GPIOA, &GPIO_InitStructure); /* USART1 configuration */ USART_InitStructure.USART_BaudRate = 115200; USART_InitStructure.USART_WordLength = USART_WordLength_8b; USART_InitStructure.USART_StopBits = USART_StopBits_1; USART_InitStructure.USART_Parity = USART_Parity_No; USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; USART_InitStructure.USART_Mode = USART_Mode_Tx; /* Apply USART1 configuration after enabling it */ USART_Init(USART1, &USART_InitStructure); USART_Cmd(USART1, ENABLE); } void Delay(__IO uint32_t nCount) { for(; nCount != 0; nCount--); } ``` 在串口调试助手中打开串口,波特率设置为115200,连接STM32F103的USART1引脚(PA9和PA10),运行程序,串口调试助手将会输出从EEPROM中读取到的字符串。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值