STM32:I2C从机未启用时钟拉伸功能
我必须在STM32L053上实现一个I2C从机,以便在从机uC上读取/写入一些任意字节的内存,要求它也适用于不支持时钟拉伸的I2C主机(STM32:I2C从机未启用时钟拉伸功能,stm32,i2c,master-slave,cortex-m,Stm32,I2c,Master Slave,Cortex M,我必须在STM32L053上实现一个I2C从机,以便在从机uC上读取/写入一些任意字节的内存,要求它也适用于不支持时钟拉伸的I2C主机(NOSTRETCH=1) 我在以下方面找到了一个很好的例子: 以下是本条的实施情况: 对于100KHz数据速率下的读取操作,这个实现对我来说没有问题,但是来自主机的写入操作在50%左右正常工作。有时写入的字节正确,有时不正确 这个例子和我的环境之间的区别是,尽管uC有点不同,但STM32L0仍然有偏差,我必须使用一个相当低的系统时钟,因为事实上,我还
NOSTRETCH=1
)
我在以下方面找到了一个很好的例子:
NOSTRETCH=1
设置参考手册的说明:
volatile unsigned char i2c_mem[256]; /* contains data, which read or written */
volatile unsigned char i2c_idx; /* the current index into i2c_mem */
volatile unsigned char i2c_is_write_idx; /* write state */
volatile uint16_t i2c_total_irq_cnt;
volatile uint16_t i2c_TXIS_cnt;
volatile uint16_t i2c_RXNE_cnt;
void i2c_mem_reset_write(void)
{
i2c_is_write_idx = 1;
}
void i2c_mem_init(void)
{
i2c_idx = 0;
i2c_mem_reset_write();
}
void i2c_mem_set_index(unsigned char value)
{
i2c_idx = value;
i2c_is_write_idx = 0;
}
void i2c_mem_write_via_index(unsigned char value)
{
i2c_mem[i2c_idx++] = value;
}
unsigned char i2c_mem_read(void)
{
i2c_mem_reset_write();
i2c_idx++;
return i2c_mem[i2c_idx];
}
void i2c_mem_write(unsigned char value)
{
if ( i2c_is_write_idx != 0 )
{
i2c_mem_set_index(value);
}
else
{
i2c_is_write_idx = 0;
i2c_mem_write_via_index(value);
}
}
void __attribute__ ((interrupt, used)) I2C1_IRQHandler(void)
{
unsigned long isr = I2C1->ISR;
i2c_total_irq_cnt ++;
if ( isr & I2C_ISR_TXIS )
{
i2c_TXIS_cnt++;
I2C1->TXDR = i2c_mem_read();
}
else if ( isr & I2C_ISR_RXNE )
{
i2c_RXNE_cnt++;
i2c_mem_write(I2C1->RXDR);
I2C1->ISR |= I2C_ISR_TXE; // allow overwriting the TCDR with new data
I2C1->TXDR = i2c_mem[i2c_idx];
}
else if ( isr & I2C_ISR_STOPF )
{
I2C1->ICR = I2C_ICR_STOPCF;
I2C1->ISR |= I2C_ISR_TXE; // allow overwriting the TCDR with new data
I2C1->TXDR = i2c_mem[i2c_idx];
i2c_mem_reset_write();
}
else if ( isr & I2C_ISR_NACKF )
{
I2C1->ICR = I2C_ICR_NACKCF;
I2C1->ISR |= I2C_ISR_TXE; // allow overwriting the TCDR with new data
I2C1->TXDR = i2c_mem[i2c_idx];
i2c_mem_reset_write();
}
else if ( isr & I2C_ISR_ADDR )
{
/* not required, the addr match interrupt is not enabled */
I2C1->ICR = I2C_ICR_ADDRCF;
I2C1->ISR |= I2C_ISR_TXE; // allow overwriting the TCDR with new data
I2C1->TXDR = i2c_mem[i2c_idx];
i2c_mem_reset_write();
}
/* if at any time the addr match is set, clear the flag */
/* not sure, whether this is required */
if ( isr & I2C_ISR_ADDR )
{
I2C1->ICR = I2C_ICR_ADDRCF;
}
}
在你的硬件上,它能在32兆赫的频率下工作吗?您使用的是哪个gcc版本?是的,我刚刚尝试了32 MHz,无法再现任何写入错误。我使用的是新的STM32CubeIDE,它用作gcc:arm-none-eabi-gcc.exe(GNU Tools for STM32 7-2018-q2-update.20190328-1800)7.3.1 20180622(发布)[arm embedded-7-branch revision 261907]奇怪的是:我尝试了I2C时钟源的另一个设置,并将其从
RCC\u I2ClKSource\u PCLK1
(是4MHz MSI)更改为RCC\u I2ClKSource\u HSI
(运行频率为16MHz),似乎在4MHz系统时钟下工作。是否I2C外设在这种操作模式下需要超过4Mhz的时钟?我测试了一些定时寄存器的组合,发现没有通信错误的积极变化仅仅来自将I2C外设时钟源从sysclock(4Mhz MSI)更改为HSI(16MHz)。有人知道为什么变通方法有效吗?可能是未记录的硬件故障/限制?