- vừa được xem lúc

I2C trong STM32

0 0 5

Người đăng: Nguyễn Đặng Triều

Theo Viblo Asia

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 */ }

Bình luận

Bài viết tương tự

- vừa được xem lúc

Password Manager đơn giản chạy trên ESP32 🎃

Khám phá những điều mới mẻ . Hi anh em dev ,.

0 0 16

- vừa được xem lúc

Nạp code stm32 bằng ST - LINK V2

Trong bài hướng dẫn này, mình sẽ hướng dẫn các bạn sử dụng mạch nạp st-link v2 để nạp code cho stm32f103c8T6, dùng STM32CubeIDE. Bước 2: Chọn ☑️.

0 0 16

- vừa được xem lúc

Message Queue: Khám Phá Bí Mật Giao Tiếp Giữa Các Task Trong FreeRTOS

Giới thiệu nhanh. Trong phần trước, chúng ta đã tìm hiểu về Task trong FreeRTOS – những “nhân viên” trong nhà máy phần mềm, mỗi task đảm nhận một nhiệm vụ cụ thể, chạy độc lập theo lịch của Scheduler.

0 0 20

- vừa được xem lúc

Vấn đề khi gửi dữ liệu vào Queue: Dữ liệu đã nhận nhưng sao chưa thực thi?

Giới thiệu. Ở bài viết trước, mình đã nêu cho các bạn biết khái niệm Queue là gì, cách sử dụng nó ra sao và những lưu ý khi sử dụng nó.

0 0 14

- vừa được xem lúc

Tránh lỗi khi sử dụng Mutex trong RTOS – Những nguyên tắc vàng

Giới thiệu nhanh. Chào các bạn.

0 0 12

- vừa được xem lúc

Hiểu về Idle Task và Idle Hook Function trong FreeRTOS

Trong hệ điều hành thời gian thực (RTOS) như FreeRTOS, khái niệm Idle Task và Idle Hook Function đóng vai trò rất quan trọng trong việc quản lý tài nguyên vi xử lý khi không có tác vụ (task) nào cần t

0 0 11