打印
[应用相关]

STM32L0 LL库 IIC 配置和使用的问题,发送不出我想要的数据...

[复制链接]
831|6
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
jcky001|  楼主 | 2021-12-28 11:47 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
FW版本是1.12;
使用IC是STM32L0F4U;
CUBEMX配置,使用LL库。
前提:因为从机的IIC是非标准协议,第一个字节不是控制R/W, 不能用HAL库解决,想使用LL库或者寄存器方式来实现,从设备没有问题,使用模拟方式能够实现。
问题:I2C_TXDR这个寄存器的数据,发送不出去。
完全采用LL库函数,其初始化函数如下,频率是400K 、
  • /* I2C1 init function */
  • void MX_I2C1_Init(void)
  • {
  •   /* USER CODE BEGIN I2C1_Init 0 */
  • //        LL_RCC_ClocksTypeDef rcc_clocks;
  •   /* USER CODE END I2C1_Init 0 */
  •   LL_I2C_InitTypeDef I2C_InitStruct = {0};
  •   LL_GPIO_InitTypeDef GPIO_InitStruct = {0};
  •   LL_IOP_GRP1_EnableClock(LL_IOP_GRP1_PERIPH_GPIOA);
  •   /**I2C1 GPIO Configuration
  •   PA9   ------> I2C1_SCL
  •   PA10   ------> I2C1_SDA
  •   */
  •   GPIO_InitStruct.Pin = LL_GPIO_PIN_9;
  •   GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;
  •   GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_VERY_HIGH;
  •   GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_OPENDRAIN;
  •   GPIO_InitStruct.Pull = LL_GPIO_PULL_UP;
  •   GPIO_InitStruct.Alternate = LL_GPIO_AF_1;
  •   LL_GPIO_Init(GPIOA, &GPIO_InitStruct);
  •   GPIO_InitStruct.Pin = LL_GPIO_PIN_10;
  •   GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;
  •   GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_VERY_HIGH;
  •   GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_OPENDRAIN;
  •   GPIO_InitStruct.Pull = LL_GPIO_PULL_UP;
  •   GPIO_InitStruct.Alternate = LL_GPIO_AF_1;
  •   LL_GPIO_Init(GPIOA, &GPIO_InitStruct);
  •   /* Peripheral clock enable */
  •   LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_I2C1);
  •   /* USER CODE BEGIN I2C1_Init 1 */
  • //
  • ////        LL_I2C_Disable(I2C1);
  •   /* USER CODE END I2C1_Init 1 */
  •   /** I2C Initialization
  •   */
  •   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 = 0x00601B28;
  •   I2C_InitStruct.AnalogFilter = LL_I2C_ANALOGFILTER_ENABLE;
  •   I2C_InitStruct.DigitalFilter = 0;
  •   I2C_InitStruct.OwnAddress1 = 0;
  •   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);
  •   /* USER CODE BEGIN I2C1_Init 2 */
  •         LL_I2C_Enable(I2C1);
  •         I2C_write();
  •         /* 5.使能I2C外设. */
  •   /* USER CODE END I2C1_Init 2 */
  • }

复制代码

其中I2C_write()的函数内容是
  • while(LL_I2C_IsActiveFlag_BUSY(I2Cx) == SET){
  •                 counter++;
  •                 if( counter == 25000 ) {//
  •                         Error_Handler();
  •                         return ERROR;
  •                 }
  •         }
  •         LL_I2C_TransmitData8(I2Cx, addr_reg);
  • //        I2Cx->CR2 |= I2C_CR2_START; /* 启动 */
  •         while(LL_I2C_IsActiveFlag_TXE(I2Cx)==RESET)
  •         {
  •                 LL_mDelay(1);
  •                 LL_I2C_TransmitData8(I2Cx, addr_reg);
  • //                I2Cx->CR2 |= I2C_CR2_START; /* 启动 */
  •         }

复制代码

