STM32——I2C——EEPROM 通讯老问题 有波形图 请教大家
EK-stm32的实验板,问题依旧是EEPROM例程无法通过以下分别
http://cache.amobbs.com/bbs_upload782111/files_10/ourdev_383464.jpg
(原文件名:原实验板波形图.jpg)
http://cache.amobbs.com/bbs_upload782111/files_10/ourdev_383465.jpg
(原文件名:上拉改为4.7k后波形图.jpg)
http://cache.amobbs.com/bbs_upload782111/files_10/ourdev_383466.jpg
(原文件名:i2c.jpg)
I2C总线的波形上升沿不够陡,想先把硬件的问题解决掉再考虑程序的问题
怎样能改善这种情况 请教 大家 谢谢 刷贴太快 基本没人看到就沉了
顶一下吧 先把总线速度降到很低,以使波形足够标准,看看软件是否正确再试着慢慢提高总线速度 上拉电阻小了,换成1K的试试吧 to 【2楼】 bluelucky
速度2m的时候 波形规则了许多 按照21ic上给出的驱动函数 可以实现读写,可如果中间出错一次
复位都不行 必须断电才可以下次通过 不知道这个是为什么。
另:固件库都是while()语句,如果死在这里 岂不复位?? 一般都是时序不严格造成的无法读写 400K比较安全 2楼问题解决没有,我现在也碰到这样的问题,是芯片本身问题吧,用51单片即读就没有这个问题 抱歉:是1楼问题解决没有,我现在也碰到这样的问题,是芯片本身问题吧,用51单片机读就没有这个问题,好象用STM32软件
仿真的就可以正常使用,难道是寄存器有问题 1) 建议先把速率降下来把程序调通,然后再提高速率。
2) 建议把上拉电阻放到2.2K或3K,一般保持1~2mA的上拉电流比较好。
3) 波形图中看不到通讯过程,不好说其它有什么问题。 上拉太大了,你看下I2C规范,时钟上升时间都是有要求的。 回复9楼,前期通讯能够建立,并且能够正常读写一次IIC外设,接着就挂了,而且复位都不行,必须断电。
IIC频率40KHZ 11楼的问题可能是第一次正常读写后的结束位不对,请对照示波器仔细检查。 到底有没有问题呀,这个IIC搞死人了,确认一下,各位搞定了没? 我没有搞定拖半年了已经项目没有E2不行
请香主 帮忙给一个“连续读写超过512字节的” 没有问题的例子
代表坛子里所有的搞不定stm32 I2C的人先谢谢香主
另:正在切换 模拟I2C的方案 我手上有的STM32板子在上电之后读EEPROM就死循环了(不是每次都会,复位一下又好了)。
有的板都不会。程序问题?硬件问题?
STM32的IIC真叫人难受呀!!!看来要改模拟接口了。 看下24C02的数据手册。是不是本身速度就不够。。 楼主如果要存的参数不事太多的话,用内部flash模拟的也不错啊。 这个问题不是速度的问题,我目前用的就是400K的,问题在于STm32的I2C的设计问题,这个大家可以去国外的网站上找一下,并且STM32最新的勘误表也指出了这个错误。特别是在I2C读EEP的时候,明显存在问题。
关于I2C读写EEP三种选择:
1、 软件模拟方式,推荐指数2;
2、I2C中断方式,由于STm32的I2C设计问题,导致中断方式几乎不能用(当然可以下载他们最新的历程,好像是可以的,我没有测试过),推荐指数:1或者0;不推荐使用;
3、DMA+I2C的方式,效率最高,而且工作起来也最正常,推荐指数:3;
我在这个问题上也是搞了好久,所以如果用STM32的I2C读写EEP,千万别用中断方式,推荐DMA方式,实在不行就软件模拟方式。 下面是我的用法,大家可以参考一下,没有怎么整理思路,只是把整个I2C相关的代码拷贝了过来,欢迎高手拍砖,呵呵!
//
//use DMA1 channel7 for I2C receive:RRP read
//
static void I2C_RcvDMAConfig(void)
{
DMA_InitTypeDef DMA_InitStructure;
// Deinit the DMA1 Channel7 for I2C revieve
DMA1_Channel7->CCR &= CCR_ENABLE_Reset;
/* Reset DMAy Channelx control register */
DMA1_Channel7->CCR= 0;
/* Reset DMAy Channelx remaining bytes register */
DMA1_Channel7->CNDTR = 0;
/* Reset DMAy Channelx peripheral address register */
DMA1_Channel7->CPAR= 0;
/* Reset DMAy Channelx memory address register */
DMA1_Channel7->CMAR = 0;
/* Reset interrupt pending bits for DMA1 Channel6 */
DMA1->IFCR |= DMA1_Channel7_IT_Mask;
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)I2C1_DR_Address;
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)EEP.ReadBuf;
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
DMA_InitStructure.DMA_BufferSize = 255; /* Just for initialization */
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStructure.DMA_PeripheralDataSize = DMA_MemoryDataSize_Byte;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
DMA_Init(DMA1_Channel7, &DMA_InitStructure);
}
//
//use DMA1 channel6 for I2C send:RRP write
//
static void I2C_SendDMAConfig(void)
{
DMA_InitTypeDef DMA_InitStructure;
// Deinit the DMA1 Channel7 for I2C revieve
DMA1_Channel6->CCR &= CCR_ENABLE_Reset;
/* Reset DMAy Channelx control register */
DMA1_Channel6->CCR= 0;
/* Reset DMAy Channelx remaining bytes register */
DMA1_Channel6->CNDTR = 0;
/* Reset DMAy Channelx peripheral address register */
DMA1_Channel6->CPAR= 0;
/* Reset DMAy Channelx memory address register */
DMA1_Channel6->CMAR = 0;
/* Reset interrupt pending bits for DMA1 Channel6 */
DMA1->IFCR |= DMA1_Channel6_IT_Mask;
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)I2C1_DR_Address;
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)EEP.WriteBuf;
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
DMA_InitStructure.DMA_BufferSize = 255; /* Just for initialization */
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStructure.DMA_PeripheralDataSize = DMA_MemoryDataSize_Byte;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
DMA_InitStructure.DMA_Priority =DMA_Priority_VeryHigh;
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
DMA_Init(DMA1_Channel6, &DMA_InitStructure);
}
/**
* @briefConfigures I2C1
* @paramNone
* @retval : None
*/
static void I2C_MasterConfig(void)
{
I2C_InitTypeDefI2C_InitStructure;
I2C_DeInit(I2C1);
I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;
I2C_InitStructure.I2C_OwnAddress1 = 0x30;
I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;
I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
I2C_InitStructure.I2C_ClockSpeed = ClockSpeed;
I2C_Init(I2C1, &I2C_InitStructure);
I2C_ITConfig(I2C1, I2C_IT_ERR|I2C_IT_EVT, ENABLE);
}
static void I2C_GPIOInit(void)
{
GPIO_InitTypeDefGPIO_InitStructure;
/* 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);
/* Configure P2.01 asEEPROM write protect pin
GPIO2->PC0 |=EEP_WP;
GPIO2->PC1 &= ~EEP_WP;
GPIO2->PC2 |=EEP_WP;*/
ENABLE_EEPWP;
}
//
//config the I2C using the DMA mode fpr send and receive
//
void I2C_Config(void)
{
I2C_MasterConfig();
I2C_RcvDMAConfig();
I2C_SendDMAConfig();
I2C_GPIOInit();
}
//
//EEP read DMA interrupt :I2C rcv
//
void DMA1_Channel7_IRQHandler(void)
{
DMA1_Channel7->CCR &= CCR_ENABLE_Reset; //disable the DMA channel7
DMA1->IFCR = DMA1_FLAG_TC7; //clear the channel6 transfer complete interrupt flag
I2C1->CR1 |= CR1_STOP_Set; //generate stop condition, release the bus
I2C1->CR2 &= (uint16_t)~I2C_IT_EVT; // In order to not have again a BTF event IT
EEP.State = Idle;
}
/**
* EEP read DMA interrupt : I2C send
*/
void DMA1_Channel6_IRQHandler(void)
{
DMA1_Channel6->CCR &= CCR_ENABLE_Reset; //disable the DMA channel6
DMA1->IFCR = DMA1_FLAG_TC6; //clear the channel6 transfer complete interrupt flag
}
/**
* @briefThis function handles I2C1 Event interrupt request.
* @paramNone
* @retval : None
*/
void I2C1_EV_IRQHandler(void)
{
switch (I2C_GetLastEvent(I2C1))
{
case I2C_EVENT_MASTER_MODE_SELECT: /* EV5 */
if(EEP.DMAState == DMARecv)
{
//I2C_Send7bitAddress(I2C1, SLAVE_ADDRESS, I2C_Direction_Receiver);
I2C1->DR = EEP.ChipAddr | 0x01;
}else{
//I2C_Send7bitAddress(I2C1, SLAVE_ADDRESS, I2C_Direction_Transmitter);
I2C1->DR = EEP.ChipAddr & 0xFE;
}
break;
/* Master Transmitter --------------------------------------------------*/
case I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED:
if(EEP.State == EEPWrite)
{
//DMA_Cmd(DMA1_Channel6, ENABLE);
DMA1_Channel6->CCR |= CCR_ENABLE_Set;
}else{
I2C1->DR = EEP.ReadAddr;
}
break;
case I2C_EVENT_MASTER_BYTE_TRANSMITTED:
if(EEP.State == EEPWrite)
{
I2C1->CR1 |= 0x200;
//I2C_ITConfig(I2C1, I2C_IT_EVT, DISABLE); /* In order to not have again a BTF event IT */
I2C1->CR2 &= (uint16_t)~I2C_IT_EVT;
EEP.State = Idle;
}else{
EEP.DMAState = DMARecv;
I2C1->CR1 |= 0x100;
}
break;
/* Master Receiver -------------------------------------------------------*/
case I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED:
// DMA_Cmd(DMA1_Channel7, ENABLE);
DMA1_Channel7->CCR |= CCR_ENABLE_Set;
break;
default:
break;
}
} 这是EEP的读写函数,当然我用的是铁电,没有EEP中的页的概念,所以如果要换到EEP中,要考虑页的概念,还有EEP的写入时间。
void EEP_BufWriteT(U16 Addr, U8* pBuf, U16 NumToWrite)
{
U32 i;
if((NumToWrite > I2CTxBufLen)||(0 == NumToWrite)) return;
EEP.ChipAddr =EEPADDR;
if(Addr>0xFF) EEP.ChipAddr =EEPADDR|0x02;
EEP.State = EEPWrite;
EEP.DMAState = DMASend;
EEP.WriteBuf = (U8)Addr;
for(i=0; i<NumToWrite; i++)
{
EEP.WriteBuf = *(pBuf+i);
}
DMA1_Channel6->CNDTR = NumToWrite+1;//set the DMA length
DMA1_Channel6->CCR |= DMA_IT_TC; // Enable the DMA channel7 transfer complete IT
I2C1->CR2 |= CR2_DMAEN_Set; //Enable DMA
I2C1->CR2 |= I2C_IT_EVT; //Enable the EV interrupt
I2C1->CR1 |= (1<<8); //generate start condition
}
void EEP_Init(void)
{
I2C_Config();
EEP.State = Idle;
EEP.ChipAddr = EEPADDR;
EEP.DMAState = Idle;
}
void EEP_BufReadT(U16 Addr , uint16_t NumToRead)
{
if((NumToRead > I2CRxBufLen)||(0 == NumToRead)) return;
if(1 == NumToRead) NumToRead++;
EEP.ChipAddr =EEPADDR;
if(Addr>255) EEP.ChipAddr =EEPADDR|0x02;
EEP.ReadAddr = Addr;
EEP.State = EEPRead;
EEP.DMAState = DMASend;
DMA1_Channel7->CNDTR = NumToRead;//set the DMA length
DMA1_Channel7->CCR |= DMA_IT_TC; // Enable the DMA channel7 transfer complete IT
I2C1->CR2 |= CR2_LAST_Set; //for the last byte,NACK
I2C1->CR2 |= CR2_DMAEN_Set; //Enable DMA
I2C1->CR2 |= I2C_IT_EVT; //Enable the EV interrupt
I2C1->CR1 |= (1<<8); //generate start condition
} OK了,就这么多了,希望对大家有帮助,我们的产品已经进入最后测试阶段,这个代码可用。当然如果有问题,希望大家一起交流。 11楼的问题我也遇到过,只有断电才能够再次读写,你可以测一下SDA和SCL,那是SDA和SCL不再都为高电平了,就是没有发出停止条件导致的,所以是无法再进行读写的,也是中断方式惹得祸! mark 看到这个帖子真是兴奋呀,该死的I2C,我都不知道该咋办了!!!
我用的是查询方式(未加DMA),EEPROM为:24C16,读写异常。
偶尔能够写,但是读一直都不行,而且,死掉后,复位没用,还得断电停一会,再上电,才又可以,极不稳定。调试起来太吃力了。
是不是硬件设计上也存在问题呢:硬件如下: http://cache.amobbs.com/bbs_upload782111/files_32/ourdev_576147.JPG
图中芯片型号实际为:24c16 (原文件名:I2C.JPG) 还是,程序有问题?程序基本参考列程,部分如下:
I2C初始化如下:
void I2C_Configuration(void)
{
I2C_InitTypeDef I2C_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
// Enable I2C1 Clock
RCC_APB1PeriphResetCmd(RCC_APB1Periph_I2C1, ENABLE);
// Enable GPIOBclocks
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
// Configure I2C1 I2C1-SCL(PB.06(58 port)) and I2C1-SDA(PB.07(59 port)) as output open-drain
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
I2C_InitStructure.I2C_ClockSpeed =I2C_CLKSpeed;
I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;
I2C_InitStructure.I2C_OwnAddress1 = I2C1_SLAVE_ADDRESS7;
I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;
I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
// enable I2C1
I2C_Cmd(I2C1, ENABLE);
//init I2C1
I2C_Init(I2C1, &I2C_InitStructure);
//I2C_Cmd(I2C1, ENABLE);
}
写单个字节:
void I2C_EE_ByteWrite(u8* pBuffer, u8 WriteAddr)
{
/* Send STRAT condition */
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, EEPROM_ADDRESS, I2C_Direction_Transmitter);
/* Test on EV6 and clear it */
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));
/* Send the EEPROM's internal address to write to */
I2C_SendData(I2C1, WriteAddr);
/* Test on EV8 and clear it */
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
/* Send the byte to be written */
I2C_SendData(I2C1, *pBuffer);
/* Test on EV8 and clear it */
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
/* Send STOP condition */
I2C_GenerateSTOP(I2C1, ENABLE);
}
还有: 那个模拟I2C,是什么,能否共享出来参考呀。 这都是老月经了。
http://www.ourdev.cn/bbs/bbs_content.jsp?bbs_sn=3881417 好消息!先谢谢各位指教。
用库2.0,调试通过了。可是换成v3.3.0的,就不行了,只是库的不同,怎么就不行呢?
谁能帮忙解释一下呀,找出原因,谢谢拉 怎么看I2C 通讯是否正常吗? MARK一下,备用 这样的波形太差了,就算能通讯你也不放心呀? 楼主不会买到水货24C02了吧,曾经切身体会过换5、6片才有一片良品的飘过 官网推荐用CPAL来解决I2C问题,但还未试验。 yoyo mark
{:dizzy:}我也遇到这个问题 你的速率太高了吧2m ,上拉电阻直接1K试试!你不能只看stm32的能搞定的频率,你还得看看24C02能否搞定啊!你把24C02的sda 和scl断开波形可能就ok了!!!你换个400K试试!我记得24c02手册说的是最大400K! STM32的IIC有问题~~~?好像很多人都用模拟的方式~ {:time:}{:time:}{:time:}{:time:}{:time:}{:time:} STM32的IIC真的就用库有问题吗?好像很多人都用模拟的方式。有没有解决的,用新的库呢?? tkxlll 发表于 2010-8-19 16:32 static/image/common/back.gif
还是,程序有问题?程序基本参考列程,部分如下:
I2C初始化如下:
我想问一下27楼,你的这段代码后来调通了吗?我碰到了跟你一样的问题 lvyi913 发表于 2009-9-20 21:37 static/image/common/back.gif
这个问题不是速度的问题,我目前用的就是400K的,问题在于STm32的I2C的设计问题,这个大家可以去国外的网站 ...
我用硬件IIC非中断方式成功测试读写EEPROM。
但是在DMA+中断方式测试则出现不能读一个字节的问题。可以读写多个字节! mark……
顶一个…
页:
[1]