🌱 STM32 - 13. Hướng Dẫn Cấu Hình Baudrate UART Trong STM32

🌱 STM32 - 13. Hướng Dẫn Cấu Hình Baudrate UART Trong STM32

    Ở những post trước mình đã giới thiệu về giao thức USARTcác thanh ghi được sử dụng với ngoại vi USART trong vi điều khiển STM32F401. Trong khi tìm hiểu về ngoại vi này, có hai vấn đề nổi lên mà các bạn thường thắc mắc: Thứ nhất là vấn đề tính Baudrate như thế nào? Và thứ hai là vấn đề về Parity hoạt động như thế nào? Vậy ở post này mình sẽ chia sẻ những hiểu biết của mình về vấn đề thứ nhất: USART Baudrate.

STM32F401 NUCLEO Board

Hình 1: Board STM32F401 NUCLEO với các chân GPIO

👉 USART Baudrate trong STM32

    Về cơ bản thì tốc độ Baudrate của ngoại vi USART được cấu hình bằng thanh ghi USART_BRR (cần cấu hình trước khi Enable ngoại vi bằng các bit TE/RE trong USART_CR1):

Hình 1: Thanh ghi USART_BRR

- Địa chỉ offset: 0x08
- Giá trị reset: 0x0000
- Các bit chính:

  • Bits[15:4] - DIV_Mantissa[11:0]: Thành phần nguyên của USARTDIV (phần trước dấu phẩy).
  • Bits[3:0] - DIV_Fraction[3:0]: Thành phần thập phân của USARTDIV (phần sau dấu phẩy).

    Công việc cần làm là tính toán giá trị nạp vào các bit này, bằng cách tính USARTDIV.

👉 Hai cách chọn Baudrate

    Khi thực hành với ngoại vi USART, các bạn có 2 cách để chọn Baudrate:

  1. Cách thứ nhất là tra bảng: Vi điều khiển STM32 cung cấp các bảng tính toán sẵn Baudrate trong Reference Manual (với STM32F401 là chương 19, bảng từ 74 trở đi). Các bảng này liệt kê các giá trị Baudrate thường dùng, kèm tần số Clock thông dụng và sai số.
    Ví dụ về một bảng tính toán trong STM32F401 Reference Manual:

    UART

    Hình 2: Bảng tính toán Baudrate trong Reference Manual

    Có thể thấy, tốc độ Baudrate sẽ phụ thuộc vào tần số Clock (PCLK1 hoặc PCLK2) và bit OVER8 của thanh ghi USART_CR1.

  2. Cách thứ hai là tính theo công thức: Reference Manual cung cấp công thức để tự tính Baudrate:

    UART

    Hình 3: Công thức tính Baudrate trong Reference Manual

    Baudrate = f_CK / (8 * (2 - OVER8) * USARTDIV)
                

    Trong đó:
    - f_CK: Tần số clock nguồn (PCLK1 hoặc PCLK2).
    - OVER8: Bit trong USART_CR1 (0 = oversampling 16, 1 = oversampling 8).
    - USARTDIV: Giá trị cần tính để nạp vào USART_BRR.

👉 Một số lưu ý khi tính Baudrate

  • Bit[15] - OVER8 trong USART_CR1:
    - OVER8 = 1: Hệ số chia là 8.
    - OVER8 = 0: Hệ số chia là 16 (mặc định).
  • Tần số xung clock của mỗi ngoại vi là khác nhau, trong STM32F401 có 6 ngoại vi USART:
    - USART1/6: Kết nối với bus APB2 (PCLK2).
    - USART2/3/4/5: Kết nối với bus APB1 (PCLK1).

    Hình 4: Sơ đồ kết nối clock của USART trong STM32F401

    ❓Vậy làm cách nào từ USARTDIV có thể tính ra giá trị nạp vào thanh ghi USART_BRR, cụ thể là 2 phần DIV_MantissaDIV_Fraction?

  • DIV_Mantissa: Là phần nguyên của USARTDIV.
    DIV_Mantissa = [USARTDIV]
                
    💬 Ví dụ: Nếu USARTDIV = 52,0625 thì DIV_Mantissa = 52 = 0x34.
  • DIV_Fraction: Là phần thập phân của USARTDIV, phụ thuộc vào OVER8:
    DIV_Fraction = {USARTDIV} * 8 * (2 - OVER8)
                
    - Nếu OVER8 = 0: Nhân phần thập phân với 16.
    - Nếu OVER8 = 1: Nhân phần thập phân với 8.
    💬 Ví dụ: Nếu USARTDIV = 52,0625 và OVER8 = 0 thì DIV_Fraction = 0,0625 * 16 = 1 = 0x1.

