使用“NUCLEO-L073RZ”开发板进行调试。在调试I2C时,遇到了一些问题。 下面介绍一下我们的使用背景以及遇到的问题: - 使用背景 对外通信是通过I2C接口,L073作为I2C从机,供主机读/写数据 - 遇到的问题 注:通过一个自制的USB转I2C通信板,与“NUCLEO-L073RZ”开发板进行I2C通信。 1. 尝试模拟主机向从机的"BYTE ADDRESS"为0x08的地址写入一个字节的数据,假设为0x12。 通过在线仿真,发现数据已经被正确的写入并保存到相关的数组中了。 接下来,尝试模拟主机从从机的"BYTE ADDRESS"为0x08的地址读出一个字节的数据,出现的现象是: 第一次读,可以正确的读出数据为0x12; 第二次读,读出数据变成了0x00; 第三次读,可以正确的读出数据为0x12; 后面都能正确的读出数据为0x12; 2. 尝试模拟主机向从机的"BYTE ADDRESS"为0x08和0x09的地址连续写入两个字节的数据,假设为0x12和0x34。 通过在线仿真,发现数据已经被正确的写入并保存到相关的数组中了。 接下来,尝试模拟主机从从机的"BYTE ADDRESS"为0x08的地址连续读出两个字节的数据,出现的现象是: 第一次读,可以正确的读出数据为0x12和0x34; 第二次读,读出数据变成了0x00和0x12; 第三次读,读出数据变成了0x34和0x12; 后面读出数据都为0x34和0x12; 3. 尝试模拟主机向从机的"BYTE ADDRESS"为0x08、0x09和0x0A的地址连续写入三个字节的数据,假设为0x12、0x34和0x56。 通过在线仿真,发现数据已经被正确的写入并保存到相关的数组中了。 接下来,尝试模拟主机从从机的"BYTE ADDRESS"为0x08的地址连续读出三个字节的数据,出现的现象是: 第一次读,可以正确的读出数据为0x12、0x34和0x56; 第二次读,读出数据变成了0x00、0x12和0x34; 第三次读,读出数据变成了0x56、0x12和0x34; 后面读出数据都为0x56、0x12和0x34; ... ... 另外,我在调试过程中发现一个现象:就是如果Firmware初次运行的时候,如果接收到I2C读一个字节操作的请求,程序会连续进入TXIS中断两次! 但是紧接着再多次发送读一个字节操作的请求,程序就只会进入TXIS一次了!为什么第一次读操作的时候会进入TXIS中断两次? 附I2C初始化及中断部分代码: /* I2C1 init function */ void MX_I2C1_Init(void) { LL_I2C_InitTypeDef I2C_InitStruct = {0}; LL_GPIO_InitTypeDef GPIO_InitStruct = {0}; LL_IOP_GRP1_EnableClock(LL_IOP_GRP1_PERIPH_GPIOB); /**I2C1 GPIO Configuration PB8 ------> I2C1_SCL PB9 ------> I2C1_SDA */ GPIO_InitStruct.Pin = I2C1_SCL_Pin; GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE; GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_HIGH; GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_OPENDRAIN; GPIO_InitStruct.Pull = LL_GPIO_PULL_UP; GPIO_InitStruct.Alternate = LL_GPIO_AF_4; LL_GPIO_Init(I2C1_SCL_GPIO_Port, &GPIO_InitStruct); GPIO_InitStruct.Pin = I2C1_SDA_Pin; GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE; GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_HIGH; GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_OPENDRAIN; GPIO_InitStruct.Pull = LL_GPIO_PULL_UP; GPIO_InitStruct.Alternate = LL_GPIO_AF_4; LL_GPIO_Init(I2C1_SDA_GPIO_Port, &GPIO_InitStruct); /* Peripheral clock enable */ LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_I2C1); // 使能I2C1的时钟 RCC->CCIPR &= ~RCC_CCIPR_I2C1SEL; // 选择APB时钟作为I2C1的时钟(Cube代码里没有这一行) NVIC_SetPriority(I2C1_IRQn, 0); NVIC_EnableIRQ(I2C1_IRQn); LL_I2C_EnableAutoEndMode(I2C1); LL_I2C_DisableOwnAddress2(I2C1); LL_I2C_DisableGeneralCall(I2C1); LL_I2C_EnableClockStretching(I2C1); I2C_InitStruct.PeripheralMode = LL_I2C_MODE_I2C; I2C_InitStruct.Timing = 0x20302E37; I2C_InitStruct.AnalogFilter = LL_I2C_ANALOGFILTER_ENABLE; I2C_InitStruct.DigitalFilter = 0; I2C_InitStruct.OwnAddress1 = SLAVE_OWN_ADDRESS; I2C_InitStruct.TypeAcknowledge = LL_I2C_ACK; I2C_InitStruct.OwnAddrSize = LL_I2C_OWNADDRESS1_7BIT; LL_I2C_Init(I2C1, &I2C_InitStruct); LL_I2C_SetOwnAddress2(I2C1, 0, LL_I2C_OWNADDRESS2_NOMASK); LL_I2C_EnableIT_ADDR(I2C1); //LL_I2C_EnableIT_NACK(I2C1); //LL_I2C_EnableIT_ERR(I2C1); LL_I2C_EnableIT_STOP(I2C1); //LL_I2C_EnableIT_TC(I2C1); //LL_I2C_EnableIT_RX(I2C1); } /* USER CODE BEGIN 1 */ void I2C_interrupt_op(void) { uint8_t DoPrefetch = 0; // 为I2C读操作执行预取数操作的标志,如果不为0,则需要预先取数 uint8_t Receiverdata; //---------------------------------------- Check ADDR flag value in ISR register //---------------------------------------- 检查是否为地址匹配中断 if(LL_I2C_IsActiveFlag_ADDR(I2C1)) { LL_I2C_ClearFlag_ADDR(I2C1); // Clear ADDR flag value in ISR register //---------------------------------------- Verify the Address Match with the OWN Slave address //---------------------------------------- 检查地址是否为设置的从机地址 if(LL_I2C_GetAddressMatchCode(I2C1) == SLAVE_OWN_ADDRESS) { //---------------------------------------- Verify the transfer direction, a read direction, Slave enters transmitter mode */ //---------------------------------------- 如果传输方向是读操作 if(LL_I2C_GetTransferDirection(I2C1) == LL_I2C_DIRECTION_READ) { I2CBusy = TRUE; LL_I2C_EnableIT_TX(I2C1); // Enable Transmit Interrupt } //---------------------------------------- 如果传输方向是写操作 else if (LL_I2C_GetTransferDirection(I2C1) == LL_I2C_DIRECTION_WRITE) { LL_I2C_EnableIT_RX(I2C1); // Enable Receive Interrupt I2CRxCount = 0; I2CBusy = TRUE; } else { I2C_error_callback(); // Call Error function } } else { I2C_error_callback(); // Call Error function } } //---------------------------------------- Check TXIS flag value in ISR register //---------------------------------------- 发送中断 else if(LL_I2C_IsActiveFlag_TXIS(I2C1)) { //LL_I2C_DisableIT_TX(I2C1); LL_I2C_TransmitData8(I2C1, I2CTxBufData); // Send the Byte requested by the Master DoPrefetch = 1; //---------------------------------------- 低128字节地址寻址 if(DataAddr == 127) { DataAddr = 0; } //---------------------------------------- 高128字节地址寻址 else if(DataAddr == 255) { DataAddr = 128; } //---------------------------------------- 地址索引增1 else { DataAddr++; } } //---------------------------------------- Check RXNE flag value in ISR register //---------------------------------------- 接收中断 else if(LL_I2C_IsActiveFlag_RXNE(I2C1)) { Receiverdata = LL_I2C_ReceiveData8(I2C1); // 将RXDR中的数据保存到Receiverdata //---------------------------------------- 如果是接收到的Data的第一个字节 if(I2CRxCount == 0) { I2CRxCount++; DataAddr = Receiverdata; // 按照协议规定,Data的第一个字节为MEMORY ADDR DoPrefetch = 2; } else { Page00H[DataAddr] = Receiverdata; //---------------------------------------- 低128字节地址寻址 if(DataAddr == 127) { DataAddr = 0; } //---------------------------------------- 高128字节地址寻址 else if(DataAddr == 255) { DataAddr = 128; } //---------------------------------------- 地址索引增1 else { DataAddr++; } } } //---------------------------------------- Check STOP flag value in ISR register //---------------------------------------- STOPF中断 else if(LL_I2C_IsActiveFlag_STOP(I2C1)) { LL_I2C_ClearFlag_STOP(I2C1); // Clear STOP flag value in ISR register I2CBusy = FALSE; } else { I2CBusy = FALSE; I2C_error_callback(); // Call Error function } //---------------------------------------- 如果预取数标志大于0,则需要预先将数据取出并保存到变量I2CTxBufData中去,等待Host去读取 if (DoPrefetch > 0) { I2CTxBufData = Page00H[DataAddr]; } } |
STM32L011D4芯片用SWD无法下载程序
求助:STM32L0系列标准库哪里下?
STM32L051低温时LPUART串口波特率异常
STM32L051单片机ADC如何彻底关闭?
STM32L051C8进入低功耗模式电流偏大
STM32L052C8T6通过I2C模拟读16位数
STM32L0的VLCD外接5V会有问题吗
求助!!使用STM32L073 IO口模拟IIC接口读写AT24CM01 程序不停...
STM32L072RB写Bank2 EEPROM不响应中断
STM32L031无法进入boot
你指的缓存是?能说具体点吗?
多谢了!
FIFO 有残余数据
评分
查看全部评分
评分
查看全部评分
//---------------------------------------- 如果传输方向是读操作
if(LL_I2C_GetTransferDirection(I2C1) == LL_I2C_DIRECTION_READ)
{
LL_I2C_ClearFlag_TXE(I2C1);
LL_I2C_EnableIT_TX(I2C1); // Enable Transmit Interrupt
I2CEvent = EVENT_OPCOD_SEND; // Set I2C entor transmit mode
}
好滴,多谢分享,还是LL库的
HAL库里面很多操作都限定死了,不是很方便。因为我需要用到很多自己定制化的功能,还是觉得LL更好用,甚至我都想用寄存器直接设置