Trong vi điều khiển, chúng ta có hai loại I/O gồm có:
- I/O đa chức năng (GPIO: General Purpose I/O): Các cổng GPIO được sử dụng để giao tiếp với các thiết bị ngoại vi thông dụng như đèn LED, công tắc, LCD, bàn phím, v.v.
- I/O chức năng đặc biệt (Special purpose I/O): Các cổng I/O này có chức năng được chỉ định cho mục đích sử dụng đặc biệt như chuyển đổi tương tự-số ADC (Analog-to-Digital), bộ định thời Timer, truyền thông nối tiếp không đồng bộ UART (Universal Asynchronous Receiver Transmitter), v.v.
Các cổng I/O có chức năng đặc biệt sẽ được trình bày trong một số bài viết khác. Trong bài viết này, chúng ta khảo sát cấu trúc của các cổng GPIO và việc ghép nối nó với các thiết bị ngoại vi đơn giản như đèn LED, phím bấm và bộ hiển thị LED 7-đoạn và chỉ ra cách truy cập chúng bằng các chương trình C.
NỘI DUNG
1. Các chân I/O trên kit FRDM-KL46Z
Trong các chip ARM của Freescale, các cổng (Port) I/O được đặt tên bằng các chữ cái A, B, C, v.v. Mỗi cổng có thể có tối đa 32 chân (Pin) và chúng được gán tên là PTA0-PTA31, PTB0-PTB31, v.v. Cần lưu ý rằng không phải tất cả 32 chân của mỗi cổng đều được thực hiện. Chip ARM được sử dụng trong bo mạch FRDM là KL46Z256VLL4 thuộc dòng Kinetis L được tích hợp năm cổng là A, B, C, D và E như chỉ ra trong Hình 1‑2. Lưu ý trong Hình 1‑2 rằng với mỗi cổng chỉ có một số chân giới hạn được triển khai. Ví dụ, đối với cổng A chỉ có các chân PTA1-PTA2, PTA4-PTA5 và PTA12-PTA17.
Hình 1 -2. Bố trí các đầu cắm mở rộng (Expand Header) trên kit FRDM-KL46Z
Mỗi chân của chip vi điều khiển ARM của Freescale có thể được sử dụng cho một số chức năng. Ví dụ, một chân cho trước có thể được sử dụng làm đầu I/O số đơn giản (GPIO), đầu vào tương tự hoặc chân I2C… như chỉ ra trong Hình 3‑2. Tất nhiên không phải tất cả các chức năng này được dùng cùng một lúc mà chúng ta phải đảm bảo rằng một chân được gán chỉ một chức năng ngoại vi tại một thời điểm. Chúng ta chọn một chức năng cho một chân bằng cách lập trình một thanh ghi chức năng đặc biệt (SFR: Special Function Register) của vi điều khiển. Kỹ thuật sử dụng một chân đơn cho nhiều chức năng được gọi là hợp kênh chân (pin multiplexing) và được sử dụng rộng rãi trong các bộ vi điều khiển. Điều này là bởi vì nếu không sử dụng hợp kênh chân thì một vi điều khiển có thể cần đến vài trăm chân để hỗ trợ tất cả các tính năng trên chip của nó.
Thanh ghi chức năng đặc biệt PORTx_PCRn (Portx Pin Control Register) (Hình 3‑1) cho phép chúng ta lập trình một chân được sử dụng cho một chức năng nhất định. Cần lưu ý rằng mỗi chân của các cổng A-E có một thanh ghi PORTx_PCRn riêng, trong đó x thay thế cho một trong số các cổng A-E và n được sử dụng cho chân số 0 đến 31. Như đã được đề cập trước đó, mỗi cổng của A-E có thể có tối đa 32 chân và không phải tất cả các chân cho một cổng nhất định đều được thực hiện. Các bit quan trọng nhất của thanh ghi PORTx_PCRn là D10-D8 được dùng làm các bit điều khiển chức năng hợp kênh chân (Mux bits) như chỉ ra trong Hình 3‑2. Sau khi reset, tất cả các cổng từ A đến E bị vô hiệu hóa. Để sử dụng một chân làm đầu GPIO số, chúng ta phải đặt các bit MUX = 001.
Hình 3‑1: Các trường điều khiển của thanh ghi PORTx_PCRn (Chapter 11 của [14]).
Hình 3‑2. Hợp kênh nhiều chức năng vào một chân trên KL46Z256-MCU.
Với thanh ghi PORTx_PCRn, chúng ta không chỉ chọn chức năng I/O cho một chân nhất định mà còn có thể điều khiển cưởng độ tải (Drive Strength) và điện trở kéo lên (Pull-up) hoặc kéo xuống (Pull-down) bên trong của chân. Hình 3‑1 và Bảng 3‑1 miêu tả các bit của thanh ghi PORTx_PCRn và chức năng của chúng. Bit #1 (PE, Pull enable) của PORTx_PCRn được sử dụng để bật tùy chọn điện trở kéo bên trong. Nếu PE = 1, thì chúng ta sử dụng bit #0 (PS, Pull Select) để bật tùy chọn điện trở kéo lên hoặc điện trở kéo xuống. Chúng ta cũng có thể kiểm soát khả năng tải (fan-out và fan-in. Xem Phụ lục A) của một chân I/O số với bit #6 (DSE, Drive Strength Enable). Các tùy chọn này được sử dụng phổ biến khi kết nối chân với công tắc hoặc đèn LED. Trong các chương sau, chúng ta sẽ xem cách sử dụng các bit PORTx_PCRn để chọn các chức năng chân khác khi đề cập đến các thiết bị ngoại vi onchip của chip KL46Z.
Bảng 3‑1. Miêu tả các các trường điều khiển của thanh ghi PORTx_PCRn
Bit | Trường | Miêu tả |
0 | PS (Pull Select) | Nếu trường PE được đặt thì trường này được sử dụng để chọn giữa điện trở treo cao (pull-up resistor) và điện trở kéo xuống (pull-down resistor)
0: pull-down resistor, 1: pull-up resistor |
1 | PE (Pull Enable) | Cho phép điện trở kéo
0: cấm điện sử dụng treo bên trong 1: cho phép sử dụng điện trở treo bên trong |
2 | SRE (Slew Rate Enable) | Cho phép tốc độ quay
0: Tốc độ quay nhanh 1: Tốc độ quay chậm |
4 | PFE (Passive Filter Enable) | Cho phép bộ lọc thụ động
0: Cấm bộ lọc thụ động lối vào 1: Cho phép bộ lọc thụ động lối vào |
6 | DSE (Drive Strength Enable) | Cho phép chọn cưởng độ tải
0: Chọn cường độ tải yếu khi chân được cấu hình là đầu ra 1: Chọn cường độ tải mạnh khi chân được cấu hình là đầu ra |
10-8 | MUX (Pin Mux Control) | Điều khiển chức năng hợp kênh chân
000: chân bị cấm (mạch analog được chọn) 001: Chức năng 1 (GPIO) 010 Chức năng 2 (phụ thuộc vào chip) 011 Chức năng 3 (phụ thuộc vào chip) 100 Chức năng 4 (phụ thuộc vào chip) 101 Chức năng 5 (phụ thuộc vào chip) 110 Chức năng 6 (phụ thuộc vào chip) 111 Chức năng 7 (phụ thuộc vào chip) |
19-16 | IRQC (Interrupt Configuration) | Cấu hình ngắt chỉ dùng cho các chân được thiết lập làm đầu vào số.
0000: Yêu cầu ngắt hoặc DMA bị cấm 0001: Yêu cầu DMA trên sườn tăng 0010: Yêu cầu DMA trên sườn giảm 0011: Yêu cầu DMA trên hai sườn 1000: Ngắt ở mức logic 0 1001: Ngắt ở sườn tăng 1010: Ngắt ở sườn giảm 1011: Ngắt ở cả hai sường 1100: Ngắt ở mức logic 1 Các tổ hợp còn lại: Chưa dùng |
24 | ISF (Interrupt Status Flag) | Cờ trạng thái ngắt
0: Không có ngắt 1: Có ngắt |
2. Mạch cấp clock cho các cổng I/O
Thanh ghi điều khiển cấp xung nhịp hệ thống SIM_SCGC5 (System Clock Gating Control Register 5) được sử dụng để cho phép nguồn xung nhịp được kết nối tới một mạch cổng I/O. Nếu cổng I/O không được sử dụng, nguồn xung nhịp cấp đến cổng có thể bị ngắt để tiết kiệm năng lượng. Chỉ có duy nhất một thanh ghi chức năng đặc biệt SIM_SCGC5 cho tất cả các cổng GPIO và một số bit của thanh ghi này được sử dụng để cho phép cấp nguồn xung nhịp đến các cổng A đến E. Trong trường hợp chip Freescale KL46Z256VLL4, vì chỉ có các cổng từ A đến E, nhiều bit của thanh ghi này không được sử dụng hoặc sử dụng cho các chức năng khác. Chi tiết về chức năng của thanh ghi này có thể tham khảo từ chương 12 của tài liệu tham khảo [14]. Các bit của thanh ghi này cũng được hiển thị trong Hình 3‑3.
Ký hiệu | Định dạng | Địa chỉ |
SIM_SCGC5
SIM→SCGC5 |
Note: 0: clock disabled; 1: Clocl enabled |
0x4004_8038 + 0x1038
= 0x4004_8038 |
Hình 3‑3. Thanh ghi SIM_SCGC5 (System Clock Gating Control Register 5).
Trong mô-đun SIM thanh ghi SIM_SCGC5 có địa chỉ offset là 0x1038. Biết địa chỉ cơ sở của mô-đun SIM là 0x4004_7000, do đó địa vật lý của thanh ghi SIM_SCGC5 sẽ là 0x4004_8038. Đây là một thanh ghi rất quan trọng. Không có tín hiệu xung nhịp, cổng sẽ không hoạt động. Mọi quyền truy cập vào các thanh ghi được liên kết với cổng trước khi tín hiệu xung nhịp được cấp sẽ dẫn đến lỗi phần cứng và chương trình gặp sự cố.
Ví dụ 3‑1 |
Hãy chỉ ra cách để:
a) Cấp tín hiệu xung nhịp tới cổng PTBb) Chọn chức năng GPIO cho các chân PTB18 và PTB19 |
Đáp án:
a) Để cho phép cấp tín hiệu xung nhịp tới cổng PTB, chúng ta cần đặt bit D10 của thanh ghi SIM_SCGC5 ở địa chỉ 0x4004_8038 lên ‘1’. Chúng ta có thể thực hiện điều này bằng cách OR thanh ghi SIM_SCGC5 với giá trị 0x400 để đảm bảo không ảnh hưởng tới các bit còn lại. b) Để chọn chức năng GPIO cho chân PTB18 và PTB19 chúng ta cần phải ghi giá trị 0x0100 tới các thanh ghi PORTB_PCR18 và PORT_PCR19. Địa chỉ của các thanh ghi này là 0x4004_A048 và 0x4004_A04C (tham khảo chương 11 của [14]). |
3. Khối GPIO
3.1. Địa chỉ của các khối GPIO
Chi tiết về mô-đun GPIO được trình bày chi tiết trong chương 42 của [14].
Các chip ARM có hai bus: Bus ngoại vi nâng cao APB (viết tắt cửa cụm từ tiếng Anh Advanced Peripheral Bus) và Bus hiệu suất cao nâng cao AHB (Advanced High-Performance Bus). Bus AHB nhanh hơn nhiều so với APB. AHB cho phép truy cập tới các thiết bị ngoại vi trong một chu kỳ xung nhịp. Bus APB chậm hơn và thời gian truy cập của nó tối thiểu là 2 chu kỳ xung nhịp.
Các cổng I/O được ánh xạ tới không gian địa chỉ của giao diện bus APB và AHB như trong Bảng 3‑2. Có nhiều thanh ghi được liên kết với mỗi cổng I/O ở trên và chúng được gán các địa chỉ xác định trong bản đồ bộ nhớ của hệ thống. Lưu ý các địa chỉ trong Bảng 3‑2 là các địa chỉ Cơ sở (Base addresses) có nghĩa là trong địa chỉ cơ sở đó có nhiều thanh ghi được liên kết với cổng đó như chỉ ra trong Hình 3‑4.
Bảng 3‑2. Địa chỉ cơ sở của các cổng I/O trên bus AHB và APB
Cổng GPIO | Bus APB | Bus AHB |
GPIO Port A | 0x400F F000 | 0xF80F F000 |
GPIO Port B | 0x400F F040 | 0xF80F F040 |
GPIO Port C | 0x400F F080 | 0xF80F F080 |
GPIO Port D | 0x400F F0C0 | 0xF80F F00C0 |
GPIO Port E | 0x400F F100 | 0xF80F F100 |
Hình 3‑4. Ánh xạ các thanh ghi của các cổng GPIO trong không gian bộ nhớ.
3.2. Các thanh ghi bên trong mỗi cổng GPIO
Bảng 3‑3 cho thấy một số thanh ghi liên quan đến PORTA. Sau khi chúng ta cấu hình thanh ghi hướng dữ liệu GPIOA_PDDR để quy định cổng làm đầu ra, chúng ta có thể sử dụng các thanh ghi GPIOA_PDOR, GPIOA_PSOR, GPIOA_PCOR và GPIOA_PTOR theo thứ tự để xuất dữ liệu ra cổng, đặt (gán giá trị 1) tới cổng, xóa (gán giá trị 0) tới cổng và đảo giá trị hiện tại của cổng. Tương tự, sau khi thanh ghi hướng dữ liệu GPIOA_PDDR được cấu hình để quy định cổng làm đầu vào, thanh ghi GPIOA_PDIR được sử dụng để nhập dữ liệu vào CPU từ các chân. Cần lưu ý rằng các thanh ghi này tồn tại trong tất cả các cổng từ A đến E trong chip Freescale ARM.
Bảng 3‑3. Các thanh ghi GPIO trong cổng PORTA
Địa chỉ | Ký hiệu | Tên thanh ghi | Loại đọc/viết | Giá trị sau Reset |
0x400F F000 | GPIOA_PDOR | Port Data Output Register | Đọc/Viết | 0x00000000 |
0x400F F004 | GPIOA_PSOR | Port Set Output register | Viết (luôn đọc được giá trị 0) | 0x00000000 |
0x400F F008 | GPIOA_PCOR | Port Clear Output Register | Viết (luôn đọc được giá trị 0) | 0x00000000 |
0x400F F00C | GPIOA_PTOR | Port Toggle Output Register | Viết (luôn đọc được giá trị 0) | 0x00000000 |
0x400F F010 | GPIOA_PDIR | Port Data Input Register | Đọc | 0x00000000 |
0x400F F014 | GPIOA_PDDR | Port Data Direction Register | Đọc/Viết | 0x00000000 |
Nói chung mỗi vi điều khiển có tối thiểu hai loại thanh ghi được liên kết với mỗi cổng I/O, bao gồm các thanh ghi dữ liệu và thanh ghi hướng dữ liệu như chỉ ra trong Hình 3‑5. Thanh ghi hướng dữ liệu được sử dụng để xác định một chân là đầu vào hoặc đầu ra. Trong họ vi điều khiển Kinetis của Freescale, mỗi cổng GPIO có một thanh ghi hướng dữ liệu 32 ký hiệu là GPIOx_PDDR (Port Data Direction Register). Sau khi thanh ghi hướng vào/ra đã được cấu hình đúng thì chúng ta sử dụng các thanh ghi dữ liệu để ghi dữ liệu vào chân hoặc đọc dữ liệu từ chân. Các thanh ghi dữ liệu lại được chia làm 2 loại là thanh ghi dùng để xuất dữ liệu và thanh ghi để đọc dữ liệu. Trong trường hợp vi điều khiển Kinetis của Freescale, mỗi cổng GPIO có bốn thanh ghi 32 bit được dùng để điều khiển việc xuất dữ liệu ra một chân là GPIOx_PDOR (Port Data Output Register), GPIOx_PSOR (Port Set Output Register), GPIOx_PCOR (Port Clear Output Register), GPIOx_PTOR (Port Toggle Output Register). Việc viết tới những thanh ghi này chỉ tác động tới chân tương ứng với các bit được viết giá trị tới. Điều này giúp dễ dàng bật hoặc tắt một hoặc một vài chân mà không ảnh hưởng đến các chân khác. Ví dụ, viết giá trị 4 (có giá trị nhị phân là 0b0100) vào thanh ghi PCOR sẽ xóa mức logic trên chân số 2 của cổng đó về 0 mà không sửa đổi bất kỳ chân nào khác. Ở chiều ngược lại, vi điều khiển dòng Kinetis của Freescale chỉ có một thanh ghi cho nhập dữ liệu từ chân vào trong vi điều khiển ký hiệu là GPIOx_PDIR (Port Data Input Register).
Hình 3‑5. Các thanh ghi dữ iệu và thanh ghi hướng dữ liệu trong cấu trúc một chân I/O.
a) Thanh ghi hướng dữ liệu PDDR (Port Data Direction Register)
Trong trường hợp chip ARM Freescale, mỗi bit của thanh ghi hướng dữ liệu cần phải gán giá trị 0 để định cấu hình chân cổng làm đầu vào và giá trị 1 để định cấu hình chân cổng làm đầu ra. Ví dụ, viết giá trị 0x03 (hoặc giá trị nhị phân 0b00000011) vào thanh ghi GPIOA_PDDR dẫn đến các chân 0 và 1 của cổng PORTA trở thành đầu ra dữ liệu trong khi các chân khác trở thành đầu vào dữ liệu. Thanh ghi hướng dữ liệu được đặt tại địa chỉ offset 0x0014 từ địa chỉ cơ sở của cổng đó. Định dạng của thanh ghi này được mô tả trong Hình 3‑6.
Ký hiệu | Định dạng | Địa chỉ |
GPIOx_PDDR
GPIOx→PDDR |
Chú ý: 0: chân được cấu hình làm đầu vào; 1: chân được cấu hình làm đầu ra |
Base address + 0x0014 offset |
Hình 3‑6. Thanh ghi GPIOx_PDDR.
b) Thanh ghi xuất dữ liệu GPIO_PDOR (Port Data Output Register)
Khi mô-đun GPIO được cấu hình làm đầu ra dữ liệu thì thanh ghi GPIO_PDOR được dùng để đệm dữ liệu mà vi điều khiển muốn xuất ra bên ngoài. Thanh ghi xuất dữ liệu GPIO_PDOR có độ dịch địa chỉ là 0x0000 so với địa chỉ cơ sở của cổng.
Ký hiệu | Định dạng | Địa chỉ |
GPIOx_PDOR
GPIOx→PDOR |
Chú ý: 0: xuất mức logic 0 ra chân; 1: xuất mức logic 1 ra chân |
Base address + 0x0000 offset |
Hình 3‑7. Thanh ghi GPIOx_PDOR (Port Data Output Register).
c) Thanh ghi đặt dữ liệu lối ra GPIOx_PSOR (Port Set Output Register)
Khi mô-đun GPIO được cấu hình làm đầu ra dữ liệu thì thanh ghi GPIO_PSOR được dùng để vi điều khiển đặt mức logic của một chân lên 1. Thanh ghi GPIO_PSOR có độ dịch địa chỉ là 0x0004 so với địa chỉ cơ sở của cổng.
Ký hiệu | Định dạng | Địa chỉ |
GPIOx_PSOR
GPIOx→PSOR |
Chú ý: 0: mức logic trên chân không thay đổi; 1: mức logic trên chân được đặt bằng 1 |
Base address + 0x0004 offset |
Hình 3‑8. Thanh ghi GPIOx_PSOR (Port Set Output Register).
d) Thanh ghi xóa dữ liệu lối ra GPIOx_PCOR (Port Clear Output Register)
Khi mô-đun GPIO được cấu hình làm đầu ra dữ liệu thì thanh ghi GPIO_PCOR được dùng để vi điều khiển xóa mức logic của một chân xuống 0. Thanh ghi GPIO_PCOR có độ dịch địa chỉ là 0x0008 so với địa chỉ cơ sở của cổng.
Ký hiệu | Định dạng | Địa chỉ |
GPIOx_PCOR
GPIOx→PCOR |
Chú ý: 0: mức logic trên chân không thay đổi; 1: mức logic trên chân được xóa về 0 |
Base address + 0x0008 offset |
Hình 3‑9. Thanh ghi GPIOx_PCOR (Port Clear Output Register).
e) Thanh ghi đảo trạng thái dữ liệu lối ra GPIOx_PTOR (Port Toggle Output Register)
Khi mô-đun GPIO được cấu hình làm đầu ra dữ liệu thì thanh ghi GPIO_PCOR được dùng để vi điều khiển đặt mức logic của một chân tới trạng thái đảo của mức logic hiện tại trên chân. Thanh ghi GPIO_PTOR có độ dịch địa chỉ là 0x000C so với địa chỉ cơ sở của cổng.
Ký hiệu | Định dạng | Địa chỉ |
GPIOx_PTOR
GPIOx→PTOR |
Chú ý: 0: mức logic trên chân không thay đổi; 1: mức logic trên chân được đặt tới trạng thái đảo của mức logic hiện tại |
Base address + 0x000C offset |
Hình 3‑10. Thanh ghi GPIOx_PTOR (Port Toggle Output Register).
f) Thanh ghi đọc dữ liệu lối vào GPIOx_PDIR (Port Data Input Register)
Khi mô-đun GPIO được cấu hình làm đầu vào dữ liệu thì thanh ghi GPIO_PDIR được dùng để vi điều khiển đọc mức logic của một chân. Thanh ghi GPIO_PDIR có độ dịch địa chỉ là 0x0010 so với địa chỉ cơ sở của cổng.
Ký hiệu | Định dạng | Địa chỉ |
GPIOx_PTOR
GPIOx→PTOR |
Chú ý: 0: mức logic đọc được từ chân là 0; 1: mức logic đọc được từ chân là 1 |
Base address + 0x0010 offset |
Hình 3‑11. Thanh ghi GPIOx_PDIR (Port Data Input Register).
Ví dụ 3‑2 |
Tìm địa chỉ vật lý của các thanh ghi GPIOA_PDOR và GPIOA_PDDR nếu địa chỉ cơ sở của GPIO cổng PORTA là 0x400F_F000. |
Đáp án:
Địa chỉ vật lý của thanh ghi GPIOA_PDOR là 0x400F_F000 + 0x0000 = 0x400F_F000. Địa chỉ vật lý của thanh ghi GPIOA_PDDR là 0x400F_F000 + 0x0014 = 0x400F_F014 |
Pingback: FRDM-KL46Z #6: Lập trình ghép nối cổng GPIO với đèn LED - SMART ELECTRONICs