Trong STM32F1:
- APB1 bus: chứa các ngoại vi như I2C1, I2C2, USART2/3, SPI2, TIM2–TIM7…
- APB2 bus: chứa các ngoại vi như USART1, SPI1, ADC1/2, TIM1, GPIO…
Mỗi bus này nhận clock riêng
- PCLK1 → clock cho APB1
- PCLK2 → clock cho APB2
Sau đây là các bước để sử dụng I2C dùng thư viện LL trên stm32f103c8t6.
Bước 1: Cấu hình tần số
/** * @brief I2C devices settings */
/* I2C SPEEDCLOCK define to value: Stardard Mode @100kHz */
#define I2C_SPEEDCLOCK 100000
#define I2C_DUTYCYCLE LL_I2C_DUTYCYCLE_2
Bước 2: Định nghĩa hàm hoạt động
void Configure_I2C_Master(void);
void Activate_I2C_Master(void);
void Handle_I2C_Master(void);
/** * @brief This function configures I2C1 in Master mode. * @note This function is used to : * -1- Enables GPIO clock. * -2- Enable the I2C1 peripheral clock and configures the I2C1 pins. * -3- Configure I2C1 functional parameters. * @note Peripheral configuration is minimal configuration from reset values. * Thus, some useless LL unitary functions calls below are provided as * commented examples - setting is default configuration from reset. * @param None * @retval None */
void Configure_I2C_Master(void)
{ LL_RCC_ClocksTypeDef rcc_clocks; /* (1) Enables GPIO clock **********************/ /* Enable the peripheral clock of GPIOB */ LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_GPIOB); /* (2) Enable the I2C1 peripheral clock *************************************/ /* Enable the peripheral clock for I2C1 */ LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_I2C1); /* Configure SCL Pin as : Alternate function, High Speed, Open drain, Pull up */ LL_GPIO_SetPinMode(GPIOB, LL_GPIO_PIN_6, LL_GPIO_MODE_ALTERNATE); LL_GPIO_SetPinSpeed(GPIOB, LL_GPIO_PIN_6, LL_GPIO_SPEED_FREQ_HIGH); LL_GPIO_SetPinOutputType(GPIOB, LL_GPIO_PIN_6, LL_GPIO_OUTPUT_OPENDRAIN); LL_GPIO_SetPinPull(GPIOB, LL_GPIO_PIN_6, LL_GPIO_PULL_UP); /* Configure SDA Pin as : Alternate function, High Speed, Open drain, Pull up */ LL_GPIO_SetPinMode(GPIOB, LL_GPIO_PIN_7, LL_GPIO_MODE_ALTERNATE); LL_GPIO_SetPinSpeed(GPIOB, LL_GPIO_PIN_7, LL_GPIO_SPEED_FREQ_HIGH); LL_GPIO_SetPinOutputType(GPIOB, LL_GPIO_PIN_7, LL_GPIO_OUTPUT_OPENDRAIN); LL_GPIO_SetPinPull(GPIOB, LL_GPIO_PIN_7, LL_GPIO_PULL_UP); /* (3) Configure I2C1 functional parameters ********************************/ /* Disable I2C1 prior modifying configuration registers */ LL_I2C_Disable(I2C1); /* Retrieve Clock frequencies */ LL_RCC_GetSystemClocksFreq(&rcc_clocks); /* Configure the SCL Clock Speed */ LL_I2C_ConfigSpeed(I2C1, rcc_clocks.PCLK1_Frequency, I2C_SPEEDCLOCK, I2C_DUTYCYCLE); /* Configure the Own Address1 */ /* Reset Values of : * - OwnAddress1 is 0x00 * - OwnAddrSize is LL_I2C_OWNADDRESS1_7BIT */ //LL_I2C_SetOwnAddress1(I2C1, 0x00, LL_I2C_OWNADDRESS1_7BIT); /* Enable Clock stretching */ /* Reset Value is Clock stretching enabled */ //LL_I2C_EnableClockStretching(I2C1); /* Enable General Call */ /* Reset Value is General Call disabled */ //LL_I2C_EnableGeneralCall(I2C1); /* Configure the 7bits Own Address2 */ /* Reset Values of : * - OwnAddress2 is 0x00 * - Own Address2 is disabled */ //LL_I2C_SetOwnAddress2(I2C1, 0x00); //LL_I2C_DisableOwnAddress2(I2C1); /* Enable Peripheral in I2C mode */ /* Reset Value is I2C mode */ //LL_I2C_SetMode(I2C1, LL_I2C_MODE_I2C);
}
/** * @brief This function Activate I2C1 peripheral (Master) * @note This function is used to : * -1- Enable I2C1. * @param None * @retval None */
void Activate_I2C_Master(void)
{ /* (1) Enable I2C1 **********************************************************/ LL_I2C_Enable(I2C1);
}
/** * @brief Slave settings */
#define SLAVE_OWN_ADDRESS 0x5A // địa chỉ này đã dịch sang trái một bit, vd: địa chỉ thực của slave = 0010 1101 /** * @brief Master Transfer Request Direction */
#define I2C_REQUEST_WRITE 0x00
#define I2C_REQUEST_READ 0x01 /** * @brief This Function handle Master events to perform a transmission process * @note This function is composed in different steps : * -1- Prepare acknowledge for Master data reception. * -2- Initiate a Start condition to the Slave device. * -3- Loop until Start Bit transmitted (SB flag raised). * -4- Send Slave address with a 7-Bit SLAVE_OWN_ADDRESS for a write request. * -5- Loop until Address Acknowledgement received (ADDR flag raised). * -6- Clear ADDR flag and loop until end of transfer (ubNbDataToTransmit == 0). * -6.1 Transmit data (TXE flag raised). * -7- End of transfer, Data consistency are checking into Slave process. * @param None * @retval None */
void Handle_I2C_Master(void)
{ /* (1) Prepare acknowledge for Master data reception ************************/ LL_I2C_AcknowledgeNextData(I2C1, LL_I2C_ACK); /* (2) Initiate a Start condition to the Slave device ***********************/ /* Master Generate Start condition */ LL_I2C_GenerateStartCondition(I2C1); /* (3) Loop until Start Bit transmitted (SB flag raised) ********************/ #if (USE_TIMEOUT == 1) Timeout = I2C_SEND_TIMEOUT_SB_MS;
#endif /* USE_TIMEOUT */ /* Loop until SB flag is raised */ while(!LL_I2C_IsActiveFlag_SB(I2C1)) {
#if (USE_TIMEOUT == 1) /* Check Systick counter flag to decrement the time-out value */ if (LL_SYSTICK_IsActiveCounterFlag()) { if(Timeout-- == 0) { /* Time-out occurred. Set LED2 to blinking mode */ LED_Blinking(LED_BLINK_SLOW); } }
#endif /* USE_TIMEOUT */ } /* (4) Send Slave address with a 7-Bit SLAVE_OWN_ADDRESS for a write request */ LL_I2C_TransmitData8(I2C1, SLAVE_OWN_ADDRESS | I2C_REQUEST_WRITE); /* (5) Loop until Address Acknowledgement received (ADDR flag raised) *******/ #if (USE_TIMEOUT == 1) Timeout = I2C_SEND_TIMEOUT_ADDR_MS;
#endif /* USE_TIMEOUT */ /* Loop until ADDR flag is raised */ while(!LL_I2C_IsActiveFlag_ADDR(I2C1)) {
#if (USE_TIMEOUT == 1) /* Check Systick counter flag to decrement the time-out value */ if (LL_SYSTICK_IsActiveCounterFlag()) { if(Timeout-- == 0) { /* Time-out occurred. Set LED2 to blinking mode */ LED_Blinking(LED_BLINK_SLOW); } }
#endif /* USE_TIMEOUT */ } /* (6) Clear ADDR flag and loop until end of transfer (ubNbDataToTransmit == 0) */ /* Clear ADDR flag value in ISR register */ LL_I2C_ClearFlag_ADDR(I2C1); #if (USE_TIMEOUT == 1) Timeout = I2C_SEND_TIMEOUT_TXE_MS;
#endif /* USE_TIMEOUT */ /* Loop until TXE flag is raised */ while(ubNbDataToTransmit > 0) { /* (6.1) Transmit data (TXE flag raised) **********************************/ /* Check TXE flag value in ISR register */ if(LL_I2C_IsActiveFlag_TXE(I2C1)) { /* Write data in Transmit Data register. TXE flag is cleared by writing data in TXDR register */ LL_I2C_TransmitData8(I2C1, (*pTransmitBuffer++)); ubNbDataToTransmit--; #if (USE_TIMEOUT == 1) Timeout = I2C_SEND_TIMEOUT_TXE_MS;
#endif /* USE_TIMEOUT */ } #if (USE_TIMEOUT == 1) /* Check Systick counter flag to decrement the time-out value */ if (LL_SYSTICK_IsActiveCounterFlag()) { if(Timeout-- == 0) { /* Time-out occurred. Set LED2 to blinking mode */ LED_Blinking(LED_BLINK_SLOW); } }
#endif /* USE_TIMEOUT */ } /* (7) End of transfer, Data consistency are checking into Slave process *****/ /* Generate Stop condition */ LL_I2C_GenerateStopCondition(I2C1); /* Turn LED2 On: * - Expected bytes have been sent * - Master Tx sequence completed successfully */ LED_On();
}
Code được tạo bởi CubeMx
static void MX_I2C1_Init(void)
{ /* USER CODE BEGIN I2C1_Init 0 */ /* USER CODE END I2C1_Init 0 */ LL_I2C_InitTypeDef I2C_InitStruct = {0}; LL_GPIO_InitTypeDef GPIO_InitStruct = {0}; LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_GPIOB); /**I2C1 GPIO Configuration PB6 ------> I2C1_SCL PB7 ------> I2C1_SDA */ GPIO_InitStruct.Pin = LL_GPIO_PIN_6|LL_GPIO_PIN_7; GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE; GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_HIGH; GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_OPENDRAIN; LL_GPIO_Init(GPIOB, &GPIO_InitStruct); /* Peripheral clock enable */ LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_I2C1); /* USER CODE BEGIN I2C1_Init 1 */ /* USER CODE END I2C1_Init 1 */ /** I2C Initialization */ LL_I2C_DisableOwnAddress2(I2C1); LL_I2C_DisableGeneralCall(I2C1); LL_I2C_EnableClockStretching(I2C1); I2C_InitStruct.PeripheralMode = LL_I2C_MODE_I2C; I2C_InitStruct.ClockSpeed = 100000; I2C_InitStruct.DutyCycle = LL_I2C_DUTYCYCLE_2; 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); /* USER CODE BEGIN I2C1_Init 2 */ /* USER CODE END I2C1_Init 2 */ }