LL_I2C_TransmitData8()    这个库函数完全发送不出来数据,示波器抓取不到波形,TXE位一直是reset。如果使用这一条I2Cx->CR2 |= I2C_CR2_START; /* 启动 */,这能发出波形,但是数据类容并非LL_I2C_TransmitData8中的数据,而是配置的从机地址。
如果调用LL_I2C_HandleTransfer() 这个函数,则能发出来波形,但是这个函数会自动调整R/W位,所以不能在第一个字节使用。
使用这个方法未能实现我需要的功能。
方法二:利用手册中的示例代码,完全寄存器操作,配置好IIC和GPIIO,配置如下:
  •   RCC->IOPENR |= RCC_IOPENR_GPIOBEN;
  •   /* (1) PU for I2C signals */
  •   /* (2) open drain for I2C signals */
  •   /* (3) AF5 for I2C signals */
  •   /* (4) Select AF mode (10) on PB13 and PB14 */
  •   GPIOA->PUPDR = (GPIOA->PUPDR & ~(GPIO_PUPDR_PUPD9 | GPIO_PUPDR_PUPD10)) \
  •                  | (GPIO_PUPDR_PUPD9_0 | GPIO_PUPDR_PUPD10_0); /* (1) */
  •   GPIOA->OTYPER |= GPIO_OTYPER_OT_9 | GPIO_OTYPER_OT_10; /* (2) */
  •   GPIOA->AFR[1] = (GPIOA->AFR[1] & ~((0xF << ( 1 * 4 )) | (0xF << ( 2 * 4 )))) \
  •                   | (1 << ( 1 * 4 )) | (1 << ( 2 * 4 )); /* (3) */
  •   GPIOA->MODER = (GPIOA->MODER & ~(GPIO_MODER_MODE9 | GPIO_MODER_MODE10)) \
  •                  | (GPIO_MODER_MODE9_1 | GPIO_MODER_MODE10_1); /* (4) */
  •     /* Enable the peripheral clock I2C2 */
  •   RCC->APB1ENR |= RCC_APB1ENR_I2C1EN;
  •   /* Configure I2C2, master */
  •   /* (1) Timing register value is computed with the AN4235 xls file,
  •          fast Mode @400kHz with I2CCLK = 16MHz, rise time = 100ns,
  •          fall time = 10ns */
  •   /* (2) Periph enable, receive interrupt enable */
  •   /* (3) Slave address = 0x5A, read transfer, 1 byte to receive, autoend */
  •   I2C1->TIMINGR = (uint32_t)0x00300619; /* (1) */
  •   I2C1->CR1 = I2C_CR1_PE; /* (2) */
  •   I2C1->CR2 =  I2C_CR2_AUTOEND | (1<<16) | (0X5A<<1); /* (3) */

复制代码

调用如下:
  • while(1){
  •                 if((I2Cx->ISR & I2C_ISR_TXE) == (I2C_ISR_TXE)) /* Check Tx empty */
  •                 {
  •                   I2Cx->TXDR = 0x48; /* Byte to send */
  •                   I2Cx->CR2 |= I2C_CR2_START; /* Go */
  •                 }
  •                 LL_mDelay(1);
  •         }

复制代码

发的数据也不是0x48,而是从机地址0x5A<<1 .
实在没招了,求大佬指点

使用特权

评论回复
沙发
zyj213| | 2021-12-31 15:07 | 只看该作者
那你用模拟实现就好啦,这样还方便移植

使用特权

评论回复
板凳
shjuturt| | 2021-12-31 15:38 | 只看该作者
LL库没用过,感觉很难读懂

使用特权

评论回复
地板
ksjdisa| | 2021-12-31 16:18 | 只看该作者
I2C的地址选择的对不对?还有就是时序问题

使用特权

评论回复
5
ppaakala| | 2021-12-31 16:18 | 只看该作者
我觉得建议你还是用模拟I2C吧,毕竟都实现过了,还方便使用

使用特权

评论回复
6
shskaoanc| | 2021-12-31 16:46 | 只看该作者
你仿真跟一下呗,看看程序走到哪儿出的问题

使用特权

评论回复
7
hfaouhfoa| | 2021-12-31 16:47 | 只看该作者
我觉得还是用模拟IIC比较好,省事儿

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

1522

主题

4615

帖子

6

粉丝