通过LL库初始化STM32的硬件IIC
生活随笔
收集整理的這篇文章主要介紹了
通过LL库初始化STM32的硬件IIC
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
前言
talk is cheap, show me the code, 直接看下列的 初始化代碼, 以及讀寫函數吧。
void Configure_I2Cx_Master(I2C_TypeDef *I2Cx) {/* (1) Enables GPIO clock and configures the I2C3 pins **********************//* (SCL on PC.0, SDA on PC.1) **********************//* Enable the peripheral clock of GPIOC */LL_IOP_GRP1_EnableClock(LL_IOP_GRP1_PERIPH_GPIOC);/* Configure SCL Pin as : Alternate function, High Speed, Open drain, Pull up */LL_GPIO_SetPinMode(GPIOC, LL_GPIO_PIN_0, LL_GPIO_MODE_ALTERNATE);LL_GPIO_SetAFPin_0_7(GPIOC, LL_GPIO_PIN_0, LL_GPIO_AF_7);LL_GPIO_SetPinSpeed(GPIOC, LL_GPIO_PIN_0, LL_GPIO_SPEED_FREQ_HIGH);LL_GPIO_SetPinOutputType(GPIOC, LL_GPIO_PIN_0, LL_GPIO_OUTPUT_OPENDRAIN);LL_GPIO_SetPinPull(GPIOC, LL_GPIO_PIN_0, LL_GPIO_PULL_UP);/* Configure SDA Pin as : Alternate function, High Speed, Open drain, Pull up */LL_GPIO_SetPinMode(GPIOC, LL_GPIO_PIN_1, LL_GPIO_MODE_ALTERNATE);LL_GPIO_SetAFPin_0_7(GPIOC, LL_GPIO_PIN_1, LL_GPIO_AF_7);LL_GPIO_SetPinSpeed(GPIOC, LL_GPIO_PIN_1, LL_GPIO_SPEED_FREQ_HIGH);LL_GPIO_SetPinOutputType(GPIOC, LL_GPIO_PIN_1, LL_GPIO_OUTPUT_OPENDRAIN);LL_GPIO_SetPinPull(GPIOC, LL_GPIO_PIN_1, LL_GPIO_PULL_UP);/* (2) Enable the I2C3 peripheral clock and I2C3 clock source ***************//* Enable the peripheral clock for I2C3 */LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_I2C3);/* Set I2C3 clock source as SYSCLK */LL_RCC_SetI2CClockSource(LL_RCC_I2C3_CLKSOURCE_SYSCLK);/* (3) Configure NVIC for I2C3 **********************************************//* Configure Event and Error IT:* - Set priority for I2C3_IRQn* - Enable I2C3_IRQn*/ // NVIC_SetPriority(I2C3_IRQn, 0); // NVIC_EnableIRQ(I2C3_IRQn);/* (4) Configure I2C3 functional parameters *********************************//* Disable I2C3 prior modifying configuration registers */LL_I2C_Disable(I2C3);/* Configure the SDA setup, hold time and the SCL high, low period *//* (uint32_t)0x00601B28 = I2C_TIMING*/uint32_t timing = __LL_I2C_CONVERT_TIMINGS(0x0, 0x6, 0x0, 0x1B, 0x28);LL_I2C_SetTiming(I2C3, timing);/* Configure the Own Address1 *//* Reset Values of :* - OwnAddress1 is 0x00* - OwnAddrSize is LL_I2C_OWNADDRESS1_7BIT* - Own Address1 is disabled*///LL_I2C_SetOwnAddress1(I2C3, 0x00, LL_I2C_OWNADDRESS1_7BIT);//LL_I2C_DisableOwnAddress1(I2C3);/* Enable Clock stretching *//* Reset Value is Clock stretching enabled *///LL_I2C_EnableClockStretching(I2C3);/* Configure Digital Noise Filter *//* Reset Value is 0x00 *///LL_I2C_SetDigitalFilter(I2C3, 0x00);/* Enable Analog Noise Filter *//* Reset Value is Analog Filter enabled *///LL_I2C_EnableAnalogFilter(I2C3);/* Enable General Call *//* Reset Value is General Call disabled *///LL_I2C_EnableGeneralCall(I2C3);/* Configure the 7bits Own Address2 *//* Reset Values of :* - OwnAddress2 is 0x00* - OwnAddrMask is LL_I2C_OWNADDRESS2_NOMASK* - Own Address2 is disabled*///LL_I2C_SetOwnAddress2(I2C3, 0x00, LL_I2C_OWNADDRESS2_NOMASK);//LL_I2C_DisableOwnAddress2(I2C3);/* Configure the Master to operate in 7-bit or 10-bit addressing mode *//* Reset Value is LL_I2C_ADDRESSING_MODE_7BIT *///LL_I2C_SetMasterAddressingMode(I2C3, LL_I2C_ADDRESSING_MODE_7BIT);/* Enable Peripheral in I2C mode *//* Reset Value is I2C mode *///LL_I2C_SetMode(I2C3, LL_I2C_MODE_I2C);/* (5) Enable I2C3 **********************************************************/LL_I2C_Enable(I2C3);/* (6) Enable I2C3 transfer complete/error interrupts:* - Enable Receive Interrupt* - Enable Not acknowledge received interrupt* - Enable Error interrupts* - Enable Stop interrupt*/ // LL_I2C_EnableIT_RX(I2C3); // LL_I2C_EnableIT_NACK(I2C3); // LL_I2C_EnableIT_ERR(I2C3); // LL_I2C_EnableIT_STOP(I2C3); }/*** @brief This Function handle Master events to perform a transmission process* @note This function is composed in different steps :* -1- Initiate a Start condition to the Slave device* -2- Loop until end of transfer received (STOP flag raised)* -2.1- Transmit data (TXIS flag raised)* -3- Clear pending flags, Data consistency are checking into Slave process* @param None* @retval None*/ void I2C_Write(I2C_TypeDef *I2Cx, unsigned char slave_addr, unsigned char reg_addr, unsigned char reg_data) {unsigned char data_size = 2;/* Master Generate Start condition for a write request : *//* - to the Slave with a 7-Bit SLAVE_OWN_ADDRESS *//* - with a auto stop condition generation when transmit all bytes */LL_I2C_HandleTransfer(I2Cx, slave_addr, LL_I2C_ADDRSLAVE_7BIT, data_size, LL_I2C_MODE_AUTOEND, LL_I2C_GENERATE_START_WRITE);/* Loop until STOP flag is raised */while(!LL_I2C_IsActiveFlag_STOP(I2Cx)){/* Check TXIS flag value in ISR register */if(LL_I2C_IsActiveFlag_TXE(I2Cx) && data_size == 2){/* Write data in Transmit Data register.TXIS flag is cleared by writing data in TXDR register */LL_I2C_TransmitData8(I2Cx, reg_addr);data_size--;}/* Check TXIS flag value in ISR register */if(LL_I2C_IsActiveFlag_TXE(I2Cx) && data_size == 1){/* Write data in Transmit Data register.TXIS flag is cleared by writing data in TXDR register */LL_I2C_TransmitData8(I2Cx, reg_data);data_size--;}if(Loop_Is_Timeout_Xms(5))break;}/* (3) Clear pending flags, Data consistency are checking into Slave process *//* End of I2C_SlaveReceiver_MasterTransmitter Process */LL_I2C_ClearFlag_STOP(I2Cx); }/*** @brief This Function handle Master events to perform a transmission process* @note This function is composed in different steps :* -1- Initiate a Start condition to the Slave device* -2- Loop until end of transfer received (STOP flag raised)* -2.1- Transmit data (TXIS flag raised)* -3- Clear pending flags, Data consistency are checking into Slave process* @param None* @retval None*/ unsigned char I2C_Read(I2C_TypeDef *I2Cx, unsigned char slave_addr, unsigned char reg_addr) {unsigned char read_byte = 0;unsigned char data_size = 1;/* Master Generate Start condition for a write request : *//* - to the Slave with a 7-Bit SLAVE_OWN_ADDRESS *//* - with a auto stop condition generation when transmit all bytes */LL_I2C_HandleTransfer(I2Cx, slave_addr, LL_I2C_ADDRSLAVE_7BIT, data_size, LL_I2C_MODE_SOFTEND, LL_I2C_GENERATE_START_WRITE);/* Loop until STOP flag is raised *//* This loop is dangerous when power support is terrrible. */while(!LL_I2C_IsActiveFlag_TC(I2Cx)){/* Check TXIS flag value in ISR register */if(LL_I2C_IsActiveFlag_TXE(I2Cx) && data_size == 1){/* Write data in Transmit Data register.TXIS flag is cleared by writing data in TXDR register */LL_I2C_TransmitData8(I2Cx, reg_addr);data_size--;}if(Loop_Is_Timeout_Xms(3))break;}data_size = 1;LL_I2C_HandleTransfer(I2Cx, slave_addr, LL_I2C_ADDRSLAVE_7BIT, data_size, LL_I2C_MODE_AUTOEND, LL_I2C_GENERATE_START_READ);/* Loop until STOP flag is raised */while(!LL_I2C_IsActiveFlag_STOP(I2Cx)){if(Loop_Is_Timeout_Xms(4))break;}if(LL_I2C_IsActiveFlag_RXNE(I2Cx))read_byte = LL_I2C_ReceiveData8(I2Cx);/* (3) Clear pending flags, Data consistency are checking into Slave process */LL_I2C_ClearFlag_STOP(I2Cx);return read_byte; }問題
Q1: 該LL_I2C_HandleTransfer(I2Cx, slave_addr, LL_I2C_ADDRSLAVE_7BIT, data_size, LL_I2C_MODE_AUTOEND, LL_I2C_GENERATE_START_READ) 函數,非常容易造成使用上的誤解問題,如果不借助邏輯分析儀的話。
A1: 關于這個問題,有幾點需要了解。
眾所周知, 在IIC器件中, 一般有三個地址, 比如hmcl5883設備器件地址為 0x1E, 寫地址為0x3c,讀地址為0x3d, 那么我們在使用stm32的硬件iic的時候, 要將slave_addr的地址值填寫為( 0x1e<<1), 也就是要設置為寫地址0x3c(不是設備地址0x1e),因為在配置了LL_I2C_GENERATE_START_READ之后,芯片會在最后一位自動改變讀寫位的電平狀態, 在讀的時候,自動產生高位電平, 也就是產生讀地址0x3d的電平出去,而如果配置了LL_I2C_GENERATE_START_WRITE之后, 在傳輸完( 0x1e<<1)的地址之后, 最后的地址位為低電平, 也就是寫地址為0x3c。
Q2: 硬件IIC在信號出現抖動(頻率過快的話或者供電不足的情況下), 主機發出的時序會完全錯亂, 比如說, 當頻率過高或者數據線接觸不良,此時我們通過重新初始化從機,且重置硬件iic的錯誤標志,iic硬件接收到的數據雖然會有變化, 但是,讀到的值完全不對, 這時候只能通過重新初始化IIC硬件才能解決, 但是,在L0系列上,利用外部中斷不斷地打斷硬件iic時, 未發現iic數據讀取出現任何較大的異常。
A2:當信號抖動之后, 根據邏輯分析儀,會發現主機在發送從機設備地址的時候,會多發一個字節的數據時序,但是,這個字節數據的值不知從何而來,這便會導致后面讀到的值各種異常, 懷疑是不是移位寄存器在發送的時候,也發送了之前發生總線錯誤的時候,移位寄存器緩存部分字節信息。 因為調試時,相關的接收, 發送寄存器的值都是正常。
總結
以上是生活随笔為你收集整理的通过LL库初始化STM32的硬件IIC的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python文件中单词的删除_使用pyt
- 下一篇: 国际上的12小时制