👉 Ví dụ tính toán UART Baudrate là 9600

    Ví dụ mình muốn cấu hình Baudrate là 9600, với sai số 0%. Mình sẽ tính giá trị nạp vào thanh ghi USART_BRR theo các bước sau:

  1. Tra bảng (bảng 74 trong Reference Manual): Với PCLK = 12MHz và OVER8 = 0, Baudrate 9600 có sai số 0%, nên mình chọn PCLK = 12MHz.
    ➤ Xem thêm: Cấu hình tần số 12MHz cấp cho USART
  2. Chọn OVER8 = 0 (hệ số chia là 16) từ bảng 74.
  3. Theo bảng 74, USARTDIV = 78,125. Có thể tính tay bằng công thức:

    UART

    Hình 5: Công thức tính USARTDIV trong ví dụ

    USARTDIV = f_CK / (16 * Baudrate) = 12,000,000 / (16 * 9600) = 78,125
                
  4. Tính 2 thành phần của thanh ghi USART_BRR:
    - DIV_Mantissa = [USARTDIV] = 78 = 0x04E (12 bit).
    - DIV_Fraction = {USARTDIV} * 16 = 0,125 * 16 = 2 = 0x2.
  5. Giá trị nạp vào USART_BRR = 0x04E2.

    Code hoàn chỉnh cấu hình Baudrate = 9600

  1. // Define base addresses for peripherals
  2. #define RCC_BASE 0x40023800
  3. #define USART2_BASE 0x40004400
  4. // Define RCC registers
  5. #define RCC_CR (*(volatile uint32_t *)(RCC_BASE + 0x00))
  6. #define RCC_APB1ENR (*(volatile uint32_t *)(RCC_BASE + 0x40))
  7. // Define USART2 registers
  8. #define USART2_SR (*(volatile uint32_t *)(USART2_BASE + 0x00))
  9. #define USART2_DR (*(volatile uint32_t *)(USART2_BASE + 0x04))
  10. #define USART2_BRR (*(volatile uint32_t *)(USART2_BASE + 0x08))
  11. // Define RCC bits
  12. #define RCC_APB1ENR_USART2EN (1 << 17)
  13. // Initialize USART2 with Baudrate = 9600
  14. void USART2_Init(void) {
  15. // Configure Clock for UART = 12MHz
  16. // Enable clock for USART2
  17. RCC_APB1ENR |= RCC_APB1ENR_USART2EN;
  18. // Configure Baudrate = 9600
  19. // PCLK1 = 12 MHz, OVER8 = 0 (oversampling 16)
  20. // USARTDIV = f_CK / (16 * Baudrate) = 12,000,000 / (16 * 9600) = 78.125
  21. // DIV_Mantissa = 78 (0x4E), DIV_Fraction = 2 (0x2)
  22. USART2_BRR = (78 << 4) | 2; // Load value: 0x04E2
  23. }

>>>>>> Follow ngay <<<<<<

Để nhận được những bài học miễn phí mới nhất nhé 😊
Chúc các bạn học tập tốt 😊

Nguyễn Văn Nghĩa

Mình là một người thích học hỏi và chia sẻ các kiến thức về Nhúng IOT.

Đăng nhận xét

Mới hơn Cũ hơn
//