GPIO là viết tắt của General Purpose Input Output là một trong những thuật ngữ phổ biến nhất mà bạn có thể đã gặp. Khi bạn bắt đầu công việc trong một hệ thống nhúng, đây là từ đầu tiên bạn phải nghe nói đến. Nhưng bạn có nghĩ rằng bạn đã nắm vững tất cả các khái niệm liên quan đến GPIO? Tín hiệu trên các chân GPIO cho phép chúng ta đạt được chức năng cuối của mình và cho phép chúng ta nói chuyện với thế giới bên ngoài. Trong bài viết này, tôi sẽ đi sâu về các khái niệm khác nhau liên quan đến GPIO. Ở cuối bài viết này, bạn sẽ có thể trả lời gpio là gì, các loại GPIO có thể được sử dụng là gì, cách cấu hình gpio để tiết kiệm điện năng, ảnh hưởng của tốc độ GPIO đến phát xạ EMI của bo mạch, khóa gpio để ngăn việc cấu hình lại ngẫu nhiên,... Là một kỹ sư phần mềm, bạn phải nắm vững các khái niệm này vì hầu hết công việc của bạn sẽ là viết mã bare metal hoặc mã driver và là một nhà phát triển ứng dụng nhúng, bạn nên biết các khái niệm này theo thứ tự để hiểu các chức năng cốt lõi được cung cấp bởi GPIO API và nếu có gì đó bị hỏng, bạn có thể nhanh chóng sửa chữa ở cấp driver.
GPIO là gì?
GPIO là một chân tín hiệu kỹ thuật số trên mạch tích hợp mà hành vi của nó (đầu vào hoặc đầu ra) được điều khiển bởi phần mềm ứng dụng. GPIO về cơ bản là một chân có thể được cấu hình làm đầu vào hoặc đầu ra. Nếu chúng ta cấu hình chân như một đầu ra, chúng ta có thể ghi 0 (LOW) hoặc 3,3 / 5 V (VDD) vào chân đó. Khi được cấu hình làm đầu vào, chúng ta có thể đọc tín hiệu trên chân đó. GPIO là giao diện tiêu chuẩn mà qua đó vi điều khiển có thể giao tiếp với thế giới bên ngoài. Nó có thể được sử dụng để đọc các giá trị từ cảm biến analog hoặc kỹ thuật số, điều khiển đèn LED, điều khiển đồng hồ cho giao tiếp I2C,...
Bản đồ bộ nhớ của ngoại vi GPIO
Như chúng ta đã biết rằng vi điều khiển hiện đại sử dụng kỹ thuật bản đồ bộ nhớ để ánh xạ tất cả các thiết bị ngoại vi trong một không gian bộ nhớ thống nhất. Vì bộ điều khiển STM32F446RE là bộ vi điều khiển dựa trên ARM Cortex M4 nên không gian bộ nhớ cho các thiết bị ngoại vi được ARM dành riêng như thể hiện trong hình:
Địa chỉ bộ nhớ trong khoảng từ 0x40000000 đến 0x600000000 có thể được nhà cung cấp vi điều khiển sử dụng để ánh xạ các thiết bị ngoại vi khác nhau của họ. Vùng này được chia thành nhiều vùng phụ, mỗi vùng được ánh xạ tới một thiết bị ngoại vi cụ thể, như thể hiện trong hình bên dưới. Từ góc độ lập trình viên, chúng ta cần tìm ra địa chỉ mà một thiết bị ngoại vi cụ thể được ánh xạ trong dải địa chỉ này. Datasheet của vi điều khiển sẽ cung cấp địa chỉ một thiết bị ngoại vi cụ thể được ánh xạ. Trong trường hợp của chúng ta, như chúng ta có thể thấy trong hình bên dưới, thiết bị ngoại vi GPIO được ánh xạ trong dải địa chỉ 0x40020000 đến 0x40021FFF. Đây cũng là vùng băng tần bit (chúng ta sẽ tìm hiểu về điều này sau).
Như chúng ta thấy, GPIO ngoại vi được chia thành GPIO A, GPIO B, GPIO C, GPIO D, GPIO E, GPIO F, GPIO G, GPIO H và mỗi cổng chứa tối đa 16 chân. Ngoại vi GPIOA được ánh xạ từ địa chỉ 0x40020000 đến 0x400203FF và nó quản lý tất cả các chân kết nối với PORT-A.
Mẫu vi xử lý ARM Cortex M-4 có bus dữ liệu rộng 32 bit, bus địa chỉ và tập thanh ghi rộng 32 bit. Trên thực tế, mỗi từ có kích thước 32-bit. Biết được bus dữ liệu, bus địa chỉ và chiều rộng thanh ghi là rất quan trọng vì nó sẽ giúp hiểu mọi thứ ở cấp độ rất thấp (cơ bản) tức là cấp độ trình điều khiển. Vì chúng ta biết rằng kích thước từ là 4 byte, do đó chúng ta có thể nói rằng mọi thanh ghi của ngoại vi GPIO dài 4 byte.
Cho đến bây giờ, chúng ta đã tìm ra địa chỉ cơ sở của các thiết bị ngoại vi GPIO. Đó là điều đầu tiên bạn sẽ làm với tư cách là một lập trình viên bất cứ khi nào bạn định lập trình bất kỳ thiết bị ngoại vi nào là tìm địa chỉ cơ sở của thiết bị ngoại vi. Bây giờ, chúng ta cần biết địa chỉ thanh ghi chính xác để lập trình các thanh ghi. Trước khi bắt đầu lập trình các thanh ghi, chúng ta phải hiểu mục đích của các thanh ghi này. Hãy đi sâu vào tập hợp thanh ghi GPIO!
Thanh ghi GPIO
Tất cả các GPIO có trong vi điều khiển được nhóm lại thành Cổng X trong đó X là A, B, C, D ...
Mỗi cổng trong STM32F446RE bao gồm 16 chân. Mỗi chân có nhiều thanh ghi khác nhau được liên kết với nó, bằng cách thay đổi nội dung của các thanh ghi, chúng ta có thể kiểm soát hành vi của một chân cụ thể.
Trong STM32F446RE, hành vi của mỗi chân có thể được kiểm soát bằng cách sử dụng:
Thanh ghi chế độ GPIO
Thanh ghi loại đầu ra GPIO
Thanh ghi tốc độ GPIO
Thanh ghi kéo lên / kéo xuống GPIO
Thanh ghi dữ liệu đầu vào GPIO
Thanh ghi dữ liệu đầu ra GPIO
Thanh ghi set / reset bit GPIO
Thanh ghi khóa cấu hình GPIO
Thanh ghi chức năng thay thế GPIO
Chúng ta sẽ xem xét các chức năng được phục vụ bởi từng thanh ghi này trong bài viết này. Hiểu chức năng của các thanh ghi này là rất quan trọng vì nó sẽ giúp bạn kiểm soát chân theo yêu cầu của bạn. Ngoài ra, nếu bạn muốn viết driver GPIO của riêng mình, bạn sẽ chủ yếu viết các hàm cốt lõi để lập trình các thanh ghi này và cung cấp API trừu tượng cho các ứng dụng người dùng sử dụng driver của bạn.
Chi tiết về thanh ghi GPIO
Thanh ghi chế độ GPIO - Thanh ghi này được sử dụng để chọn chế độ của chân cắm. Có bốn chế độ có thể được lập trình vào thanh ghi này: Chế độ đầu vào, Chế độ đầu ra mục đích chung, Chế độ chức năng thay thế và Chế độ analog. Khi phần mềm muốn đọc bất kỳ dữ liệu nào từ bên ngoài như cảm biến, nó đã định cấu hình chân cắm làm đầu vào. Mỗi chân có một bộ đệm đầu vào tương ứng mà phần mềm có thể đọc được khi chân đó đang hoạt động ở Chế độ INPUT. Chế độ Đầu ra Mục đích Chung được sử dụng khi chúng ta muốn ghi giá trị THẤP hoặc CAO vào chân. Ví dụ: nếu chúng ta kết nối một đèn LED với một chân và chúng ta muốn bật đèn LED, phần mềm sẽ cấu hình chân đó là đầu ra và ghi HIGH (VDD) vào chân. Mỗi chân có một bộ đệm đầu ra tương ứng có thể được ghi bởi phần mềm, trong trường hợp này, chúng ta đang ghi 1 vào bộ đệm đầu ra. Chế độ chức năng thay thế được sử dụng khi chúng ta muốn gán một chân cụ thể cho bất kỳ thiết bị ngoại vi nào khác. Hãy chia nhỏ ra một cách đơn giản dễ hiểu với một ví dụ đơn giản. Ví dụ: Nếu bạn muốn sử dụng giao tiếp I2C, bạn sẽ cần hai chân là SDA và SCL. Bạn cần chọn một số chân cụ thể do nhà cung cấp vi điều khiển cung cấp, có thể được sử dụng như dòng I2C SDA và SCL. Bạn có thể lấy thông tin này từ datasheet thiết bị. Trong bảng dưới đây, bạn có thể thấy rằng đối với SCL ngoại vi I2C1, bạn có thể sử dụng Cổng B Chân 6 trong Chức năng Thay thế (AF) 4.
Từ sơ đồ trên, bạn có thể thấy rằng nhà sản xuất thiết bị đã ánh xạ một số chân cụ thể nhất định sẽ được sử dụng bởi các thiết bị ngoại vi khác nhau. Do đó, trong ví dụ của chúng ta, Cổng B Chân 6 nên được cấu hình ở chế độ chức năng Thay thế để nó có thể được sử dụng bởi thiết bị ngoại vi I2C1. Nếu bạn muốn gán các chân cho thiết bị ngoại vi ADC (Analog to Digital Converter) hoặc DAC (Digital to Analog convertor), bạn nên định cấu hình chế độ là chế độ Analog.
Thanh ghi loại đầu ra GPIO - Thanh ghi này được viết bởi phần mềm để cấu hình loại đầu ra của chân. Có thể có hai loại đầu ra: Đầu ra push-pull và Đầu ra open-drain. Để hiểu sự khác biệt giữa đầu ra push-pull và đầu ra open-drain, chúng ta cần hiểu cách chân gpio được thực hiện về mặt cổng transistor. Là một kỹ sư nhúng, bạn nên hiểu rõ về sự khác biệt giữa hai cấu hình này.
Hãy tìm hiểu cách thức hoạt động của chế độ đầu vào và đầu ra ở cấp độ mạch. Hình dưới đây cho thấy cách thực hiện đơn giản của chân GPIO trong vi điều khiển.
Mỗi chân bao gồm hai bộ đệm - bộ đệm đầu vào và đầu ra cùng với một dòng enable. Khi dòng enable là 0, bộ đệm đầu ra được kích hoạt và bộ đệm đầu vào sẽ bị vô hiệu hóa. Bộ đệm đầu ra về cơ bản là hai transistor CMOS được kết nối theo kiểu bên dưới.
Khi chúng ta ghi 1 từ phần mềm, inverter đầu tiên sẽ đặt nó là 0 và mạch PMOS (T1) sẽ hoạt động (NMOS (T2) sẽ bị vô hiệu hóa) do đó chân sẽ được kéo lên VCC. Khi chúng ta ghi 0 từ phần mềm, biến tần đầu tiên sẽ đặt nó là 1 và NMOS sẽ được kích hoạt do đó chân sẽ được kéo xuống 0. Đây là cấu hình mặc định của chân GPIO và còn được gọi là đầu ra push-pull.
Nếu chúng ta đặt dòng enable là 1, thì chân sẽ được cấu hình ở chế độ đầu vào bằng cách kích hoạt bộ đệm đầu vào. Bộ đệm đầu vào bao gồm hai transistor CMOS được kết nối theo kiểu dưới đây:
Khi chân đọc 1 (CAO), inverter sẽ đảo mức logic cao này về 0 và transistor T1 PMOS sẽ BẬT. Vì nó được kéo lên VCC, phần mềm đọc logic là 1. Khi chân đọc 0 (LOW), inverter đảo mức logic thấp này thành 1 và T2 NMOS sẽ được kích hoạt và nó sẽ được kéo xuống 0, do đó phần mềm đọc 0. Dòng kích hoạt này được cấu hình bởi phần mềm.
Trong chế độ open-drain đầu ra, transistor PMOS trên cùng không có mặt. Sơ đồ trông giống như sau:
Khi T2 bật, chân sẽ được kéo xuống mức thấp (gnd). Khi T2 tắt, drain (D) của transistor sẽ nổi hoặc mở, do đó đầu ra sẽ nổi. Do đó, cấu hình open-drain chỉ có thể kéo chân xuống, không thể kéo chân lên. Vì open-drain chỉ có hai mức logic, logic 0 hoặc nổi, bạn cần cung cấp khả năng kéo lên cho chân này bằng cách kích hoạt điện trở kéo lên bên trong (có thể được thực hiện thông qua thanh ghi GPIO) hoặc đưa điện trở kéo lên bên ngoài. Trong một số thiết bị ngoại vi, GPIO được định cấu hình là open-drain, ví dụ, thiết bị ngoại vi I2C định cấu hình các chân SDA và SCL trong cấu hình open-drain.
Thanh ghi tốc độ GPIO - Tốc độ này không liên quan gì đến tần số chuyển mạch. Tốc độ nhanh hơn không có nghĩa là tốc độ chuyển đổi GPIO cao hơn (số lần một chân chuyển từ BẬT sang TẮT theo đơn vị thời gian). Tham số tốc độ này chỉ đơn giản xác định tốc độ quay của GPIO, tức là tốc độ nó có thể đi từ mức 0V đến mức VDD và ngược lại.
Làn sóng màu đỏ là đường cong chuyển đổi lý tưởng từ 0 sang 1 nhưng trong thực tế, chúng ta chỉ nhận được làn sóng màu xanh lá cây. Tăng thông số tốc độ sẽ di chuyển đường cong màu xanh lá cây sang trái sang đường màu đỏ. Lưu ý: Việc điều khiển chân ở tốc độ cao hơn cũng ảnh hưởng đến sự phát xạ EMI tổng thể của bo mạch.
Thanh ghi kéo lên / kéo xuống GPIO - Sử dụng thanh ghi này, chúng ta có thể bật / tắt điện trở kéo lên và kéo xuống của một chân nhất định.
Thanh ghi dữ liệu đầu vào GPIO - Chúng ta có thể sử dụng thanh ghi này để đọc trạng thái đầu vào (logic) trên chân. Tuy nhiên, nó chỉ có thể được đọc dưới dạng 4 byte, do đó chúng ta cần phải che tất cả các bit khác để trích xuất bit quan tâm của chúng ta.
Thanh ghi dữ liệu đầu ra GPIO - Thanh ghi này được sử dụng để thiết lập / thiết lập lại logic trên chân đầu ra. Để đẩy chân lên cao, phần mềm ghi 1 vào bit cụ thể của thanh ghi này tương ứng với chân cụ thể.
Thanh ghi set / reset bit GPIO - Thanh ghi này cho phép ứng dụng thiết lập và đặt lại từng bit riêng lẻ trong thanh ghi dữ liệu đầu ra GPIO. Sử dụng thanh ghi này để thay đổi giá trị của các bit riêng lẻ trong thanh ghi dữ liệu đầu ra là một hiệu ứng "một lần" tức là nó cung cấp một cách thực hiện xử lý theo từng bit nguyên tử.
Thanh ghi khóa cấu hình GPIO - Thanh ghi này được sử dụng để khóa cấu hình của chân port cho đến lần thiết lập lại tiếp theo. Có một trình tự cụ thể trong đó thanh ghi này cần được ghi để kích hoạt khóa.
Thanh ghi chức năng thay thế GPIO - Thanh ghi này được sử dụng để định cấu hình các chân gpio làm các chức năng thay thế, tức là các chân này có thể được sử dụng bởi các thiết bị ngoại vi khác trong bộ vi điều khiển. Tuy nhiên, một chân cụ thể chỉ có thể được liên kết với một thiết bị ngoại vi tại một thời điểm. Hầu hết các chân I / O được kết nối với các thiết bị ngoại vi trên bo mạch thông qua một bộ ghép kênh cho phép chỉ một chức năng thay thế của một thiết bị ngoại vi được kết nối với một chân I / O tại một thời điểm, đảm bảo rằng không thể có xung đột giữa các thiết bị ngoại vi chia sẻ cùng một chân I / O . Mỗi chân I / O có một bộ ghép kênh với 16 đầu vào chức năng thay thế (AF0 đến AF15) có thể được chọn bằng cách sử dụng thanh ghi chức năng thay thế GPIO. Sau khi đặt lại, tất cả I / O được kết nối với chức năng thay thế AF0 của hệ thống, đây là hoạt động mặc định. Các chức năng thay thế của thiết bị ngoại vi được ánh xạ từ AF1 đến AF13.
Vì vậy, nếu bạn muốn sử dụng một chân cụ thể làm thiết bị ngoại vi I2C1 (miễn là chân đó hỗ trợ chức năng I2C1), bạn sẽ chọn AF4 bằng cách viết thanh ghi chức năng thay thế gpio này với giá trị tương ứng.
Làm thế nào để truy cập thanh ghi GPIO trong chương trình?
Khi bạn đã xác định được địa chỉ cơ sở của thiết bị ngoại vi GPIO nhất định và hiểu các chức năng của các thanh ghi khác nhau để định cấu hình các chân, bây giờ chúng ta có thể tiếp tục và hiểu cách truy cập và lập trình các thanh ghi này. Xin lưu ý rằng mỗi port sẽ có một tập hợp tất cả 9 thanh ghi mà chúng ta đã thảo luận ở trên.
Giả sử bạn muốn lập trình thanh ghi chế độ của GPIOA. Một cách để lập trình các thanh ghi này là tìm ra địa chỉ chính xác của thanh ghi chế độ GPIOA và lấy một con trỏ đến địa chỉ thực đó, tham khảo con trỏ này, chỉnh sửa các giá trị và ghi lại vào vị trí này bằng cách sử dụng cùng một con trỏ. Đây là một cách tiếp cận dài dòng vì bạn cần tìm ra địa chỉ thực của mọi thanh ghi để đọc / ghi từ đó.
Cách tiếp cận khác đơn giản hơn là trừu tượng hóa ánh xạ ngoại vi cụ thể. Điều này được thực hiện bằng cách xác định một số bộ xử lý cho mỗi thiết bị ngoại vi. Một trình xử lý là một cấu trúc C, có các tham chiếu được sử dụng để trỏ đến các địa chỉ ngoại vi thực.
Đoạn mã trên là cấu trúc C và mỗi trường rộng 32 bit tương ứng với các thanh ghi mà chúng ta đã thấy ở trên. Nếu chúng ta trỏ cấu trúc GPIO_TypeDef đến địa chỉ cơ sở của thiết bị ngoại vi GPIOA, và vì mỗi trường này rộng 32 bit, mỗi trường có thể trỏ đến địa chỉ thanh ghi tương ứng trong bộ nhớ.
Do đó, bằng cách viết như thế này GPIOA ((GPIO_TypeDef *) GPIOA_BASE) trong đó GPIOA_BASE tương ứng với địa chỉ GPIOA thực là 0x40020000, mỗi trường bên trong cấu trúc này trỏ đến địa chỉ thanh ghi tương ứng thực tế trong bộ nhớ. Do đó, bằng cách viết GPIOA-> MODER, chúng ta có thể truy cập nội dung của thanh ghi chế độ của thiết bị ngoại vi GPIOA.
Trạng thái của GPIO ngay sau khi khởi động lại nguồn là gì?
Trong và ngay sau khi thiết lập lại bật nguồn, hầu hết các chân GPIO I / O (Đầu vào / Đầu ra) được cấu hình ở chế độ nổi đầu vào. Tuy nhiên, các chân gpio dành riêng cho mạch debug, tức là các chân debug được định cấu hình ở chế độ chức năng thay thế. Sau mỗi lần thiết lập lại thiết bị, các chân JTAG / SWD (mạch debug) này được chỉ định làm các chân chuyên dụng có thể sử dụng ngay lập tức bởi máy chủ debug. Điều này có ý nghĩa vì bạn muốn mạch debug hoạt động trong và ngay sau khi reset.
Hotline: 0979 466 469