Bao Cao Do An Tot Nghiep

You might also like

Download as doc, pdf, or txt
Download as doc, pdf, or txt
You are on page 1of 178

BỘ GIÁO DỤC VÀ ĐÀO TẠO

TRƯỜNG ĐẠI HỌC SƯ PHẠM KỸ THUẬT TP. HCM

KHOA ĐIỆN-ĐIỆN TỬ

ĐỒ ÁN TỐT NGHIỆP


Đề Tài:

THIẾT KẾ KITS NHÚNG VÀ


VÀ LẬP TRÌNH NHÚNG

Chuyên ngành Công Nghệ Kỹ Thuật Máy Tính


Hệ Đại Học Chính Quy

Tp. Hồ Chí Minh - Tháng 6/2010


Trang 1
TRƯỜNG ĐẠI HỌC SƯ PHẠM KỸ THUẬT CỘNG HÒA XÃ HỘI CHỦ NGHĨA VIỆT
NAM
TP.HỒ CHÍ MINH
Độc lập- Tự do – Hạnh phúc
KHOA ĐIỆN – ĐIỆN TƯ

Tp.HCM, ngày ….tháng….năm 2010

NHIỆM VỤ ĐỒ ÁN TỐT nghiệp


Họ tên sinh viên : 1. Đào Thanh Mai MSSV :06119058

2. MSSV :

Chuyên Ngành : Công Nghệ Kỹ Thuật Máy Tính Mã Ngành :

Hệ đào tạo : Đại học chính quy Mã hệ :

Khóa : 2006 Lớp :061190B

I. TÊN ĐỀ TÀI

THIẾT KẾ KITS NHÚNG VÀ LẬP TRÌNH NHÚNG


II. NHIỆM VỤ VÀ NỘI DUNG

.........................................................................................................................................

.........................................................................................................................................

.........................................................................................................................................

.........................................................................................................................................

.........................................................................................................................................

.........................................................................................................................................

.........................................................................................................................................

.........................................................................................................................................

III.NGÀY GIAO NHIỆM VỤ .....................................................................................

IV NGÀY HOÀN THÀNH NHIỆM VỤ.....................................................................

V. GIÁO VIÊN HƯỚNG DẪN : Thầy TRƯƠNG NGỌC SƠN

Trang 2
GIÁO VIÊN HƯỜNG DẪN

LỜI MỞ ĐẦU
_________________________________________________________________________

.............................................................................................................................................

.............................................................................................................................................

.............................................................................................................................................

.............................................................................................................................................

.............................................................................................................................................

.............................................................................................................................................

.............................................................................................................................................

.............................................................................................................................................

.............................................................................................................................................

.............................................................................................................................................

.............................................................................................................................................

.............................................................................................................................................

.............................................................................................................................................

.............................................................................................................................................

.............................................................................................................................................

.............................................................................................................................................

.............................................................................................................................................

.............................................................................................................................................

.............................................................................................................................................

Trang 3
.............................................................................................................................................

.............................................................................................................................................

LỜI CẢM ƠN
_________________________________________________________________________

.............................................................................................................................................

.............................................................................................................................................

.............................................................................................................................................

.............................................................................................................................................

.............................................................................................................................................

.............................................................................................................................................

.............................................................................................................................................

.............................................................................................................................................

.............................................................................................................................................

.............................................................................................................................................

.............................................................................................................................................

.............................................................................................................................................

.............................................................................................................................................

.............................................................................................................................................

.............................................................................................................................................

.............................................................................................................................................

.............................................................................................................................................

.............................................................................................................................................

Trang 4
.............................................................................................................................................

.............................................................................................................................................

.............................................................................................................................................

NHẬN XÉT GIÁO VIÊN PHẢN BIỆN


_________________________________________________________________________

.............................................................................................................................................

.............................................................................................................................................

.............................................................................................................................................

.............................................................................................................................................

.............................................................................................................................................

.............................................................................................................................................

.............................................................................................................................................

.............................................................................................................................................

.............................................................................................................................................

.............................................................................................................................................

.............................................................................................................................................

.............................................................................................................................................

.............................................................................................................................................

.............................................................................................................................................

.............................................................................................................................................

.............................................................................................................................................

.............................................................................................................................................

.............................................................................................................................................
Trang 5
.............................................................................................................................................

.............................................................................................................................................

.............................................................................................................................................

NHẬN XÉT GIÁO VIÊN HƯỚNG DẪN


.............................................................................................................................................

.............................................................................................................................................

.............................................................................................................................................

.............................................................................................................................................

.............................................................................................................................................

.............................................................................................................................................

.............................................................................................................................................

.............................................................................................................................................

.............................................................................................................................................

.............................................................................................................................................

.............................................................................................................................................

.............................................................................................................................................

.............................................................................................................................................

.............................................................................................................................................

.............................................................................................................................................

.............................................................................................................................................

.............................................................................................................................................

.............................................................................................................................................
Trang 6
.............................................................................................................................................

.............................................................................................................................................

.............................................................................................................................................

MỤC LỤC

Nhiệm vụ đồ án

Nhận xét của giáo viên phản biện

Nhận xét của giáo viên hướng dẫn

Lời nói đầu

Lời cảm ơn

Mục lục.

Liệt kê các từ viết tắt

PHẦN MỞ ĐẦU

1. Tóm tắt đề tài

2. Lý do chọn đề tài

3. Mục đích nghiên cứu

4. Đối tượng và phạm vi nghiên cứu

5. Ý nghĩa khoa học và thực tiễn đề tài

PHẦN I : THIẾT KẾ KITS ARM

PHẦN II : LẬP TRÌNH NHÚNG

PHẦN III : VIẾT ỨNG DỤNG


Trang 7
Trang 8
PHẦN MỞ ĐẦU

I. Lời Nói Đầu


Thế kỷ 21 là thế kỷ của những công nghệ mới, trong đó có công nghệ số hiện đại. Ngày nay
chúng ta có thể bắt gặp các sản phẩm áp dụng kỹ thuật số hầu như khắp mọi ngõ ngách của
cuộc sống từ nhũng thiết bị đơn giản đến phức tạp. Sự phổ dụng như vậy là do các tính năng
do kỹ thuật số đem lại. Trái tim hay trung tâm của các sản phẩm kỹ thuật số này là các bộ xử
lý (processors).

Trước kia các hệ thống số 4, 8 hay 16 bit đã được sử dụng rất rộng rãi. Tuy nhiên hiện nay
đang chứng kiến sự dịch chuyển mạnh mẽ sang các thiết kế 32 bit do những ưu điểm của
thiết kế 32 bit đáp ứng được các yêu cầu ngày càng cao của thị trường (các sản phẩm cao
cấp với nhiều tính năng phức tạp, giao diện bắt mắt và thân thiện, giá thành phải chăng, công
suất tiêu thụ thấp).

Trong các thiết kế 32 bit hiện hành, thiết kế 32 bit dựa trên kiến trúc ARM đang và sẽ phát
triển rất mạnh mẽ, chiếm ưu thế do các ưu điểm vượt trội mà nó mang lại so với các đối thủ
cạnh tranh khác như:

Cung cấp giải pháp trọn gói cho thiết kế SoC (System On Chip) bao gồm các bộ xử lý
32 bit dựa trên tập lệnh RISC cao cấp, các hệ thống bus tốc độ cao tiên tiến, tổ chức bộ nhớ
thông minh, các IPs (Interlectual Property) và các công cụ phát triển tốt nhất. Nhờ đó mà
các giải pháp thiết kế 32 bit do ARM cung cấp đem lại khả năng tích hợp hệ thống cao nhất
(hight speed and small die size).

Đem đến chất lượng cao mà giá cả phải chăng thông qua một loạt các giải pháp
như: tối ưu chất lượng/dung lượng mã, công nghệ Thumb-2, ….. Hiện nay các thiết kế vi xử
lý dựa trên kiến trúc ARM đem lại công suất tiêu thụ thấp nhất, một đặc điểm rất quan trọng
đối vói các sản phẩm số hiện đại.

ARM cung cấp các công cụ hỗ trợ phát triển cả cứng (Prime Cells) lẫn mềm (ví dụ OS
và Middle ware) tốt và rộng nhất cho các kiến trúc ARM 32 bit.
Trang 9
Kiến trúc ARM đem lại cho người dùng sự lựa chọn rộng rãi nhất về hỗ trợ phát triển
ứng dụng dựa trên hệ điều hành (OS) như: hỗ trợ Windows Mobile, Windows Embedded CE,
Symbian OS, Embedded Linux, FreeRTOS, ….

Với hơn 5 tỷ bộ xử lý đã được bán ra và được sử dụng thành công trong rất nhiều sản
phẩm cao cấp (Advanced high end products), các giải pháp về OS của ARM đã chiếm đươc
sự tin cậy của các nhà phát triển sản phẩm.

Không bằng lòng với những gì đã và đang đạt đươc, ARM cam kết cộng tác chặt chẽ
với các công ty phát triển hệ điều hành nhằm đáp ứng yêu cầu càng cao của thị trường.

Rút ngắn đáng kể thời gian từ lúc phát triển đến lúc sản phẩm được đưa ra thi
trường nhờ sự hỗ trợ rộng rãi và mạnh mẽ của các công cụ hỗ trợ tốt và tin cậy do ARM và
cộng đồng ARM đem lại. Chẳng hạn như việc cung cấp các IPs có khả năng sử dụng lại, các
platform mẫu, ….. cũng như công cụ phát triển phần mềm RV MDK (RealView
Microcontroller Development Kit), RVDS (RealView Development Suit), RealView ICE, ...
Trong đó nổi bật là hai công cụ phát triển chuyên nghiệp RVDS Pro (tích hợp tính năng
Profilers và RTSM -Real Time System Model) và RealView ICE do ARM cung cấp nhằm đem
lại tính ưu việt của các sản phẩm so với các đối thủ cạnh tranh như: độ tin cậy và bền vững,
tỷ giá chất lượng/giá thành cao, tương thích với phát triển tương lai, … Chính nhờ các công
nghệ và công cụ phát triển tin cậy, chất lượng cao như vậy mà ARM đã rất thành công trong
việc giúp việc biến các ý tưởng thành các sản phẩm được người tiêu dùng và thị trường
đánh giá rất cao. Sự tin cậy và chất lượng cao thể hiện rõ nhất ở lượng hàng tỷ chip xử lý
được bán ra và con số này không ngừng tăng lên.

Các giải pháp thiết kế dựa trên kiến trúc ARM 32 bit mà ARM cung cấp đã đưa đến
các hệ EcoSystems.

ARM cam kết đầu tư không ngừng vào R&D nhằm cung cấp và đáp ứng ngày càng tốt
hơn các yêu cầu của thị trường và nắm bắt được các xu thế tương lai. Điều đó được minh
chứng qua các thành công của ARM trong việc phát triển các công nghệ tiên tiến IPs, Neon,
Multi media, TrustZone, VFP, Thumb-2, Java Jazelle …

Công nghệ bảo mật hàng đầu thế giới (Công nghệ TrustZone)

Hiện nay ARM cung cấp rất nhiều dòng xử lý (ARM7, ARM9, Cortex …..) nhằm đáp ứng
các giải pháp khác nhau: thiết bị gia dụng (TV, tủ lạnh, …), giải pháp về thiết bị di động
(điện thoại di động thông minh, gaming, camera,….), giải pháp nhúng (ô tô, máy bay, hệ
thống đo và điều khiển tự động công nghiệp …) … Chẳng hạn dòng ARM A-profile hướng
đến các ứng dụng đòi hỏi tính năng cao, dòng ARM R-profile hướng đến các hệ Real time,
còn dòng ARM M-profile hướng đến các ứng dụng nhúng.

ARM hiện nay là kiến trúc vi xử lý được hỗ trợ rộng rãi và tốt nhất thông qua ARM, các đối
tác và cộng đồng ARM (Microsfoft, Linux, Apple ….).

* Hiện nay công nghệ ARM được sử dụng trên 90% các máy điện thoại di động

Trang 10
* Hơn 90% điện thoại di động sử dụng ít nhất một chíp ARM

* 9 triệu ARM chip được xuất xưởng hàng ngày

* Gấp 10 lần PC

* Dự đoán 5 tỷ lõi ARM được sản xuất chỉ trong năm 2011

* ARM phát triển rất nhanh, không những chỉ trong lĩnh vực điện thoại di động

* MCU (vi điều khiển): đóng góp thứ hai chỉ sau các thiết bị di động không dây và đạt
tốc độ phát triển rất cao.

* ARM là nhà cung cấp hàng đầu các vi xử lý dựa trên kiến trúc RISC 32 bit

* Chiếm 75% thị trường

* ARM MCUs tăng tốc 2.4x năm

* Triển vọng đến năm 2018: Vi xử lý ARM thống lĩnh thị trường MCU (60% - 70%)

* Kiến trúc tiêu chuẩn thực tế (De-facto standard architecture) cho các ứng dụng và thiết
bị nhúng.

Chính vì vậy mà ngày càng có nhiều người dùng đã và đang chuyển sang kiến trúc ARM 32
bit. Nhờ công nghệ vượt trội mà ARM đem lại cùng với sự hỗ trợ chu đáo từ ARM cũng như
cộng đồng ARM đem lại (processors, physical IP, SoC designs, Application-specific
standard products -ASSPs, related software and development tools), người dùng có thể tìm
thấy mọi thứ họ cần để phát triển thành công các sản phẩm, đặc biệt là những sản phẩm đem
lại sự khác biệt mà truớc đây không thể có được. Và ARM đã trở thành sự lựa chọn tin cậy
của rất nhiều người dùng ngay từ đầu.

Để thuận lợi cho việc phát triển các sản phẩm dựa trên kiến trúc ARM, ARM cung cấp cho
người dùng các bo mạch phát triển khác nhau, đáp ứng các đối tượng khác nhau.

Trang 11
PHẦN I

Trang 12
CHƯƠNG I
HỆ THỐNG NHÚNG
I Hệ thống nhúng - Embedded system

1. Định nghĩa hệ thống nhúng:

Trang 13
- Hệ thống nhúng (HTN) là hệ thống có khả năng tự trị được nhúng vào trong 1 môi
trường hay 1 hệ thống mẹ. Đó là các hệ thống tích hợp cả phần cứng và phần mềm
phục vụ các bài toán chuyên dụng trong nhiều lĩnh vực công nghiệp, tự động hoá điều
khiển, quan trắc và truyền tin. Hệ thống điều khiển nhúng lấy thông tin từ các cảm
biến, xử lý tính toán các thuật điều khiển và phát tín hiệu điều khiển cho các cơ cấu
chấp hành. Khác với các hệ thống điều khiển cổ điển theo nguyên lý thuỷ lực, khí nén,
rơ le, mạch tương tự, hệ điều khiển nhúng là hệ thống điều khiển số được hình thành
từ những năm 1960 đến nay. Trước đây các hệ điều khiển số thường do các máy tính
lớn đảm nhiệm, ngày nay chức năng điều khiển số này do các chip vi xử lý, các hệ
nhúng đã thay thế. Phần mềm điều khiển ngày càng tinh sảo tạo nên độ thông minh
của thiết bị và ngày càng chiếm tỷ trọng lớn trong giá thành của thiết bị.
- Như vậy không phải tất cả các sản phẩm đo lường và điều khiển đều là các hệ nhúng.
Hiện nay chúng ta còn gặp nhiều hệ thống điều khiển tự động hoạt động theo nguyên
tắc cơ khí, thuỷ lực, khí nén, rơ le, hoặc diện tử tương tự…

- Ngược lại phần lớn các sản phẩm cơ điện tử hiện nay đều có nhúng trong nó các chip
vi xử lý hoặc một mạng nhúng. Ta biết rằng cơ điện tử là sự cộng năng của các công
nghệ cơ khí, điện tử, điều khiển và công nghệ thông tin. Sự phối hợp đa ngành này tạo
Trang 14
nên sự vượt trội của các sản phẩm cơ điện tử. Sản phẩm cơ điện tử ngày càng tinh sảo
và ngày càng thông minh mà phần hồn của nó do các phần mềm nhúng trong nó tạo
nên. Các sản phẩm cơ điện tử là các sản phẩm có ít nhất một quá trình cơ khí (thường
là một quá trình chuyển động), là đối tượng để điều khiển do vậy các sản phẩm cơ
điện tử ngày nay thường có các hệ nhúng trong nó nhưng ngược lại không phải hệ
thống nhúng nào cũng là một hệ cơ điện tử.

- Điểm qua sự phát triển của máy tính ta thấy nó đã trải qua 3 giai đoạn. Giai đoạn năm
1960-1980 là giai đoạn phát triển của máy tính lớn và máy mini (main frame và mini
computer) với khoảng 1000 chip/máy và mỗi máy có khoảng 100 người dùng. Giai
đoạn từ 1980-2000 là giai đoạn phát triển của máy PC với số chip vi xử lý khoảng 10
chip/máy và thông thường cho một người sử dụng. Thời đại hậu PC (Post-PC Era) là
giai đoạn mà mọi đồ dùng đều có chip, trung bình 1 chip/một máy và số máy dùng cho
một người lên đến >100 máy. Giai đoạn hậu PC được dự báo từ 2001-2010 khi các
thiết bị xung quanh ta đều được thông minh hoá và kết nối với nhau thành mạng tạo
thành môi trường thông minh phục vụ cho con người.

- Điểm qua về chức năng xử lý tin ở PC và ở các thiết bị nhúng có những nét khác biệt.
Đối với PC và mạng Internet chức năng xử lý đang được phát triển mạnh ở các lĩnh
vực như thương mại điện tử, ngân hàng điện tử, chính phủ điện tử, thư viện điện tử,
đào tạo từ xa, báo điện tử….Các ứng dụng này thường sử dụng máy PC để bàn, mạng
WAN, LAN hoạt động trong thế giới ảo. Còn đối với các hệ nhúng thì chức năng xử lý
tính toán được ứng dụng cụ thể cho các thiết bị vật lý (thế giới thật) như mobile phone,
quần áo thông minh, các đồ điện tử cần tay, thiết bị y tế, xe ô tô, tàu tốc hành, phương
tiện vận tải thông minh, máy đo, đầu đo cơ cấu chấp hành thông minh, các hệ thống
điều khiển, nhà thông minh, thiết bị gia dụng thông minh …

- HTN có vai trò đảm nhận một phần công việc cụ thể của hệ thống mẹ. HTN có thể là
một hệ thống phần cứng và cũng có thể là một hệ thống phần mềm. Đặc điểm của HTN là
hoạt động ổn định và có tính năng tự động hoá cao. HTN được thiết kế để thực hiện một
chứa năng chuyên biệt nào đó. Khác với các máy tính đa năng, chẳng hạn như PC, một
HTN chỉ thực hiện một hay một vài chức năng nhất định, thường đi kèm với những yêu
cầu cụ thể và bao gồm một số thiết bị máy móc và phần cứng chuyên dụng mà ta không
tìm thấy trong một máy tính đa năng nói chung. Vì hệ thống chỉ được xây dựng cho một
số nhiệm vụ nhất định nên các nhà thiết kế có thể tối ưu hóa nó nhằm giảm thiểu kích
thước và chi phí sản xuất. Các HTN thường được sản xuất hàng loạt với số lượng lớn.
HTN rất đa dạng, phong phú về chủng loại. Đó có thể là những thiết bị cầm tay nhỏ gọn
như đồng hồ kĩ thuật số và máy chơi nhạc MP3, các thiết bị điện tử dân dụng (máy giặt, tủ
lạnh, TV...), các thiết bị điện tử “thông minh” (điện thoại di động), thiết bị truyền thông,
thiết bị y tế, xe hơi, thậm chí cả trong một máy tính cá nhân (card mở rộng), hoặc những
sản phẩm lớn như đèn giao thông, bộ kiểm soát trong nhà máy hoặc hệ thống kiểm soát
các máy năng lượng hạt nhân. Xét về độ phức tạp, HTN có thể rất đơn giản với một vi
điều khiển hoặc rất phức tạp với nhiều đơn vị, các thiết bị ngoại vi và mạng lưới được
nằm gọn trong một lớp vỏ máy lớn.

- Các thiết bị PDA hoặc máy tính cầm tay cũng có một số đặc điểm tương tự với HTN
như các hệ điều hành hoặc vi xử lý điều khiển chúng nhưng các thiết bị này không phải là
Trang 15
HTN thật sự bởi chúng là các thiết bị đa năng, cho phép sử dụng nhiều ứng dụng và kết
nối đến nhiều thiết bị ngoại vi.

- Có rất nhiều hãng sản xuất bộ vi xử lý, phần cứng và phần mềm trong thị trường hệ
thống nhúng và ứng với mỗi nhà sản xuất lại có nhiều dòng sản phẩm, phong phú về
chủng loại và giá thành:

• Những bộ vi xử lý và phần cứng khác nhau: Texas Instrument, Freescale, ARM,
Intel, Motorola, Atmel, AVR, Renesas…

• Những hệ điều hành khác nhau: QNX, uITRON, VxWorks, Windows CE/XP
Embedded, Embedded Linux, Osek, Symbian…

• Những ngôn ngữ lập trình khác nhau: C/C++, B#, Ada, Assembly, PMC, LabView,
PLC…

2. Lịch sử:

- HTN đầu tiên là Apollo Guidance Computer (Máy tính Dẫn đường Apollo) được phát
triển bởi Charles Stark Draper tại phòng thí nghiệm của trường đại học MIT. HTN được
sản xuất hàng loạt đầu tiên là máy hướng dẫn cho tên lửa quân sự vào năm 1961. Nó là
máy hướng dẫn Autonetics D-17, được xây dựng sử dụng những bóng bán dẫn và một đĩa
cứng để duy trì bộ nhớ. Khi Minuteman II được đưa vào sản xuất năm 1996, D-17 đã được
thay thế với một máy tính mới sử dụng mạch tích hợp. Tính năng thiết kế chủ yếu của máy
tính Minuteman là nó đưa ra thuật toán có thể lập trình lại sau đó để làm cho tên lửa chính
xác hơn, và máy tính có thể kiểm tra tên lửa, giảm trọng lượng của cáp điện và đầu nối
điện.

- Từ những ứng dụng đầu tiên vào những năm 1960, các HTN đã giảm giá và phát triển
mạnh mẽ về khả năng xử lý. Bộ vi xử lý đầu tiên hướng đến người tiêu dùng là Intel 4004,
được phát minh phục vụ máy tính điện tử và những hệ thống nhỏ khác. Tuy nhiên nó vẫn
cần các chip nhớ ngoài và những hỗ trợ khác. Vào những năm cuối 1970, những bộ xử lý
8 bit đã được sản xuất, nhưng nhìn chung chúng vẫn cần đến những chip nhớ bên ngoài.

- Vào giữa thập niên 80, kỹ thuật mạch tích hợp đã đạt trình độ cao dẫn đến nhiều thành
phần có thể đưa vào một chip xử lý. Các bộ vi xử lý được gọi là các vi điều khiển và được
chấp nhận rộng rãi. Với giá cả thấp, các vi điều khiển đã trở nên rất hấp dẫn để xây dựng
các hệ thống chuyên dụng. Đã có một sự bùng nổ về số lượng các HTN trong tất cả các
lĩnh vực thị trường và số các nhà đầu tư sản xuất theo hướng này. Ví dụ, rất nhiều chip xử
lý đặc biệt xuất hiện với nhiều giao diện lập trình hơn là kiểu song song truyền thống để kết
nối các vi xử lý. Vào cuối những năm 80, các HTN đã trở nên phổ biến trong hầu hết các
thiết bị điện tử và khuynh hướng này vẫn còn tiếp tục cho đến nay. Một hệ thống nhúng
đầu tiên được phát triển bởi Intel vào năm 1971. Đó chính là một con chip vi xử lý 4004
cho các máy tính cầm tay. Một con chip giống nó cũng đã được sử dụng cho tất cả các máy
tính cầm tay với nhiều chủng lại khác nhau, chúng chỉ khác nhau ở phần mềm tương ứng
với mỗi dòng được nạp trên ROM. Ngày nay, trên thế giới xấp xỉ 98% các loại vi xử lý/vi
điều khiển được sử dụng trong một HTN. Và ARM là nhà cung cấp hàng đầu các vi xử lý
dựa trên kiến trúc RISC 32 bit (chiếm 75% thị trường) cho các HTN đó. Điểm đặc biệt là

Trang 16
ARM chỉ bán IP chứ không bán chip, do đó việc tích hợp các IP vi xử lý 32 bit của ARM
vào một chip để xây dựng một SoC trở nên dễ dàng hơn.

- Cho đến nay, khái niệm HTN được nhiều người chấp nhận nhất là: hệ thống thực hiện
một số chức năng đặc biệt có sử dụng vi xử lý. Không có HTN nào chỉ có phần mềm.

- Điểm quan trọng cần lưu ý là sự khác biệt giữa một HTN và hệ thống máy tính PC :
một HTN chính là một hệ thống chuyên dụng với một chức năng cụ thể, trong khi đó hệ
thống máy tính PC là một hệ thống đa dụng với chức năng của nó tại một thời điểm do
phần mềm quyết định.

- Trong một HTN có thể có nhiều chương trình phần mềm chạy cùng lúc với nhau dưới
một hệ điều hành nào đó. Bởi vì một HTN còn có thể là một phần nhỏ của một hệ thống
lớn hơn, nên nó có thể nằm trên một board mạch với một vi xử lý riêng cùng với phần
mềm được lưu trữ trong ROM. Vì là một hệ thống chuyên dụng, nên hầu hết các HTN
phải đáp ứng sự thay đổi ở các tín hiệu ngõ vào (input) trong thời gian ngắn nhất có thể,
tức là phải đảm bảo tốc độ hoạt động của nó. Vì vậy, các HTN đều có tốc độ hoạt động rất
cao là được xếp vào loại thời gian thực (real time). Với các ứng dụng đơn giản, nó chỉ cần
một chương trình nhỏ (mà không cần hệ điều hành) để điều khiển hệ thống, tuy nhiên, một
hệ điều hành cài đặt trên HTN để chạy các chương trình ứng dụng sẽ giúp cho hệ thống
trở nên cực kỳ linh hoạt.

3. Đặc trưng của hệ thống nhúng:

- Một đặc trưng quan trọng của HTN đó chính là “tính quyết định”. Đặc trưng này có
nghĩa là tất cả các trạng thái bên trong của hệ thống, các giá trị ngõ vào liên quan đến ngõ
ra đều có thể tính toán trước được (về mặt nguyên tắc). Tất nhiên “tính quyết định” không
chỉ là một đặc trưng riêng cho một HTN mà nó có thể là một hệ thống bất kỳ. Tuy vậy, một
đặc tính khác cũng khá quan trọng và mang nét riêng của HTN đó chính là thời gian thực.
Một HTN phải có khả năng thực hiện chức năng của mình trong một khoảng thời gian hữu
hạn, ít nhất và có thể biết trước.

- Một HTN bao giờ cũng được “bao bọc” bởi một hệ thống phần cứng mà nó điều
khiển. Chính vì vậy, đối với người sử dụng cuối, họ không nhận ra sự hiện diện của HTN
trong một thiết bị phần cứng. Do đó, đây cũng là sự khác biệt giữa một HTN và một PC.
Một HTN cũng có khả năng tương tác với thế giới bên ngoài, tuy nhiên giao diện người sử
dụng của nó lại thường khá đơn giản.

- Lĩnh vực HTN đòi hỏi sự kết hợp của nhiều ngành lại với nhau như: kỹ thuật phần
mềm, hệ điều hành, thiết kế phần cứng (chip) … Vì vậy, một kỹ sư thiết kế HTN phải có
khả năng hiểu được nhiều lĩnh vực khác nhau, từ thiết kế phần cứng, xuống layout ra chip,
đến lập trình phần mềm, cài đặt hệ điều hành ...

4. Các đặc điểm:

HTN thường có một số đặc điểm chung như sau:

- Các HTN được thiết kế để thực hiện một số nhiệm vụ chuyên dụng chứ không phải
đóng vai trò là các hệ thống máy tính đa chức năng. Một số hệ thống đòi hỏi ràng buộc về

Trang 17
tính hoạt động thời gian thực để đảm bảo độ an toàn và tính ứng dụng, một số hệ thống
không đòi hỏi hoặc ràng buộc chặt chẽ, cho phép đơn giản hóa hệ thống phần cứng để
giảm thiểu chi phí sản xuất.

- Một HTN thường không phải là một khối riêng biệt mà là một hệ thống phức tạp nằm
trong thiết bị mà nó điều khiển.

- Phần mềm được viết cho các hệ thống nhúng được gọi là firmware và được lưu trữ
trong các chip bộ nhớ chỉ đọc (read-only memory) hoặc bộ nhớ flash chứ không phải là
trong một ổ đĩa. Phần mềm thường chạy với số tài nguyên phần cứng hạn chế: không có
bàn phím, màn hình hoặc có nhưng với kích thước nhỏ, bộ nhớ hạn chế.

4.1 Đặc điểm giao diện:

- Các HTN có thể không có giao diện (đối với những hệ thống đơn nhiệm) hoặc
có đầy đủ giao diện giao tiếp với người dùng tương tự như các hệ điều hành trong các
thiết bị để bàn. Đối với các hệ thống đơn giản, thiết bị nhúng sử dụng nút bấm, đèn
LED và hiển thị chữ cỡ nhỏ hoặc chỉ hiển thị số, thường đi kèm với một hệ thống
menu đơn giản.Còn trong một hệ thống phức tạp hơn, một màn hình đồ họa, cảm ứng
hoặc có các nút bấm ở lề màn hình cho phép thực hiện các thao tác phức tạp mà tối
thiểu hóa được khoảng không gian cần sử dụng. Ý nghĩa của các nút bấm có thể thay
đổi theo màn hình và các lựa chọn. Các HTN thường có một màn hình với một nút
bấm dạng cần điểu khiển (joystick button). Sự phát triển mạnh mẽ của mạng toàn cầu
đã mang đến cho những nhà thiết kế HTN một lựa chọn mới là sử dụng một giao diện
web thông qua việc kết nối mạng. Điều này có thể giúp tránh được chi phí cho những
màn hình phức tạp nhưng đồng thời vẫn cung cấp khả năng hiển thị và nhập liệu phức
tạp khi cần đến, thông qua một máy tính khác. Điều này là hết sức hữu dụng đối với
các thiết bị điều khiển từ xa, cài đặt vĩnh viễn. Ví dụ, các router là các thiết bị đã ứng
dụng tiện ích này.

4.2 Kiến trúc CPU:

- Các bộ xử lý trong HTN có thể được chia thành hai loại: vi xử lý và vi điều
khiển. Các vi điều khiển thường có các thiết bị ngoại vi được tích hợp trên chip nhằm
giảm kích thước của hệ thống. Có rất nhiều loại kiến trúc CPU được sử dụng trong
thiết kế HTN như ARM, MIPS, Coldfire/68k, PowerPC, x86, PIC, 8051, Atmel AVR,
Renesas H8, SH, V850, FR-V, M32R, Z80, Z8 … Điều này trái ngược với các loại
máy tính để bàn, thường bị hạn chế với một vài kiến trúc máy tính nhất định. Các
HTN có kích thước nhỏ và được thiết kế để hoạt động trong môi trường công nghiệp
thường lựa chọn PC/104 và PC/104++ làm nền tảng. Những hệ thống này thường sử
dụng DOS, Linux, NetBSD hoặc các hệ điều hành nhúng thời gian thực như QNX hay
VxWorks. Còn các HTN có kích thước rất lớn thường sử dụng một cấu hình thông
dụng là hệ thống on chip (System on a chip – SoC), một bảng mạch tích hợp cho một
ứng dụng cụ thể (an application-specific integrated circuit – ASIC). Sau đó nhân CPU
được mua và thêm vào như một phần của thiết kế chip. Một chiến lược tương tự là sử
dụng FPGA (field-programmable gate array) và lập trình cho nó với những thành phần
nguyên lý thiết kế bao gồm cả CPU.

4.3 Thiết bị ngoại vi: HTN giao tiếp với bên ngoài thông qua các thiết bị ngoại vi

Trang 18
 Serial Communication Interfaces (SCI): RS-232, RS-422, RS-485...
 Synchronous Serial Communication Interface: I2C, JTAG, SPI, SSC và ESSI

 Universal Serial Bus (USB)

 Networks: Controller Area Network, LonWorks...

 Bộ định thời: PLL(s), Capture/Compare và Time Processing Units

 Discrete IO: General Purpose Input/Output (GPIO)

4.4 Công cụ phát triển:

- Tương tự như các sản phẩm phần mềm khác, phần mềm HTN cũng được phát
triển nhờ việc sử dụng các trình biên dịch (compilers), chương trình dịch hợp ngữ
(assembler) hoặc các công cụ gỡ rối (debuggers). Tuy nhiên, các nhà thiết kế HTN có
thể sử dụng một số công cụ chuyên dụng như:

 Bộ gỡ rối mạch hoặc các chương trình mô phỏng (emulator)


 Tiện ích để thêm các giá trị checksum hoặc CRC vào chương trình,
giúp HTN có thể kiểm tra tính hợp lệ của chương trình đó.

 Đối với các hệ thống xử lý tín hiệu số, người phát triển hệ thống có thể
sử dụng phần mềm workbench như MathCad hoặc Mathematica để mô
phỏng các phép toán.

 Các trình biên dịch và trình liên kết (linker) chuyên dụng được sử dụng
để tối ưu hóa một thiết bị phần cứng.

 Một HTN có thể có ngôn ngữ lập trình và công cụ thiết kế riêng của nó
hoặc sử dụng và cải tiến từ một ngôn ngữ đã có sẵn.

- Các công cụ phần mềm có thể được tạo ra bởi các công ty phần mềm chuyên
dụng về HTN hoặc chuyển đổi từ các công cụ phát triển phần mềm GNU. Đôi khi, các
công cụ phát triển dành cho PC cũng được sử dụng nếu bộ xử lý của HTN đó gần
giống với bộ xử lý của một máy PC thông dụng.

4.5 Độ tin cậy:

- Các HTN thường nằm trong các cỗ máy được kỳ vọng là sẽ chạy hàng năm trời
liên tục mà không bị lỗi hoặc có thể khôi phục hệ thống khi gặp lỗi. Vì thế, các phần
mềm HTN được phát triển và kiểm thử một cách cẩn thận hơn là phần mềm cho PC.
Ngoài ra, các thiết bị rời không đáng tin cậy như ổ đĩa, công tắc hoặc nút bấm thường
bị hạn chế sử dụng. Việc khôi phục hệ thống khi gặp lỗi có thể được thực hiện bằng
cách sử dụng các kỹ thuật như watchdog timer – nếu phần mềm không đều đặn nhận
được các tín hiệu watchdog định kì thì hệ thống sẽ bị khởi động lại.

- Một số vấn đề cụ thể về độ tin cậy như:

• Hệ thống không thể ngừng để sửa chữa một cách an toàn, VD như ở các
hệ thống không gian, hệ thống dây cáp dưới đáy biển, các đèn hiệu dẫn
Trang 19
đường … Giải pháp đưa ra là chuyển sang sử dụng các hệ thống con dự trữ
hoặc các phần mềm cung cấp một phần chức năng.
• Hệ thống phải được chạy liên tục vì tính an toàn, VD như các thiết bị
dẫn đường máy bay, thiết bị kiểm soát độ an toàn trong các nhà máy hóa
chất,… Giải pháp đưa ra là lựa chọn backup hệ thống.
• Nếu hệ thống ngừng hoạt động sẽ gây tổn thất rất nhiều tiền của, VD
như các dịch vụ buôn bán tự động, hệ thống chuyển tiền, hệ thống kiểm
soát trong các nhà máy …

5.Các kiến trúc phần mềm HTN:

Một số loại kiến trúc phần mềm thông dụng trong các HTN như sau:

5.1 Vòng lặp kiểm soát đơn giản:

- Theo thiết kế này, phần mềm được tổ chức thành một vòng lặp đơn giản. Vòng
lặp gọi đến các chương trình con, mỗi chương trình con quản lý một phần của hệ
thống phần cứng hoặc phần mềm.

5.2 Hệ thống ngắt điều khiển:

- Các HTN thường được điểu khiển bằng các ngắt. Có nghĩa là các tác vụ của
HTN được kích hoạt bởi các loại sự kiện khác nhau. VD: một ngắt có thể được
sinh ra bởi một bộ định thời sau một chu kỳ được định nghĩa trước, hoặc bởi sự
kiện khi cổng nối tiếp nhận được một byte nào đó.

- Loại kiến trúc này thường được sử dụng trong các hệ thống có bộ quản lý sự
kiện đơn giản, ngắn gọn và cần độ trễ thấp. Hệ thống này thường thực hiện một
tác vụ đơn giản trong một vòng lặp chính. Đôi khi, các tác vụ phức tạp hơn sẽ
được thêm vào một cấu trúc hàng đợi trong bộ quản lý ngắt để được vòng lặp xử
lý sau đó. Lúc này, hệ thống gần giống với kiểu nhân đa nhiệm với các tiến trình
rời rạc.

5.3 Đa nhiệm tương tác:

- Một hệ thống đa nhiệm không ưu tiên cũng gần giống với kỹ thuật vòng lặp
kiểm soát đơn giản ngoại trừ việc vòng lặp này được ẩn giấu thông qua một giao
diện lập trình API. Các nhà lập trình định nghĩa một loạt các nhiệm vụ, mỗi nhiệm
vụ chạy trong một môi trường riêng của nó. Khi không cần thực hiện nhiệm vụ đó
thì nó gọi đến các tiến trình con tạm nghỉ (bằng cách gọi “pause”, “wait”, “yeild”
…).

- Ưu điểm và nhược điểm của loại kiến trúc này cũng giống với kiểm vòng lặp
kiểm soát đơn giản. Tuy nhiên, việc thêm một phần mềm mới được thực hiện dễ
dàng hơn bằng cách lập trình một tác vụ mới hoặc thêm vào hàng đợi thông dịch
(queue-interpreter).

5.4 Đa nhiệm ưu tiên:

Trang 20
- Ở loại kiến trúc này, hệ thống thường có một đoạn mã ở mức thấp thực hiện
việc chuyển đổi giữa các tác vụ khác nhau thông qua một bộ định thời. Đoạn mã
này thường nằm ở mức mà hệ thống được coi là có một hệ điều hành và vì thế
cũng gặp phải tất cả những phức tạp trong việc quản lý đa nhiệm.

- Bất kỳ tác vụ nào có thể phá hủy dữ liệu của một tác vụ khác đều cần phải
được tách biệt một cách chính xác. Việc truy cập tới các dữ liệu chia sẻ có thể
được quản lý bằng một số kỹ thuật đồng bộ hóa như hàng đợi thông điệp
(message queues), semaphores … Vì những phức tạp nói trên nên một giải pháp
thường được đưa ra đó là sử dụng một hệ điều hành thời gian thực. Lúc đó, các
nhà lập trình có thể tập trung vào việc phát triển các chức năng của thiết bị chứ
không cần quan tâm đến các dịch vụ của hệ điều hành nữa.

5.5. Vi nhân (Microkernel) và nhân ngoại (Exokernel):

- Khái niệm vi nhân (microkernel) là một bước tiếp cận gần hơn tới khái niệm hệ
điều hành thời gian thực. Lúc này, nhân hệ điều hành thực hiện việc cấp phát bộ
nhớ và chuyển CPU cho các luồng thực thi. Còn các tiến trình người dùng sử
dụng các chức năng chính như hệ thống file, giao diện mạng lưới,… Nói chung,
kiến trúc này thường được áp dụng trong các hệ thống mà việc chuyển đổi và giao
tiếp giữa các tác vụ là nhanh.

- Còn nhân ngoại (exokernel) tiến hành giao tiếp hiệu quả bằng cách sử dụng các
lời gọi chương trình con thông thường. Phần cứng và toàn bộ phần mềm trong hệ
thống luôn đáp ứng và có thể được mở rộng bởi các ứng dụng.

5.6 Nhân khối (monolithic kernels):

- Trong kiến trúc này, một nhân đầy đủ với các khả năng phức tạp được chuyển
đổi để phù hợp với môi trường nhúng. Điều này giúp các nhà lập trình có được
một môi trường giống với hệ điều hành trong các máy để bàn như Linux hay
Microsoft Windows và vì thế rất thuận lợi cho việc phát triển. Tuy nhiên, nó lại
đòi hỏi đáng kể các tài nguyên phần cứng làm tăng chi phí của hệ thống. Một số
loại nhân khối thông dụng là Embedded Linux và Windows CE. Mặc dù chi phí
phần cứng tăng lên nhưng loại HTN này đang tăng trưởng rất mạnh, đặc biệt là
trong các thiết bị nhúng mạnh như Wireless router hoặc hệ thống định vị GPS. Lý
do của điều này là:

• Hệ thống này có cổng để kết nối đến các chip nhúng thông dụng
• Hệ thống cho phép sử dụng lại các đoạn mã sẵn có phổ biến như các trình
điều khiển thiết bị, Web Servers, Firewalls, …
• Việc phát triển hệ thống có thể được tiến hành với một tập nhiều loại đặc tính,
chức năng còn sau đó lúc phân phối sản phẩm, hệ thống có thể được cấu hình
để loại bỏ một số chức năng không cần thiết. Điều này giúp tiết kiệm được
những vùng nhớ mà các chức năng đó chiếm giữ.
• Hệ thống có chế độ người dùng để dễ dàng chạy các ứng dụng và gỡ rối. Nhờ
đó, qui trình phát triển được thực hiện dễ dàng hơn và việc lập trình có tính
linh động hơn.
Trang 21
• Có nhiều HTN thiếu các yêu cầu chặt chẽ về tính thời gian thực của hệ thống
quản lý. Còn một hệ thống như Embedded Linux có tốc độ đủ nhanh để trả lời
cho nhiều ứng dụng. Các chức năng cần đến sự phản ứng nhanh cũng có thể
được đặt vào phần cứng.

6. Hệ thống thời gian thực:

- Như đã đề cập ở trên, một hệ thống có khả năng thực hiện thời gian thực nghĩa là hệ
thống đó phải thực hiện các chức năng của mình trong một khoảng thời gian xác định và nhỏ
nhất có thể chấp nhận được. Khi đáp ứng được yêu cầu này, hệ thống đó có thể gọi là hệ
thống thời gian thực.

- Các hệ thống này phải có khả năng đáp ứng các tín hiệu ngõ vào hoặc các sự kiện
trong giới hạn một khoảng thời gian bắt buộc. Cho nên các hệ thống này không chỉ phải trả
về một kết quả đúng mà còn phải nhanh nhất đáp ứng được yêu cầu về tốc độ của hệ thống.
Trong các hệ thống thời gian thực, tốc độ cũng quan trọng không kém gì độ chính xác của
nó.

- Có 2 loại thời gian thực: thời gian thực cứng và thời gian thực mềm. Đối với hệ thống
thời gian thực cứng, tất cả các chức năng của nó phải được thực thi chính xác trong một
khoảng thời gian xác định, nếu không cả hệ thống sẽ bị lỗi nghiêm trọng. VD: hệ thống điều
khiển không lưu, hệ thống dẫn đường tên lửa, thiết bị y tế ... Đối với hệ thống thời gian thực
mềm, các chức năng phải được thực hiện trong một khoảng thời gian xác định nhỏ nhất
nhưng không bắt buộc.

7. Hệ điều hành thời gian thực (RTOS) và kernel thời gian thực:

- Một số các ứng dụng nhúng có thể thực hiện hiệu quả mà chỉ cần một chương trình
đơn giản chạy độc lập điều khiển cả hệ thống. Tuy nhiên, đối với đa số các ứng dụng mang
tính thương mại, một HTN cần phải có hệ điều hành thời gian thực hoặc kernel thời gian
thực. Một kernel thời gian thực thường nhỏ hơn rất nhiều so với một RTOS hoàn chỉnh.
Trong lý thuyết về hệ điều hành, kernel chính là một phần của hệ điều hành, nó sẽ được nạp
lên bộ nhớ đầu tiên và vẫn tồn tại trong lúc chương trình hoạt động. Một kernel thời gian
thực sẽ cung cấp hầu hết các dịch vụ cần thiết cho các ứng dụng nhúng.Do đó chỉ là một
phần của hệ điều hành và được nạp thẳng lên bộ nhớ, nên một kernel thời gian thực thường
có kích thước rất nhỏ, rất phù hợp cho các bộ nhớ có dung lượng thấp trong các HTN. Hình
dưới mô tả một kernel trong một RTOS hoàn chỉnh.

Trang 22
- Hoạt động của HTN đươc thực hiện theo chương trình, gồm các tác vụ (task) hoặc
luồng (thread) trong việc đáp ứng các tín hiệu ngõ vào hay trong quá trình xử lý bình thường
theo yêu cầu của hệ thống. Các quá trình xử lý phải trả về kết quả đúng trong một khoảng thời
gian xác định.
8. Chương trình, tác vụ và luồng:
- Một chương trình trên một HTN chính là một phần mềm có khả năng thực thi độc lập
và có vùng nhớ riêng của mình. Nó bao gồm môi trường thực thi một chức năng cụ thể và
khả năng tương tác với hệ điều hành. Một chương trình có thể được bắt đầu chạy một cách
độc lập hoặc có thể từ các chương trình khác. Một hệ điều hành có khả năng thực thi nhiều
chương trình cùng một lúc song song nhau.
- Tuy nhiên, khi một chương trình có khả năng tự chia ra một vài phần có khả năng thực
thi song song nhau, mỗi phần đó được gọi là một luồng. Một luồng chính là một phần trong
chương trình và phụ thuộc về mặt chức năng so với các luồng khác nhưng lại có khả năng
hoạt động độc lập nhau. Các luồng sẽ chia sẻ chung một bộ nhớ trong một chương trình.
Khái niệm về tác vụ và luồng có thể thay thế cho nhau. Hình dưới mô tả sự khác nhau giữa
chương trình và luồng.

9. Kiến trúc của hệ thống thời gian thực:

- Kiến trúc của một hệ thống thời gian thực sẽ quyết định các luồng được thực thi khi
nào và bằng cách nào. Có 2 kiến trúc phổ biến là kiến trúc điều khiển vòng lặp với polling
và mô hình sắp xếp ưu tiên. Trong kiến trúc điều khiển vòng lặp với polling, kernel sẽ thực
thi một vòng lặp vô hạn, vòng lặp này sẽ chọn ra luồng trong một mẫu được định trước. Nếu
một luồng cần dịch vụ, nó sẽ được xử lý. Có một vài biến thể của phương pháp này, tuy
nhiên vẫn phải đảm bảo mỗi luồng đều có khả năng truy cập đến vi xử lý. Hình dưới mô tả
cách xử lý của phương pháp này.

Trang 23
- Mặc dù phương pháp điều khiển vòng lặp với polling rất dễ thực hiện, tuy nhiên nó
vẫn có những hạn chế nghiêm trọng. Thứ nhất đó chính là nó sẽ mất rất nhiều thời gian, khi
mà một luồng cần truy cập đến vi xử lý sẽ phải chờ đến lượt của mình và một chương trình có
quá nhiều luồng sẽ bị chậm đi rất nhiều. Thứ hai, phương pháp này không có sự phân biệt
giữa các luồng, luồng nào quan trọng và luồng nào ít quan trọng, từ đó xác định mức độ ưu
tiên giữa các luồng.
- Một phương pháp khác mà các kernel thời gian thực hay sử dụng đó chính là mô hình
sắp xếp mức độ ưu tiên. Trong mô hình này, mỗi luồng sẽ đi kèm với mức độ ưu tiên của nó.
Lúc này, vi xử lý sẽ thiết lập đường truy cập tới luồng nào có mức độ ưu tiên cao nhất khi nó
đòi hỏi được phục vụ. Cũng có một vài biến thể của phương pháp này, tuy nhiên vẫn phải đảm
bảo các luồng có mức độ ưu tiên thấp nhất vẫn phải có thể truy cập tới vi xử lý một vài lần.
Hình dưới mô tả phương pháp cách xử lý của phương pháp này.

- Một ưu điểm cực kỳ quan trọng của phương pháp này đó chính là nó có khả năng tạm
hoãn thực thi một luồng khi có một luồng khác với mức độ ưu tiên cao hơn cần phục vụ. Quá
trình lưu trữ lại các thông tin hiện thời của luồng bị tạm hoãn thực thi khi có một luồng khác
với mức độ ưu tiên cao hơn cần phục vụ gọi là “context switching”. Quá trình này phải được
thực hiện nhanh và đơn giản để luồng bị tạm hoãn có thể thực hiện tiếp nhiệm vụ của mình
một cách chính xác khi nó lấy lại đươc quyền điều khiển.
- Một HTN thời gian thực phải có khả năng đáp ứng lại các tín hiệu ngõ vào hay các sự
kiện một cách nhanh nhất và chính xác nhất, đây chính là các ngắt của hệ thống. Ngắt của hệ
thống sẽ phải làm cho vi xử lý ngưng nhiệm vụ đang thực thi để xử lý ngắt. Một ngắt sẽ được
xử lý bởi ISR (interrupt service routine), nó có khả năng kích hoạt một luồng có mức độ ưu
tiên cao hơn luồng đang được thực thi. Lúc này, nó sẽ tạm hoãn lại luồng hiện tại để dành
quyền cho luồng mới có mức độ ưu tiên cao hơn. Ngắt có thể được tạo ra bởi phần mềm (ngắt
mềm) hay bởi các thiết bị phần cứng (ngắt cứng).

10.Phân tích một HTN:

Trang 24
- Hình trên là sơ đồ khối của một HTN điển hình. Đây là một ví dụ rất đơn giản của một
kiến trúc phần cứng cấp cao có thể được tìm thấy trong một điểm truy cập không dây.
Trung tâm của hệ thống này con vi xử lí 32bit RISC .Bộ nhớ Flash được sử dụng có
chương trình nonvolatile và lưu trữ dữ liệu. Bộ nhớ chính là một bộ nhớ động SDRAM và
có dung lượng từ vài MB đến vài trăm MB tùy thuộc vào từng ứng dụng. Một module đồng
hồ thời gian thực, chạy bằng pin lưu trữ thời gian trong ngày ( ngày /tháng /năm) .VD này
bao gồm một giao diện Ethernet và USB, cũng như một cổng nối tiếp với bàn điều khiển
truy cập thông qua RS-232. chip 802.11 thực hiện chức năng không dây.
- Thường thì bộ vi xử lí trong HTN thực hiện nhiều chức năng hơn CPU cổ điển. Giả sử
rằng vi xử lí trong hình trên có tích hợp chức năng UART cho giao diện nối tiếp và tích
hợp bộ điều khiển USB và Ethernet. Nhiều bộ vi xử lí còn tích hợp cả thiết bị ngoại vi.
- Thiết kế các HTN là thiết kế phần cứng và phần mềm phối hợp bao gồm những bước
sau:

• Mô hình hoá hệ thống: Mô tả các khối chức năng với các đặc tính và thuật toán
xử lý.

• Chi tiết hoá các khối chức năng.

• Phân bố chức năng cho phần cứng và mềm (HW-SW).

• Đồng bộ hoạt động của hệ thống.

• Cài đặt các chức năng thiết kế vào phần cứng (hardware) và phần mềm
(software) hoặc phần nhão (firm-ware).

- Cách thiết kế cổ điển là các chức năng phần mềm (SW) và phần cứng (HW) được xác
định trước rồi sau đó các bước thiết kế chi tiết được tiến hành một cách độc lập ở hai
khối . Hiện nay đa số các hệ thống tự động hoá thiết kế (CAD) thường dành cho thiết
kế phần cứng. Các hệ thống nhúng sử dụng đồng thời nhiều công nghệ như vi xử lý,
DSP, mạng và các chuẩn phối ghép, protocol, do vậy xu thế thiết kế các hệ nhúng hiện
Trang 25
nay đòi hỏi có khả năng thay đổi mềm dẻo hơn trong quá trình thiết kế 2 phần HW và
SW. Để có được thiết kế cuối cùng tối ưu quá trình thiết kế SW và HW phải phối hợp
với nhau chặt chẽ và có thể thay đổi sau mỗi lần thử chức năng hoạt động tổng hợp

- Thiết kế các hệ nhúng đòi hỏi kiến thức đa ngành về điện tử, xử lý tín hiệu, vi xử lý,
thuật điều khiển và lập trình thời gian thực.

11.Sự phát triển của hệ thống nhúng:

- Các ứng dụng nhúng ngày nay rất rộng rãi và sẽ được phát triển ngày càng cao ở cả
phần cứng lẫn phần mềm. Các ứng dụng nhúng đều cần phải có thời gian thực, đây là một sự
khác biệt rất lớn giữa một HTN và một hệ thống máy tính truyền thống. Ngày nay để tăng
tốc độ của một HTN, nó phải có khả năng thực hiện xử lý song song giữa các luồng với
nhau. Do vậy, cách viết các chương trình phần mềm truyền thống sẽ không còn phù hợp khi
lập trình cho các HTN đa luồng nữa. Hơn nữa, một vi xử lý trong HTN đòi hỏi tốc độ cao sẽ
không còn làm nhiệm vụ xử lý, mà chỉ còn làm nhiệm vụ điều khiển và giám sát hoạt động
của hệ thống. Chức năng xử lý luồng dữ liệu sẽ được các module phần cứng trong hệ thống
đảm nhận và được thực hiện song song nhau. Kiến trúc một HTN thời gian thực đã có sự
khác biệt rất nhiều và những cải tiến đáng kể so với kiến trúc hệ thống máy tính truyền
thống trước kia. Điều này nhằm đảm bảo về sự chính xác và cải thiện tốc độ của hệ thống.
Hầu hết các HTN ngày nay dùng ngôn ngữ C để lập trình, tuy nhiên một số rất ít vẫn dùng
hợp ngữ.

- Xu hướng phát triển của các hệ thống nhúng hiện nay là:

• Phần mềm ngày càng chiếm tỷ trọng cao và đã trở thành một thành phần cấu tạo
nên thiết bị bình đẳng như các phần cơ khí, linh kiện điện tử, linh kiện quang
học…
• Các hệ nhúng ngày càng phức tạp hơn đáp ứng các yêu cầu khắt khe về thời gian
thực, tiêu ít năng lượng và hoạt động tin cậy ổn định hơn.

• Các hệ nhúng ngày càng có độ mềm dẻo cao đáp ứng các yêu cầu nhanh chóng
đưa sản phẩm ra thương trường, có khả năng bảo trì từ xa, có tính cá nhân cao.

• Các hệ nhúng ngày càng có khả năng hội thoại cao, có khả năng kết nối mạng và
hội thoại được với các đầu đo cơ cấu chấp hành và với người sử dụng,.

• Các hệ nhúng ngày càng có tính thích nghi, tự tổ chức cao có khả năng tái cấu hình
như một thực thể, một tác nhân.

• Các hệ nhúng ngày càng có khả năng tiếp nhận năng lượng từ nhiều nguồn khác
nhau (ánh sáng, rung động, điện từ trường, sinh học….) để tạo nên các hệ thống tự
tiếp nhận năng lượng trong quá trình hoạt động.

- Trong các hệ nhúng, hệ thống điều khiển nhúng đóng một vai trò hết sức quan trọng.

- Nhu cầu hệ thống nhúng trên thế giới:

Trong thế giới công nghệ thông tin, các “ông lớn” như IBM, Microsoft, Intel
Trang 26
đã chuyển hướng một số bộ phận nghiên cứu phát triển của mình sang làm hệ thống
nhúng từ rất sớm. Điển hình là Microsoft với các máy chơi game Xbox, hệ điều hành
nhúng Windows CE, Intel với các dòng chip xử lý nhúng như Intel 8008, 8080, 8085,
3000, các thẻ nhớ Nand Flash, các vi điều khiển MCS 51/251, MCS 96/296 …Bên
cạnh đó là sự xuất hiện của hàng loạt các nhà sản xuất vi xử lý cho HTN như ARM,
Atmel, Renesas…Thị trường HTN có tiềm năng phát triển vô cùng lớn. Theo các nhà
thông kê trên thế giới thì số chip xử lý trong các máy PC và các server, các mạng
LAN, WAN, Internet chỉ chiếm không đầy 1% tổng số chip vi xử lý có trên thế giới.
Hơn 99% số vi xử lý còn lại nằm trong các hệ HTN. Số liệu đánh giá chi tiết của nhóm
nghiên cứu BCC (BCC Research Group) về thị trường HTN toàn cầu đến năm
2009 :“Thị trường HTN toàn cầu đạt doanh thu 45,9 tỷ USD trong năm 2004 và dự
báo sẽ tăng 14% trong vòng năm năm tới, đạt 88 tỷ USD.Trong đó thì thị trường phần
mềm nhúng sẽ tăng trưởng từ 1,6 tỷ USD năm 2004 lên 3,5 tỷ USD năm 2009, với
mức tăng trung bình hằng năm là 16%. Tốc độ tăng trưởng phần cứng nhúng sẽ là
14,2% một năm, đạt 78,7 tỷ USD năm 2009, trong khi lợi nhuận các board mạch
nhúng sẽ tăng 10% một năm.

Tại Châu Á, Nhật Bản đang dẫn đầu về thị trường nhúng và là một trong
những thị trường phần mềm nhúng hàng đầu thế giới. Theo thống kê của JISA (Hiệp
hội Dịch vụ Công nghệ Thông tin Nhật Bản), phần mềm nhúng hiện nay chiếm tới
40% thị phần phần mềm Nhật Bản, với các sản phẩm rất đa dạng : lò vi ba, máy
photocopy, máy in laser, máy FAX, các bảng quảng cáo sử dụng hệ thống đèn LED,
màn hình tinh thể lỏng…Năm 2004, thị trường phần mềm nhúng của Nhật Bản đạt
khoảng 20 tỷ USD với 150.000 nhân viên. Đây được coi là thị trường đầy hứa hẹn với
các đối tác chuyên sản xuất phần mềm nhúng như Trung Quốc, Indonesia, Nga,
Ireland, Israel và cả Việt Nam.

- Nhu cầu hệ thống nhúng ở Việt Nam:

Với tốc độ tăng trưởng nhanh như vậy, cơ hội cho các doanh nghiệp Việt Nam
đối với loại hình phần mềm mới mẻ này đang mở rộng. Chủ tịch Hiệp hội doanh
nghiệp phần mềm Việt Nam (VINASA) Trương Gia Bình cho rằng, các doanh nghiệp
Việt Nam đang có một số lợi thế. Đó là nguồn nhân lực công nghệ thông tin rẻ và tiếp
thu nhanh, có kinh nghiệm làm gia công phần mềm cho nước ngoài, được Chính phủ
quan tâm và hỗ trợ phát triển…Tuy nhiên, Việt Nam mới chỉ là “lính mới” trong sân
chơi sôi động này.Ở Việt Nam, HTN mới được quan tâm trong thời gian gần đây. Các
doanh nghiệp làm phần mềm nhúng cũng chưa nhiều, mới có một số trung tâm thuộc
các trường Đại học Quốc gia, Đại học Bách khoa, các đơn vị như Học viện Kỹ thuật
quân sự, Viện nghiên cứu Điện tử - Tin học và Tự động hóa, Tổng công ty Điện tử -
Tin học, Công ty thiết bị Điện tử y tế, Công ty VTC – Truyền hình số mặt đất và một
số công ty phần mềm khác…Các sản phẩm phần mềm nhúng “made in Việt Nam” có
lẽ mới chỉ là con số khá khiêm tốn, còn lại là làm gia công cho nước ngoài. Có thể
điểm ra một vài sản phẩm tiêu biểu do người Việt làm ra như phần mềm nhúng cho
đầu thu kỹ thuật số của Công ty Điện tử HANEL (giải Sao Khuê 2005), Nhúng cá thể
hóa thẻ thông minh của Công ty Liên doanh thẻ thông minh MK (giải Sao Khuê 2005)
…Con đường để đến với thành công trong sản xuất và xuất khẩu phần mềm nhúng của
Trang 27
các doanh nghiệp Việt Nam còn rất nhiều chông gai. Theo ông Phan Văn Hòa, Giám
đốc Trung tâm công nghệ của FPT Software, thách thức lớn nhất Việt Nam phải vượt
qua hiện nay là chưa có nhiều kinh nghiệm trong lĩnh vực mới mẻ này, mới chỉ loanh
quanh làm gia công phần mềm, làm thuê theo đơn đặt hàng của nước ngoài, chưa có
nhiều trung tâm đào tạo chuyên sâu về hệ thống nhúng. Tại hội thảo về CNTT tổ chức
tại Hải Phòng tháng 9-2005, Hiệp hội doanh nghiệp phần mềm Việt Nam VINASA
cho rằng, xây dựng và phát triển phần mềm nhúng là một trong 3 mũi nhọn có thể coi
là đột phá cho hướng đi của công nghệ phần mềm Việt Nam, bên cạnh việc phát triển
game và các giải pháp ERP. Trong chiến lược phát triển công nghệ thông tin đến năm
2010, phần mềm nhúng được coi là một trong những sản phẩm trọng điểm.

- Những thách thức và các vấn đề tồn tại của hệ nhúng:

• Độ phức tạp của sự liên kết đa ngành phối hợp cứng - mềm.Độ phức tạp của hệ
thống tăng cao do nó kết hợp nhiều lĩnh vực đa ngành, kết hợp phần cứng -
mềm, trong khi các phương pháp thiết kế và kiểm tra chưa chin muồi. Khoảng
cách giữa lý thuyết và thực hành lớn và còn thiếu các phương pháp và lý thuyết
hoàn chỉnh cho khảo sát phân tích toàn cục các hệ nhúng.
• Thiếu phương pháp tích hợp tối ưu giữa các thành phần tạo nên hệ nhúng bao
gồm lý thuyết điều khiển tự động, thiết kế máy, công nghệ phần mềm, điện tử,
vi xử lý, các công nghệ hỗ trợ khác.
• Thách thức đối với độ tin cậy và tính mở của hệ thống: Do hệ thống nhúng
thường phải hội thoại với môi trường xung quanh nên nhiều khi gặp những tình
huống không được thiết kế trước dễ dẫn đến hệ thống bị loạn. Trong quá trình
hoạt động một số phần mềm thường phải chỉnh lại và thay đổi nên hệ thống
phần mềm có thể không kiểm soát được. Đối với hệ thống mở, các hãng thứ 3
đưa các module mới, thành phần mới vào cũng có thể gây nên sự hoạt động
thiếu tin cậy

12. Các hệ điều hành nhúng:

Trang 28
- Khác với PC thường chạy trên nền hệ điều hành Windows hoặc UNIX, các HTN có
các hệ điều hành nhúng riêng của mình. Các hệ điều hành dùng trong các HTN nổi trội
hiện nay bao gồm Embedded Linux, VxWorks, Win CE, Lynyos, BSD, Green Hills,
QNX và DOS.
- Embedded Linux hiện đang phát triển mạnh và chiếm vị trí số 1. Hiện nay 40% các
nhà thiết kế các hệ nhúng cân nhắc đầu tiên sử dụng Embedded Linux cho các ứng
dụng mới của mình và sau đó mới đến các hệ điều hành nhúng truyền thống nhu
VxWorks, Win CE. Các đối thủ cạnh tranh của Embedded Linux hiện nay là các hệ
điều hành nhúng tự tạo và Windows CE.
- Sở dĩ Embedded Linux có sự phát triển vượt bậc là do có sức hấp dẫn đối với các ứng
dụng không đòi hỏi thời gian thực như set-top, các hệ server nhúng, các ứng dụng giá
thành thấp và đòi hỏi thời gian đưa sản phẩm ra thị trường nhanh. Mặt khác Linux là
phần mềm mã nguồn mở nên bất kỳ ai cũng có thể hiểu và thay đổi theo ý mình. Linux
cũng là một hệ điều hành có cấu trúc module và chiếm ít bộ nhớ trong khi Windows
không có các đặc tính ưu việt này.
- Bên cạnh các ưu điểm trên thì Embedded Linux cũng có các nhược điểm sau:
• Embedded Linux không phải là hệ điều hành thời gian thực nên có thể không
phù hợp với một số ứng dụng như điều khiển quá trình, các ứng dụng có các yêu
cầu xử lý khẩn cấp.
• Embedded Linux thiếu một chuẩn thống nhất và không phải là sản phẩm của
một nhà cung cấp duy nhất nên khả năng hỗ trợ kỹ thuật ít.

- Do thị trường của các sản phẩm nhúng tăng mạnh nên các nhà sản xuất ngày càng sử
dụng các hệ điều hành nhúng để bảo đảm sản phẩm có sức cạnh tranh và Embedded
Linux đang là sản phẩm hệ điều hành nhúng có uy tín chiếm vị trí số 1 trong những
năm tới.
- Phần mềm nhúng (Embedded Software): Phần mềm nhúng là phần mềm tạo nên phần
hồn, phần trí tuệ của các sản phẩm nhúng. Phần mềm nhúng ngày càng có tỷ lệ giá trị
cao trong giá trị của các sản phẩm nhúng.Hiện nay phần lớn các phần mềm nhúng nằm

Trang 29
trong các sản phẩm truyền thông và các sản phẩm điện tử tiêu dùng (consumer
electronics), tiếp đến là trong các sản phẩm ô tô, phương tiện vận chuyển, máy móc
thiết bị y tế, các thiết bị năng lượng, các thiết bị cảnh báo bảo vệ và các sản phẩm đo
và điều khiển.
- Để có thể tồn tại và phát triển, các sản phẩm công nghiệp và tiêu dùng cần phải thường
xuyên đổi mới và ngày càng có nhiều chức năng tiện dụng và thông minh hơn. Các
chức năng này phần lớn do các chương trình nhúng tạo nên. Phần mềm nhúng là một
lĩnh vực công nghệ then chốt cho sự phát triển kinh tế của nhiều quốc gia trên thế giới
như Nhật Bản, Hàn Quốc, Phần Lan và Trung quốc. Tại Mỹ có nhiều chương trình hỗ
trợ của Nhà nước để phát triển các hệ thống và phần mềm nhúng. Hàn Quốc có những
dự án lớn nhằm phát triển công nghệ phần mềm nhúng như các thiết bị gia dụng nối
mạng Internet, hệ thống phần mềm nhúng cho phát triển thành phố thông minh, dự án
phát triển ngành công nghiệp phần mềm nhúng, trung tâm hỗ trợ các ngành công
nghiệp hậu PC...Hàn Quốc cũng chấp nhận Embedded Linux như một hệ điều hành
chủ chốt trong việc phát triển các sản phẩm nhúng của mình. Thuỵ Điển coi phát triển
các HTN có tầm quan trọng chiến lược cho sự phát triển của đất nước. Phần Lan có
những chính sách quốc gia tích cực cho nghiên cứu phát triển các HTN đặc biệt là các
phần mềm nhúng. Những quốc gia này còn thành lập nhiều viện nghiên cứu và trung
tâm phát triển các HTN.
- Một thực tế khách quan là chúng ta mới nhìn thấy bề nổi của công nghệ thông tin còn
phần chìm của công nghệ thông tin chiếm hơn 99% số processor trên toàn cầu này
nằm trong các HTN thì còn ít được biết đến. Trong khi đó công nghệ thông tin và viễn
thông trên thế giới lại đang bước vào thời đại hậu PC - thời đại của các thiết bị, HTN
thông minh cao.
- Sự hội tụ của công nghệ truyền thông không dây băng rộng với thiết bị tính toán cầm
tay đang đưa công nghệ thông tin và truyền thông sang một thời đại mới - thời đại của
môi trường thông minh. Sức đẩy của công nghệ đưa công nghệ vi điện tử, các công
nghệ vi cơ điện, công nghệ sinh học hội tụ tạo nên các chip của công nghệ nano, là nền
tảng cho những thay đổi cơ bản trong công nghệ thông tin và truyền thông. Sức kéo
của thị trường đòi hỏi các thiết bị phải có nhiều chức năng thân thiện với người dùng,
có mức độ thông minh ngày càng cải thiện đưa đến vai trò và tầm quan trọng của các
HTN ngày càng cao trong nền kinh tế quốc dân.
- Phát triển các HTN và phần mềm nhúng là quốc sách của nhiều quốc gia trên thế giới,
nhất là vào giai đoạn hậu PC hiện nay.
- Chính phủ, các ngành công nghiệp, các viện nghiên cứu, trường đại học của Việt Nam
nên nhìn nhận lại chiến lược phát triển công nghệ thông tin và truyền thông của mình
và có những điều chỉnh phù hợp để có thể theo kịp, rút ngắn khoảng cách tụt hậu trong
lĩnh vực công nghệ thông tin và truyền thông đối với các nước trong khu vực và trên
thế giới trong quá trình hội nhập nền kinh tế toàn cầu không thể tránh khỏi hiện nay.

II. HỆ ĐIỀU HÀNH NHÚNG

1. Hệ điều hành

- Nguồn gốc ra đời của hệ điều hành là để đảm nhiệm vai trò trung gian để tương tác

Trang 30
trực tiếp với phần cứng của máy tính, phục vụ cho nhiều ứng dụng đa dạng. Các hệ
điều hành cung cấp một tập các chức năng cần thiết để cho phép các gói phần mềm
điều khiển phần cứng máy tính mà không cần phải can thiệp trực tiếp sâu. Hệ điều
hành của máy tính có thể thấy nó bao gồm các drivers cho các ngoại vi tích hợp với
máy tính như card màn hình, card âm thanh... Các công cụ để quản lý tài nguyên như
bộ nhớ và các thiết bị ngoại vi nói chung. Điều này tạo ra một giao diện rất thuận lợi
cho các ứng dụng và người sử dụng phát triển phần mềm trên các nền phần cứng đã
có. Đồng thời tránh được yêu cầu và hiểu biết sâu sắc về phần cứng và có thể phát
triển dựa trên các ngôn ngữ bậc cao.

- Hệ thống điều hành bản chất cũng là một loại phần mềm nhưng nó khác với các
loại phần mềm thông thường. Sự khác biệt điển hình là hệ thống điều hành được nạp
và thực thi đầu tiên khi hệ thống bắt đầu khởi động và được thực hiện trực tiếp bởi bộ
xử lý của hệ thống. Hệ thống điều hành được viết để phục vụ điều khiển bộ xử lý cũng
như các tài nguyên khác trong hệ thống bởi vì nó sẽ đảm nhiệm chức năng quản lý và
lập lịch các quá trình sử dụng CPU và cùng chia sẻ tài nguyên.

- Tóm lại, hệ điều hành thực chất chính là một giao diện quan trọng, giao tiếp trực
tiếp với tầng phần cứng cấp thấp phục vụ cho cả người sử dụng cũng như các chương
trình ứng dụng thực thi trên nền phần cứng hệ thống. Hơn nữa hệ điều hành còn có vai
trò quan trọng trong việc đảm nhiệm 3 tác vụ nguyên lý chính: (1) Quản lý quá trình,
(2) Quản lý tài nguyên, (3) Bảo vệ tài nguyên khỏi sự xâm phạm của các quá trình
thực thi sai.

2. Bộ nạp khởi tạo (Boot-loader)

- Thuật ngữ “bootstrap” bắt nguồn từ cách diễn đạt cổ xưa có nghĩa là tự mình vươn
lên bằng chính nỗ lực của bản thân “pulling yourself up by your own bootstraps”. Nó
đã được sử dụng như một thuật ngữ rất phổ biến để gọi tên một phần mềm thực thi
việc khởi tạo chương trình thực thi trên các nền vi điện tử khả trình nói chung.
Chương trình này thường rất nhỏ gọn và đảm nhiệm chức năng tiền hoạt động của hệ
điều hành. Cũng rất phổ biến hiện nay người ta cũng thường dùng thuật ngữ “boot‐
loader” (bộ nạp khởi tạo) thay vì “bootstrap”. Bộ nạp khởi tạo thực chất là một
chương trình nhỏ thực hiện trong hệ thống và đảm nhiệm chức năng cần thiết để đưa
hệ điều hành vào hoạt động. Trong các hệ nhúng, các lệnh được thực hiện đầu tiên
thường nằm trong các vùng nhớ ROM và thường thuộc loại chậm. Dó đó, một trong
những tác vụ phổ biến của bộ nạp khởi tạo là sao chép chương trình ứng dụng chính
(main program) vào trong vùng bộ nhớ nhanh trước khi chúng được thực hiện. Bộ nạp
khởi tạo cũng có nhiệm vụ khởi tạo vùng nhớ dữ liệu và các thanh ghi hệ thống trước
khi nhảy tới chương trình ứng dụng chính. Cũng có rất nhiều dạng khác nhau của bộ
nạp khởi tạo, từ dạng đơn giản đến phức tạp. Dạng đơn giản nhất có thể chỉ là một
lệnh nhảy tới chương trình ứng dụng chính ngay sau khi reset mà không thực hiện bất
kỳ một tác vụ khởi tạo hay nạp chương trình gì. Chương trình ứng dụng chính sẽ phải
tự thiết lập để thực thi tác vụ của mình. Các bộ nạp khởi tạo phức tạp hơn có thể thực
hiện nhiệm vụ chuẩn đoán bộ nhớ và khởi tạo hệ thống, kiểm tra chương trình và nạp
chúng trước khi cho bộ xử lý nhảy tới thực hiện chương trình ứng dụng chính.

Trang 31
- Thuộc tính nguyên lý cơ bản của bộ nạp khởi tạo.

- Trong môi trường phát triển hệ nhúng điển hình, nền phần cứng đích cần phát triển
được kết nối với trạm chủ (host) thông qua một giao diện truyền thông. Một môi
trường phát triển bao gồm một chương trình gỡ rối (debugger)

- Ví Dụ nhu Composer Studio của Texas Instrument, để cho phép người phát triển
chương trình nạp và thực hiện thử nghiệm các chương trình trên phần cứng đích. Một
số các công cụ hỗ trợ ví dụ như để thiết lập các điểm dừng (breakpoint)…và các
nhiệm vụ phụ trợ khác để bám sát trạng thái quá trình thực thi thời gian thực của
chương trình thử nghiệm. Điều này rất có ý nghĩa và tạo nên một sự dễ dàng hơn trong
quá trình phát triển và gỡ rối một chương trình ứng dụng mới cho nền phần cứng đích.

- Thông thường các ứng dụng được phát triển trong môi trường ngôn ngữ C thì
chương trình ứng dụng chính được thực thi và nằm trong phạm vi hàm main() phần
khởi tạo chương trình và nạp tiền thực hiện chương trình chính thường không tường
minh hoặc bị ẩn đi. Thực chất điều này chỉ đúng đối với những người phát triển mã
chương trình ứng dụng chính bằng ngôn ngữ bậc cao (đặc biệt cho các ứng dụng
không phải cho hệ nhúng) mà không cần phải quan tâm nhiều đến các tác vụ cơ sở
đảm nhiệm việc khởi tạo các thanh ghi hệ thống, ngăn xếp và dữ liệu…Điều này cũng
rất có ý nghĩa để tạo ra một cảm giác và môi trường phát triển thân thiện cho người
phát triển chương trình và chỉ cần tập trung phần thực hiện chức năng chính của hệ
thống. Tuy nhiên trong môi trường phát triển hệ thống nhúng việc thực thi chương
trình thường bắt đầu tại địa chỉ chương trình nơi bắt đầu tác vụ khởi tạo hệ thống trước
khi nhảy tới thực hiện chương trình chính main(). Quá trình này được bắt đầu thực
chất là thực thi một tác vụ ngắt kích hoạt bởi sự kiện reset.

- Boot‐loader cũng có nhiều dạng khác nhau. Hình trên mô tả một bộ nạp khởi tạo
cho một ứng dụng C nhúng. Trong ví dụ này vector RESET trỏ tới thủ tục c_int00 thực
hiện tác vụ khởi tạo. Ngoài việc khởi tạo các thanh ghi, ngăn xếp… các biến C cũng
cần được khởi tạo trước khi được thực thi. Quá trình này sẽ sao chép từ phần .cinit và
viết vào các địa chỉ dữ liệu tương ứng của chúng trong phần .bss. Sau khi hoàn thành
chương trình chính main() mới được gọi và bắt đầu thực thi. Trong ví dụ đơn giản này
bộ nạp khởi tạo tổ hợp vector RESET cùng với hàm khởi tạo c_int00 và giả thiết rằng
cả chương trình bộ nạp khởi tạo và chương trình ứng dụng chính đều nằm cùng trong
vùng nhớ vật lý non‐volatile. Trong các trường hợp hệ thống phức tạp hơn, bộ nạp
khởi tạo có thể bao hàm cả tác vụ sao chép chương trình chính vào trong vùng nhớ fast
volatile trước khi nó được gọi và thực thi. Bộ nạp khởi tạo cũng có thể đảm nhiệm cả
chức năng chuẩn đoán, gỡ rối và nâng cấp hệ thống nếu có. Chức năng chuẩn đoán có
thể chỉ là kiểm tra bộ nhớ, ngoại vi và độ tương thích tích hợp trong hệ thống. Chức
năng gỡ rối cũng có thể là một giao diện giám sát cung cấp thông tin và trạng thái thời
gian thực về hệ thống mà người ta vẫn thường biết tới với tên gọi là chương trình
monitoring. Việc nâng cấp hoặc thay đổi chương trình bộ nạp khởi tạo cũng có thể
được thực thi nhờ khả năng lập trình FLASH in‐circuit và nạp từ bộ nhớ ngoài thông
qua giao diện với trạm chủ hoặc chức năng tương tự.

3. Các yêu cầu chung

Trang 32
- Như chúng ta đã được biết đối với các hệ thống thời gian thực, yêu cầu thiết kế một
hệ điều hành khá đặc biệt. Hệ nhúng thời gian thực lại yêu cầu hệ điều hành phải thực
hiện với một nguồn tài nguyên thường rất hạn hẹp. Mặc dù kích thước bộ nhớ tích hợp
on‐chip sẽ có thể tăng lên trong tương lai nhưng với sự phát triển hiện nay hệ điều
hành cho các hệ nhúng chỉ nên cỡ khoảng nhỏ hơn 32 Kbytes.

- Hệ thống điều hành đảm nhiệm việc điều khiển các chức năng cơ bản của hệ thống
bao gồm chủ yếu là quản lý bộ nhớ, ngoại vi và vào ra giao tiếp với hệ thống phần
cứng. Một điểm khác biệt cơ bản như chúng ta đã biết về hệ điều hành với các phần
mềm khác là nó thực hiện chức năng điều khiển sự kiện thực thi trong hệ thống. Có
nghĩa là nó thực hiện các tác vụ theo mệnh lệnh yêu cầu từ các chương trình ứng dụng,
thiết bị vào ra và các sự kiện ngắt.

- Bốn nhân tố chính tác động trực tiếp tới quá trình thiết kế hệ điều hành là (1) khả
năng thực hiện, (2) năng lượng tiêu thụ, (3) giá thành, và (4) khả năng tương thích.
Hiện nay chúng ta cũng có thể bắt gặp rất nhiều hệ điều hành khác nhau đặc biệt cho
các hệ nhúng cũng vì sự tác động của 4 nhân tố nêu trên. Hầu hết chúng đều có kiểu
dạng và giao diện khá giống nhau nhưng cơ chế quản lý và thực thi các tác vụ bên
trong rất khác nhau. Mỗi hệ điều hành được thiết kế phục vụ trực tiếp các chức năng
đặc thù phần cứng của hệ nhúng và không dễ dàng so sánh được giữa chúng với nhau.

- Hai thành phần chính trong thiết kế hệ điều hành là: phần hạt nhân (kernel) và
các chương trình hệ thống. Hạt nhân nó chính là phần lõi của hệ điều hành. Nó được
sử dụng để phục vụ cho các bộ quản lý quá trình, bộ lập lịch bộ quản lý tài nguyên và
bộ quản lý vào ra. Phần hạt nhân đảm nhiệm chức năng lập lịch, đồng bộ và bảo vệ hệ
thống bởi việc sử dụng sai, xử lý ngắt…Chức năng điều khiển chính của nó là phục vụ
điều khiển phần cứng bao gồm ngắt, các thanh ghi điều khiển, các từ trạng thái và các
bộ định thời gian. Nó nạp các phần mềm điều khiển thiết bị để cung cấp các tiện ích
chung và phối hợp với các hoạt động vào ra với hệ thống. Phần hạt nhân có vai trò
điều khiển rất quan trọng để đảm bảo tất cả các phần của hệ thống có thể làm việc ổn
định và thống nhất.

- Hai kiến trúc thiết kế phần hạt nhân kinh điển nhất là kiến trúc vi hạt nhân và đơn
hạt nhân (monolithic). Các vi hạt nhân cung cấp các chức năng điều hành cơ bản cốt
lõi (thô) theo cơ chế các module tương đối độc lập đảm nhiệm các tác vụ cụ thể và
chuyển rời rất nhiều các dịch vụ điển hình điều hành hệ thống thực thi trong không
gian người sử dụng. Nhờ cơ chế này mà các dịch vụ có thể được khởi tạo hoặc cấu
hình lại mà không nhất thiết phải khởi tạo lại toàn bộ hệ thống. Kiến trúc vi hạt nhân
cung cấp độ an toàn cao bởi vì dịch vụ hệ thống chạy ở tầng người sử dụng với hạn
chế về truy nhập vào tài nguyên của hệ thống và có thể được giám sát. Kiến trúc vi hạt
nhân có thể được xây dựng một cách mềm dẻo để phù hợp với cấu hình phần cứng
khác nhau một cách llinh hoạt hơn so với kiểu kiến trúc hạt nhân monilithic. Tuy nhiên
do tính độc lập tương đối giữa các modul trong vi hạt nhân nên cần thiết phải có một
cơ chế trao đổi thông tin hay truyền thông giữa các modul đó vì vậy có thể là lý do
làm chậm tốc độ và giảm tính hiệu quả hoạt động của hệ thống. Đặc điểm nổi bật và
cốt lõi của kiến trúc vi hạt nhân là kích thước nhỏ và dễ dàng sửa đổi cũng như xây
dựng linh hoạt hơn. Các dịch vụ thực thi ở tầng trên của hạt nhân vì vậy đạt được độ
an toàn cao. Kiến trúc vi hạt nhân được phát triển mạnh mẽ trong các hệ thống đa xử
Trang 33
lý ví dụ như Windows 2000, Mach và QNX.

- Kiểu kiến trúc monolithic cung cấp tất cả chức năng/dịch vụ chính yếu thông qua
một qua trình xử lý đơn lẻ. Chính vì vậy kích thước của chúng thường lớn hơn kiểu
kiến trúc vi hạt nhân. Loại hình kiến trúc này thường được áp dụng chủ yếu cho các
phần cứng cụ thể mà hạt nhân monolithic có sự tương tác trực tiếp với phần cứng nhờ
vậy mà khả năng tối ưu cũng dễ dàng hơn so với áp dụng kiểu kiến trúc vi hạt nhân.
Chính vì vậy cũng là lý do tại sao kiến trúc monolithic không thể thay đổi mềm dẻo
linh hoạt như kiểu vi hạt nhân. Ví dụ điển hình về loại hình kiến trúc hạt nhân
monolithic bao gồm Linux, MacOS, và DOS.

- Vì hệ điều hành cũng đòi hỏi về tài nguyên và kiêm cả chức năng quản lý chúng vì
vậy người thiết kế cần phải nắm được thông tin về chúng một cách đầy đủ. Ví dụ như
đối với hệ thống điều hành cho Sun Microsystem Solaris yêu cầu tối thiểu không gian
bộ nhớ trên đĩa là 8MB; Windows 2000 yêu cầu khoảng gấp hai lần như vậy.

4. Hệ điều hành thời gian thực

- QNX là một ví dụ điển hình về hệ thống thời gian thực RTOS được thiết kế để đáp
ứng các yêu cầu về lập lịch rất khắt khe. QNX cũng chưa thực sự phù hợp để có thể
được thực thi cho các hệ thống nhúng bởi vì nó đòi hỏi dung lượng bộ nhớ không nhỏ
và thường phù hợp cho các ứng dụng đòi hỏi về độ an toàn và độ tin cậy lớn.

Hệ thống điều hành thời gian thực là hệ điều hành hỗ trợ khả năng xây dựng các hệ

thống thời gian thực.

Hệ thống điều hành với phần lõi là hạt nhân phải đảm nhiệm các tác vụ chính như sau:
Xử lý ngắt

 ƒ Lưu trữ ngữ cảnh chương trình tại thời điểm xuất hiện ngắt
 ƒ Nhận dạng và lựa chọn đúng bộ xử lý và phục vụ dịch vụ ngắt

Điều khiển quá trình

 ƒ Tạo và kết thúc quá trình/tác vụ


 ƒ Lập lịch và điều phối hoạt động hệ thống

 ƒ Định thời

Điều khiển ngoại vi

 ƒ Xử lý ngắt
 ƒ Khởi tạo giao tiếp vào ra

Trang 34
Tùy theo cơ chế thực hiện và xây dựng hoạt động của hạt nhân người ta phân loại một
số loại hình:

(1) Hệ thống thời gian thực nhỏ: Với loại này các phần mềm được phát triển mà không
cần có hệ điều hành, người lập trình phải tự quản lý và xử lý các vấn đề về điều khiển
hệ thống bao gồm:

 ƒ Xử lý ngắt
 ƒ Điều khiển quá trình/ tác vụ

 ƒ Quản lý bộ nhớ

(2) Công nghệ đa nhiệm

 ƒ Mỗi quá trình có một không gian bộ nhớ riêng


 ƒ Các quá trình phải được chia nhỏ thành các Thread cùng chia sẻ không
gian bộ nhớ

(3) Các dịch vụ cung cấp bởi hạt nhân

 ƒ Tạo và kết thúc quá trình/ tác vụ


 ƒ Truyền thống giữa các quá trình

 ƒ Các dịch vụ về định thời gian

 ƒ Một số các dịch vụ cung cấp hỗ trợ việc thực thi liên quan đến điều
khiển hệ thống

Đặc điểm cơ bản của hạt nhân thời gian thực điển hình:

 ƒ Kích thước nhỏ (lưu trữ toàn bộ trong ROM)


 ƒ Hệ thống ngắt

 ƒ Không nhất thiết phải có các cơ chế bảo vệ

 Chỉ hỗ trợ phần kiểm tra chương trình ứng dụng

 Tăng tốc độ chuyển ngữ cảnh và truyền thông giữa các quá trình

 Khi các quá trình ứng dụng đang thực hiện thì các yêu cầu hệ thống điều

hành có thể được thực hiện thông qua các lời gọi hàm thay vì sử dụng cơ

chế ngắt mềm

 Vi hạt nhân (Micro‐kernel): Bao gồm một tập nhỏ các dịch vụ hỗ trợ
 Quản lý quá trình

Trang 35
 Các dịch vụ truyền thông giữa các quá trình nếu cần

 Các phần mềm điều khiển thiết bị là các quá trình ứng dụng

Hạt nhân điển hình cơ bản

 ƒ Loại hạt nhân đơn giản nhất là một vòng lặp vô hạn thăm dò các sự
kiện xuất hiện trong hệ thống và phản ứng lại theo sự thay đổi nếu có.
 ƒ Với một bộ xử lý cấu hình nhỏ nhất, không phải lúc nào nó cũng có thể
lưu cất

ngữ cảnh vì không thể thay đổi con trỏ ngăn xếp hoặc vùng ngăn xếp rất hạn chế.

 ƒ Thay vì sử dụng các thanh ghi thiết bị, vòng lặp thăm dò có thể giám
sát các

biến mà chịu sự thay đổi cập nhật bởi các bộ xử lý ngắt.

 ƒ Hạt nhân có thể được xây dựng sao cho tất cả các tín hiệu logic được
điều khiển bởi vòng lặp và nhịp được điều khiển bởi các ngắt.
 ƒ Các tác vụ lớn cần nhiều thời gian thực hiện có thể được chia nhỏ thành
các tác

vụ nhỏ và được thực hiện tại các thời điểm khác nhau nhờ vào cơ chế chuyển và sử
dụng bộ đệm

Các hạt nhân thực thi theo cơ chế ngắt rất giống với loại hạt nhân thực hiện theo cơ
chế vòng lặp thăm dò. Nó xử lý tất cả các tác vụ thông qua các dịch vụ ngắt.

ƒ Các hạt nhân lớn và phức tạp hơn sẽ bao gồm một số các dịch vụ phụ phục vụ

cho việc truyền thông giữa các quá trình. Và nếu được bổ sung đầy đủ nó sẽ trở

thành một hệ điều hành đầy đủ.

Các kiểu loại hạt nhân cơ bản

ƒ Hạt nhân thực hiện vòng lặp thăm dò

ƒ Hạt nhân thực hiện theo cơ chế ngắt

ƒ Hạt nhân quá trình vận hành quá trình

Trang 36
Việc lựa chọn loại hạt nhân nào hoàn toàn tùy thuộc vào các bộ xử lý và kích thước
phần mềm, tuy nhiên riêng loại hạt nhân vận hành theo quá trình không phù hợp với
các bộ xử lý nhỏ.

Hạt nhân quá trình

Các hạt nhân quá trình rõ ràng là phức tạp hơn các hạt nhân thực hiện theo cơ chế
thăm dò và điều khiển ngắt. Các đường truyền tín hiệu logic bên trong các quá trình và
các dịch vụ ngắt được tích hợp và thực hiện thông qua việc truyền dữ liệu.

Hạt nhân sẽ phải đảm nhiệm chức năng lập lịch cho các quá trình theo đúng mô hình
trạng thái.

 ƒ RUN: quá trình được thực hiện


 ƒ WAIT: các quá trình chờ một sự kiện hoặc tín hiệu vào ra kích hoạt quá
trình

 ƒ READY: các quá trình sẵn sàng được thực hiện

Các phần tử thuộc tính của một quá trình: Các phần tử này cần thiết để phục vụ cho
việc lập lịch. Ví dụ đối với cơ chế lập lịch theo mức độ ưu tiên sẽ yêu cầu thông tin
sau với mỗi quá trình:

Tên (địa chỉ bộ nhớ của phần tử quá trình)

Trạng thái: RUN, WAIT, READY

Mức độ ưu tiên

Ngữ cảnh (dùng con trỏ để quản lý lưu cất thông tin trong ngăn xếp)

CHƯƠNG II : NGHIÊN CỨU CHÍP ARM

I. Đôi nét về lịch sử hình thành và phát triển:

- Ngày 26/4/1985, mẫu sản phẩm ARM đầu tiên sản xuất tại công ty kĩ thuật VLSI,
SanJose, bang Califonia được chuyển tới trung tâm máy tính Acorn ở Cambridge, Anh
Quốc. Một vài giờ sau, chương trình thử nghiệm đầu tiên thành công và họ đã khui
sâm banh ăn mừng!

Trang 37
- Nửa thập niên sau đó, ARM được phát triển rất nhanh chóng để làm nhân máy tính
để bàn của Acorn, nền tảng cho các máy tính hỗ trợ giáo dục ở Anh. Trong thập niên
1990, dưới sự phát triển của Acorn Limited, ARM đã thành một thương hiệu đứng đầu
thế giới về các ứng dụng sản phẩm nhúng đòi hỏi tính năng cao, sử dụng năng lượng ít
và giá thành thấp.

- Chính nhờ sự nổi trội về thị phần đã thúc đẩy ARM liên tục được phát triển và cho ra
nhiều phiên bản mới. Những thành công quan trọng trong việc phát triển ARM ở thập niên
sau này:

o Giới thiệu ý tưởng về định dạng các chỉ lệnh được nén lại (thumb) cho phép
tiết kiệm năng lượng và giá thành ở những hệ thống nhỏ.

o Giới thiệu họ điều khiển ARM9, ARM10 và ‘Strong ARM’

o Phát triển môi trường làm việc ảo của ARM trên PC.

o Các ứng dụng cho hệ thống nhúng dựa trên nhân xử lý ARM ngày càng trở

nên rộng rãi.

- Hầu hết các nguyên lý của hệ thống trên chip (Systems on chip-SoC) và cách thiết
kế bộ xử lý hiện đại được sử dụng trong ARM, ARM còn đưa ra một số khái niệm
mới <như giải nén động các dòng lệnh>. Việc sử dụng 3 trạng thái nhận lệnh-giải mã-
thực thi trong mỗi chu kì máy mang tính quy phạm để thiết kế các hệ thống xử lý thực.
Do đó, nhân xử lý ARM được sử dụng rộng rãi trong các hệ thống phức tạp.

II. Sơ lược về thiết kế nhân điều khiển:

- Việc thiết kế các nhân điều khiển đa dụng vẫn là mong ước của hầu hết kĩ sư. Điều
đó, đòi hỏi những nghiên cứu tỉ mỉ, chi tiết, đầy mâu thuẫn và cả sự thỏa hiệp. Trong
phần này, ta sẽ bàn về một số khái niệm xung quanh việc thiết kế phần cứng cho nhân
điều khiển, thiết kế tập lệnh, cấu trúc máy tính số thực thi lệnh dạng stored-program.

1. Đôi nét về thiết kế phần cứng:

Máy tính là một thiết bị hoạt động ở tốc độ rất cao. Những vi xử lý hiện đại có thể bao
gồm đến vài triệu transistor <hiện tại đang sử dụng công nghệ 90nm> và chúng đóng
ngắt đến hàng trăm triệu lần trong một giây. Tất cả chúng (Transistor) đều phải hoàn
hảo, chẳng có Transistor nào được phép sai lệch hoặc hoạt động ngẫu nhiên, một sai
lệch nhỏ của dù chỉ

1 Transistor cũng có thể gây sai lệch cho cả hệ thống! Bạn cứ tưởng tượng-so sánh
một đội quân tinh nhuệ thiện chiến được huấn luyện công phu dàn quân khắp chiến
tuyến, bất kì 1 vị trí nào không chiến đấu được cũng làm cả đội quân thất thủ! <hoặc
đơn giản hơn, bạn cứ nghĩ là mình phải học qua 5-6 môn tiên quyết mới có thể làm
luận văn tốt nghiệp-nếu rớt bất kì môn nào cũng không được nhận đề tài!> Như thế, ta
thấy sự phức tạp đến mức nào của một

Trang 38
vi điều khiển!

Tuy nhiên, không phải công nghệ bắt đầu vào chế tạo bán dẫn kích thước micro, nano
ngay được, đấy là một quá trình phát triển lâu dài, từ ống chân không, một Transistor,
vài Transistor, mạch tích hợp (IC) đến mạch tích hợp rất cao (VLSI) với vài triệu
Transistor hiệu ứng trường trên mỗi chip đơn lẻ!

2. Cấu trúc máy tính số sử dụng chương trình lưu trữ:<Stored-program>

Xem hình sau:

Hình 1: Mô hình máy tính số sử dụng chương trình lưu trữ

Ta chú thích một cách dễ hiểu nguyên lý hoạt động của bộ xử lý dạng này: <dựa trên
mô hình có PC>

o Bộ xử lý đưa ra địa chỉ kế tiếp cho thanh ghi (PC) truy cập vào vùng nhớ, nhận chỉ
lệnh thực thi, chỉ lệnh thực thi chứa các địa chỉ của dữ liệu chương trình <sẽ phân tích
ở phần sau>, thanh ghi dùng các địa chỉ này để truy cập vào vùng nhớ để lấy dữ liệu,
dữ liệu đấy được dùng để xử lý trong nhân tính toán <qua bộ ALU chẳng hạn>, kết
quả cuối cùng sẽ được ghi ngược lại bộ nhớ bằng địa chỉ định trước hoặc địa chỉ trung
gian, hoặc qua thanh ghi tích lũy.

III. Dạng đơn giản của bộ xử lý:

Có thể gồm những phần cơ bản sau:

i. Program Counter (PC): thanh ghi giữ địa chỉ của chỉ lệnh hiện tại. ii. Thanh
ghi tích lũy (ACC): giữ giá trị dữ liệu khi đang làm việc.

iii. Đơn vị xử lý số học (ALU): thực thi các lệnh nhị phân như cộng, trừ, gia tăng…

iv. Thanh ghi chỉ lệnh (IR): giữ chỉ lệnh hiện tại đang thực thi.

Nhân xử lý đơn giản MU0 được phát triển đầu tiên ở đại học Manchester-Anh Quốc là
Trang 39
nhân xử lý có chỉ lệnh dài 16bit, với 12bit địa chỉ <8kBytes> và 4 bit opcode; cấu trúc
chuẩn cho chỉ lệnh có dạng:

Hình 2: Cấu trúc chuẩn cho chỉ lệnh của MU0

Ví dụ đơn giản về thiết kế đường truyền dữ liệu<datapath> của nhân xử lý MU0:

Hình 3: Ví dụ về đường truyền dữ liệu của MU0

Ta đang xét việc thiết kế ở cấp chuyển đổi mức thanh ghi(RTL): PC chỉ đến chỉ lệnh
cần thực thi, load vào IR, giá trị chứa trong IR chỉ đến vùng địa chỉ ô nhớ, nhận giá trị,
kết hợp với giá trị đang chứa trong ACC qua đơn vị xử lý ALU để tạo giá trị mới, chứa
vào ACC. Mỗi chỉ lệnh như vậy, tùy vào số lần truy cập ô nhớ mà tốn số chu kì xung
nhịp tương đương. Sau mỗi chỉ lệnh thực thi, PC sẽ được tăng thêm.

3. Sơ qua về cách thiết kế cấu trúc tập lệnh:

A. Cấu trúc chỉ lệnh có 4 địa chỉ:

Hình 4: Cấu trúc chỉ lệnh có 4 địa chỉ

ADD d, s1, s2, next_i ;d := s1 +s2

B. Cấu trúc chỉ lệnh có 3 địa chỉ:

Trang 40
Hình 5: Cấu trúc chỉ lệnh có 3 địa chỉ

ADD d, s1, s2 ; d := s1 + s2

C. Cấu trúc chỉ lệnh có 2 địa chỉ:

Hình 6: Cấu trúc chỉ lệnh có 2 địa chỉ

ADD d, s1 ; d := d + s1

D. Cấu trúc chỉ lệnh có 1 địa chỉ:

Hình 7: Cấu trúc chỉ lệnh có 1 địa chỉ

ADD s1 ; accumulator := accumulator + s1

E. Cấu trúc chỉ lệnh không truy cập địa chỉ:

Hình 8: Cấu trúc chỉ lệnh không truy cập địa chỉ

ADD ; top_of_stack := top_of_stack +next_on_stack

F. Các chế độ định địa chỉ:

Các chế độ định địa chỉ cơ bản, bạn tham khảo ở sách Vi xử lý của thầy Hồ Trung Mỹ.
Có thể tùy nhà sản xuất đưa ra 8 hoặc 9 chế độ khác nhau. Tuy nhiên, nó cùng một
mức nền như nhau.

G. Cấu trúc lệnh CISC và RISC:

Máy tính chỉ hiểu các mức 0/1 trên mỗi transistor cụ thể, người sử dụng muốn thực
hiện một chương trình nào đấy, phải nạp các mã lệnh 0-1 vào bộ nhớ cho máy tính. Có
3 cách cơ bản để làm việc ấy:

Trang 41
1. Viết ngay dạng mã máy 0-1 và nạp vào bộ nhớ. Cách này rất khó thực thi.

2. Viết dạng tên gợi nhớ bằng hợp ngữ, sau đó biên dịch ra mã máy, cấp này cũng rất
gần với ngôn ngữ máy và cũng khó thực hiện với các chương trình phức tạp. Tuy
nhiên, cấu trúc gọn nhẹ.

3. Viết bằng một ngôn ngữ cấp cao, sau đó dùng một trình biên dịch <compiler> để
dịch ra mã máy. Cách này tuy dễ với người viết chương trình nhưng cũng sẽ làm
chương trình có dung lượng lớn hơn nếu viết bằng ASM. Và thách thức là làm sao các
nhà sản xuất phần mềm, phần cứng bắt tay nhau để chương trình biên dịch này thật
chuẩn tắc, nhỏ gọn, không tạo nhiều code trung gian.

H. Nêu vấn đề:

Trong suốt thập niên 1980, các nhà thiết kế cố gắng thu hẹp khoảng cách giữa ngôn
ngữ cấp cao của con người và ngôn ngữ máy, họ đã đưa ra cấu trúc các chỉ lệnh phức
tạp- CISC, có các chế độ định địa chỉ khác nhau, mỗi lệnh thực thi cần nhiều lần định
địa chỉ để

lấy dữ liệu, và do đó, tốn nhiều chu kì xung nhịp cho mỗi chỉ lệnh.

Nếu việc giảm thiểu ranh giới giữa tập lệnh của vi điều khiển và ngôn ngữ cấp cao
không phải là một cách hay để máy tính hoạt động hiệu quả, các nhà thiết kế phải làm
sao để tối ưu tốc độ xử lý?

K. Thiết kế tập lệnh dựa trên CISC và RISC:

Nếu muốn biết cách làm để vi xử lý hoạt động nhanh hơn, ta phải biết vi xử lý dùng
hầu hết thời gian của chúng vào việc gì? Chúng ta dễ nghĩ rằng: ‘Vi xử lý tất nhiên
dùng hầu hết thời gian của nó để tính toán’; nghĩa là thời gian hầu hết ở bộ ALU. Thật
ra, theo thống kê thì suy đoán này hoàn toàn sai lầm:

Loại chỉ lệnh Sử dụng

Chuyển dữ liệu 43%

Điều khiển dòng chảy <lệnh> 23%

Tính toán số học 15%

So sánh 13%

Phép toán logic 5%

Khác 1%

i. Chu kì lệnh:

Trang 42
Thông thường, để thực thi một chỉ lệnh, quá trình có thể bao gồm các bước sau:

1. Nhận lệnh từ bộ nhớ <fetch>

2. Giải mã lệnh, xác định các tác động cần có và kích thước lệnh <decode>

3. Truy cập các toán hạng có thể được yêu cầu từ thanh ghi <reg>

4. Kết hợp toán hạng đấy với để tạo thành kết quả hay địa chỉ bộ nhớ <ALU>

5. Truy cập vào bộ nhớ cho toán hạng dữ liệu nếu cần thiết <mem>

6. Viết kết quả ngược lại băng thanh ghi <res>

ii. So sánh CISC và RISC:

ii.a. Kiến trúc tập lệnh RISC:

Có các đặc điểm quan trọng sau:

◊ Kích thước các chỉ lệnh là cố định <32 bit> với chỉ một vài định dạng.

<CISC có kích thước tập lệnh thay đổi với rất nhiều định dạng khác nhau>

◊ Sử dụng kiến trúc load-store các chỉ lệnh xử lý dữ liệu hoạt động chỉ trong
thanh ghi và cách ly với các chỉ lệnh truy cập bộ nhớ <CISC cho phép giá trị trong bộ
nhớ được dùng như như toán hạng trong các chỉ lệnh xử lý dữ liệu>

◊ Gồm một số lớn các thanh ghi đa dụng 32 bit, cho phép cấu trúc load- store
hoạt động hiệu quả. <CISC có rất nhiều thanh ghi, nhưng hầu hết đề chỉ để sử dụng
cho một mục đích riêng biệt nào đấy-ví dụ các thanh ghi dữ liệu và địa chỉ trong
Motorola MC68000>

ii.b. Tổ chức tập lệnh RISC:

◊ Giải mã các chỉ lệnh logic bằng kết nối phần cứng <CISC sử dụng rất nhiều
code trong ROM giải mã các chỉ lệnh>

◊ Thực thi chỉ lệnh theo cấu trúc dòng chảy <xem hình dưới> <CISC ít khi cho
phép các dòng lệnh thực thi kiểu này, chúng phải tuần tự hết dòng lệnh này mới đến
dòng lệnh khác>

Trang 43
Hình 9: Thực thi lệnh theo cấu trúc dòng chảy

◊ Một chỉ lệnh thực thi trong 1 chu kì xung nhịp <CISC cần nhiều chu kì xung
nhịp để hoàn thành một lệnh>

ii.c. Điểm mạnh của bộ xử lý dùng tập lệnh RISC:

◊ Kích thước miếng bán dẫn nhỏ hơn: bộ xử lý đơn giản đòi hỏi ít transistor hơn,
do đó, kích thước cần dùng nhỏ lại, dành vùng diện tích trống để tăng các chức năng
như bộ nhớ cache, chức năng quản lý bộ nhớ,

..vv…

◊ Thời gian phát triển một sản phẩm ngắn hơn <do kĩ thuật đơn giản hơn>

◊ Cấu hình mạnh hơn: điều này có vẻ khó tin, tuy nhiên, để ý các lập luận:

• Những vật nhỏ hơn thì có tần số hoạt động tự nhiên lớn hơn

<côn trùng đập cánh nhanh hơn bồ câu, bồ câu đập cánh nhanh hơn đại bàng…>

• Khi ta đặt ra các chỉ lệnh phức tạp, tuy nó gần gũi với ngôn ngữ

cấp cao, nhưng như thế, vô tình cũng làm các chỉ lệnh khác phức tạp lên, và để thực
thi một chỉ lệnh như vậy cần tốn nhiều chu kì xung nhịp. Trong khi đó, nếu dùng RISC
chỉ mất một chu kì xung nhịp cho mỗi lệnh, khi ta phân nhỏ vấn đề phức tạp thành các
vấn đề đơn giản thì cách giải quyết sẽ tốt hơn.

ii.d. Tần số hoạt động tối đa của RISC và CISC:

◊ Như ví von ở trên, RISC nhỉnh hơn, tuy nhiên, cũng có giai đoạn CISC có tần
số xung nhịp lớn hơn RISC, mặc dù vậy, thời gian để hoàn tất một lệnh của CISC cũng
chậm hơn RISC do 1 chỉ lệnh của CISC cần nhiều chu kì xung nhịp để hoàn tất.

ii.e. Những điểm bất tiện của RISC:

◊ Không phải RISC chỉ có điều thuận lợi, nó cũng có một vài bất cập, mà cụ thể

Trang 44
là:

• Mã lệnh của RISC không phong phú bằng CISC.

• Không thể thực thi các mã lệnh của x86.

◊ Điểm bất tiện thứ 2 được kể trên khó để sửa đổi, phải dùng các phần mềm hỗ
trợ nền cơ sở cho RISC, tuy nhiên, với máy tính của IBM, có thể bị từ chối.

◊ Điểm bất tiện thứ nhất phát sinh vì cấu trúc tập lệnh của RISC là cố định, nó sẽ
trở nên nghiêm trọng<làm chậm hệ thống> nếu phải giải quyết các công việc phức tạp.
Nếu không có bộ nhớ phụ cache sẽ dẫn tới việc cần nhiều băng thông của bộ nhớ
chính, điều đó làm tiêu tốn nhiều năng lượng.

III. Kiến trúc tổ chức của ARM:

1. Sơ lược về tên gọi:

ARM lúc đầu được đặt tên theo công ty Acorn. ARM=Acorn RISC Machine (dịch
môm na là chiếc máy sử dụng tập lệnh đơn giản của công ty Acorn). Sau này, do có
thêm nhiều công ty cùng phát triển và một số lý do khác, người ta thống nhất gọi
ARM=Advance

RISC Machine.

2. Sự kế thừa cấu trúc:

Với các mô hình RISC của Berkeley RISC I và II, Stanford MIPS, ARM kế thừa:

3. Cấu trúc cơ bản:

ƒ Cấu trúc load-store

ƒ Chỉ lệnh có chiều dài cố định <32bit>

ƒ Cấu trúc chỉ lệnh có 3 địa chỉ.

ƒ Thay vì chỉ dùng 1 chu kì xung nhịp cho tất cả các chỉ lệnh, ARM thiết kế

để sao cho tối giản số chu kì xung nhịp cho một chỉ lệnh, do đó tăng được

sự phức tạp cho các chỉ lệnh đơn lẻ.

4. Mô hình thiết kế ARM:

Để phục vụ mục đích của người dùng: r0-r14: 15 thanh ghi đa dụng, r15 là thanh ghi
PC, thanh ghi trạng thái chương trình hiện tại (CPSR). Các thanh ghi khác được giữ lại

Trang 45
cho hệ thống <thanh ghi chứa các ngắt chẳng hạn>

Hình 10: Các thanh ghi của ARM

i. Thanh ghi trạng thái chương trình hiện tại(CPSR)

Hình 11: Cấu trúc của thanh ghi trạng thái chương trình hiện tại

Thanh ghi CPSR được người dùng sử dụng chứa các bit điều kiện.

• N: Negative- cờ này được bật khi bit cao nhất của kết quả xử lý ALU bằng 1.

• Z: Zero- cờ này được bật khi kết quả cuối cùng trong ALU bằng 0.

• C: Carry- cờ này được bật khi kết quả cuối cùng trong ALU lớn hơn giá trị
32bit và tràn.

• V: Overflow-cờ báo tràn sang bit dấu.

5. Cấu trúc load-store:

Cũng như hầu hết các bộ xử lý dùng tập lênh RISC khác, ARM cũng sử dụng cấu trúc
load-store. Điều đó có nghĩa là: tất cả các chỉ lệnh <cộng, trừ…> đều được thực hiện
trên thanh ghi. Chỉ có lệnh copy giá trị từ bộ nhớ vào thanh ghi<load> hoặc chép lại

Trang 46
giá trị từ thanh ghi vào bộ nhớ<store> mới có ảnh hưởng tới bộ nhớ.

Các bộ xử lý CISC cho phép giá trị trên thanh ghi có thể cộng với giá trị trong bộ nhớ,
đôi khi còn cho phép giá trị trên bộ nhớ có thể cộng với giá trị trên thanh ghi. ARM
không hỗ trợ cấu trúc lệnh dạng ‘từ bộ nhớ đến bộ nhớ’. Vì thế, tất cả các lệnh của
ARM có thể thuộc 1 trong 3 loại sau:

1. Chỉ lệnh xử lý dữ liệu: chỉ thay đổi giá trị trên thanh ghi.

2. Chỉ lệnh truyền dữ liệu: copy giá trị từ thanh ghi vào bộ nhớ và chép giá trị từ bộ
nhớ vào thanh ghi.<load-store>

3. Chỉ lệnh điều khiển dòng lệnh: Bình thường, ta thực thi các chỉ lệnh chứa trong
một vùng nhớ liên tiếp, chỉ lệnh điều khiển dòng lệnh cho phép chuyển sang các địa
chỉ khác nhau khi thực thi lệnh, tới những nhánh cố định, <lệnh rẽ nhánh> hoặc là lưu
và trở lại địa chỉ để phục hồi chuỗi lệnh ban đầu <chỉ lệnh rẽ nhánh và kết nối> hay là
đè lên vùng code của hệ thống <gọi giám sát-ngắt phần mềm>.

4. Tập lệnh của ARM:

Tất cả lệnh của ARM đều là 32bit:

• Có cấu trúc dạng load-store.

• Cấu trúc lệnh định dạng 3 địa chỉ (nghĩa là địa chỉ của 2 toán hạng nguồn và
toán hạng đích đều là các địa chỉ riêng biệt)

• Mỗi chỉ lệnh thực thi một điều kiện.

• Có cả chỉ lệnh load-store nhiều thanh ghi đồng thời.

• Có khả năng dịch bit kết hợp với thực thi lệnh ALU trong chỉ 1 chu kì máy.

• Thumb code.

6. ARM C-Compiler:

Trang 47
Hình 12: Cấu trúc của bộ công cụ hỗ trợ phát triển.

7. Lập trình hợp ngữ cho ARM: D.I.

Lệnh xử lý dữ liệu:

Lệnh xử lý dữ liệu của ARM cho phép thực thi các lệnh số học, logic trên các thanh
ghi.

Những phép toán dạng này có 2 tóan tử tham gia và sinh ra 1 kết quả duy nhất. Trong
2 tóan hạng nguồn, toán hạng thứ 2 có thể là thanh ghi, giá trị tức thời, tóan hạng này
có thể được dịch bit trước khi tham gia vào phép tính số học mà vẫn tính là trong 1
chu kì máy.

+Tất cả các toán hạng đều có chiều dài 32bit.

+Nếu là 1 kết quả thì nó cũng có chiều dài là 32bit <trừ trường hợp nhân sinh ra kết
quả

dài 64bit>

+ARM sử dụng cấu trúc chỉ lệnh có 3 địa chỉ.

• Các lệnh tóan học.

Trang 48
Hình 13: Các lệnh toán học

• Các lệnh logic.

Hình 14: Các lệnh logic

• Tác vụ chuyển giá trị các thanh ghi.

Hình 15: Tác vụ chuyển các giá trị của thanh ghi

Chỉ lệnh chuyển dữ liệu cũng tương tự như lệnh số học, có các dạng như chuyển dữ
liệu giữa

2 thanh ghi, giữa 1 thanh ghi và 1 địa chỉ trực tiếp.

o Chỉ lệnh load và store 1 thanh ghi.

o Chỉ lệnh load và store nhiều thanh ghi.

o Chỉ lệnh trao đổi giá trị các thanh ghi

Định địa chỉ gián tiếp qua thanh ghi:

o Ví dụ:

Trang 49
LDR r0, [r1] ;r0 := mem32[r1]

STR r0, [r1] ;mem32[r1] := r0

D.IV. Khởi tạo địa chỉ pointer: <r15=PC> D.V. Định địa chỉ stack.

D.VI. Các chỉ lệnh điều khiển dòng lệnh:

o Chỉ lệnh rẽ nhánh.

o Nhánh điều kiện.

..vv…

Do các phần này tương đối đơn giản, vả lại tôi cũng không muốn chú trọng vào nên ta
lược bỏ qua. Bạn xem thêm ở sách tiếng Anh.

IV. Viết chương trình đơn giản:

1. Xét chương trình sau:

AREA HelloW,CODE,READONLY ;Khai bao vung code

SWI_SwiteC EQU &0 ;Ki tu xuat o R0

SWI_Exit EQU &11 ;Ket thuc chuong trinh

ENTRY ;Diem bao hieu vao chuong trinh START ADR

R1,TEXT ;R1 chi den vung dia chi cua TEXT LOOP LDRB R0,[R1],#1
;R0:=[R1];R1:=R1+1

CMP R0,#0 ;R0 chi toi gia tri cuoi hay chua

SWINE SWI_WriteC ;Neu chua ket thuc in

BNE LOOP ;thi quay nguoc lai vong lap

SWI SWI_Exit ;Quay nguoc ve lai chuong trinh quan ly

TEXT ="Hello World",&0a,&0d,0 ;Khai bao doan Text

END ;Chuong trinh ket thuc

;Do không chú trọng tới ASM nên lược qua phần này.

Trang 50
E. Cách tổ chức và thực thi tập lệnh của ARM:

Cách tổ chức của nhân ARM không thay đổi nhiều trong khoảng 1983-1995:đến
ARM7- sử dụng dòng chảy lệnh sử dụng 3 tác vụ. Từ 1995 trở về sau, đã xuất hiện
một vài nhân ARM mới được giới thiệu có dòng chảy lệnh sử dụng 5 tác vụ.

2. Dòng chảy lệnh có 3 tác vụ:

Fetch-decode-Excute<nhận lệnh, giải mã, thực thi>

Hình 17: Chỉ lệnh một chu kì máy sử dụng dòng chảy lệnh có 3 tác vụ

Hình 18: Dòng chảy lệnh 3 tác vụ áp dụng trong trường hợp 1chỉ lệnh có nhiều chu kì
máy

3. Dòng chảy lệnh có 5 tác vụ:

<Fetch-decode-excute-buffer/data-write back>

Trang 51
Thời gian để bộ xử lý thực thi một chương trình: Tprog

= Ninst ×CPI <Công thức 1>.

fclk

Trong đó CPI là số xung nhịp trung bình cần cho mỗi chỉ lệnh, Ninst là số chỉ lệnh
thực thi một chương trình<là cố định>, fclk là tần số xung nhịp. Với công thức trên, ta
có 2 cách để giảm thời gian thực thi một chương trình:

+Tăng tần số xung nhịp: điều này đòi hỏi trạng thái của mỗi tác vụ trong dòng chảy
lệnh là

đơn giản, và, do đó, số tác vụ sẽ tăng thêm.

+Giảm CPI: điều này đòi hỏi mỗi chỉ lệnh cần nhiều dòng chảy lệnh hơn với tác vụ
không

đổi, hoặc các tác vụ cần đơn giản hơn, hoặc kết hợp cả 2 lại với nhau.

ÆARM đưa ra cấu trúc mỗi dòng chảy lệnh có 5 tác vụ, với cách mô phỏng tựa như
cấu trúc

von Neumann, với vùng nhớ dữ liệu và chương trình riêng biệt. Từ cấu trúc lệnh có 3
tác vụ

được chia nhỏ lại thành 5 tác vụ cũng làm cho mỗi chu kì xung nhịp sẽ thực hiện một
công việc đơn giản hơn ở mỗi trạm, cho phép có thể tăng chu kì xung nhịp của hệ
thống. Sự tách

rời bộ nhớ chương trình và bộ nhớ dữ liệu <cache chứa các chỉ lệnh I-cache và cache
chứa dữ

liệu D-cache là tách rời nhau> cũng cho phép giảm đáng kể tài nguyên chiếm của mỗi
chỉ

lệnh trong một chu kì máy.

<ta có thể quay lại ví dụ ví von ban đầu với đơn hàng đặt ngay phòng làm việc của
người quản lý>

Trang 52
Hình 19: Cách tổ chức dòng chảy lệnh có 5 tác vụ với ARM9TDMI

4. Tập lệnh của ARM:


5. Kiểu dữ liệu:

ARM hỗ trợ 6 loại dữ liệu:

Trang 53
+8 bit có dấu và không dấu.

+16 bit có dấu và không dấu.

+32 bit có dấu và không dấu.

Như phần trên đề cập, các tóan tử của ARM có 32 bit, bởi vậy, khi làm việc với các dữ
liệu ngắn hơn,các bit cao của toán tử sẽ được thay thế bằng bit ‘0’.

6. Chế độ hoạt động:

Bảng 2: Các chế độ hoạt động của ARM và sử dụng thanh ghi

Bảng 3: Các địa chỉ dùng cho hệ thống

7. Thực thi các điều kiện:

Điều kiện cần thực thi nằm trên 4 bit cao nhất của chỉ lệnh.

Hình 20: Vị trí các bit điều kiện trong chỉ lệnh 32bit

Tổ hợp các điều kiện này được quyết định bởi các bit <N,Z,C,V> nằm trong thanh ghi
trạng thái chương trình hiện tại <CPSR>

Opcode

[31:28]

Mnemonic

extension Giải thích Trạng thái cờ để thực thi

Trang 54
0000 EQ Bằng 0 hoặc bằng nhau Z=1

0001 NE Không bằng Z=0

0010 CS/HS Có nhớ, cao hơn số không có dấu C=1

0011 CC/LOXóa cờ nhớ, thấp hơn số có dấu C=0

0100 Ml Trừ/âmN=1

0101 PL Cộng/dương hay zero N=0

0110 VS Cờ tràn V=1

0111 VC Không tràn V=0

1000 HI Lớn hơn số không dấu C=1 và Z=0

1001 LS Bé hơn hoặc bằng số không dấu C=0 hoặc Z =1

1010 GE Lớn hơn hoạc bàng số có dấu N=V

1011 LT Nhỏ hơn số có dấu N≠V

1100 GT Lớn hơn số có dấu Z=0 và N=V

1101 LE- Nhỏ hơn hoặc bằng số có dấu Z=1 hoặc N≠V

1110 AL Luôn luôn Tùy định

1111 NV Không được sử dụng! Không tồn tại

F.IV. Ngắt phần mềm<SWI>:

Các chỉ lệnh ngắt phần mềm gọi chương trình giám sát. Nó đưa vi xử lý vào chế độ

giám sát tại địa chỉ 0x0008.

Hình 21: Ngắt phần mềm

Trường 24bit của vector này không ảnh hưởng tới hoạt động các chỉ lệnh nhưng có thể
tác động tới code hệ thống. Nếu vào được chế độ giám sát, vi xử lý sẽ:

Trang 55
+Lưu địa chỉ PC vào thanh ghi r14.

+Lưu giá trị thanh ghi trạng thái chương trình chương trình hiện tại vào thanh ghi
SPSR

+Vào chế độ giám sát và không cho phép các ngắt bình thường xảy ra <nhưng các
ngắt nhanh vẫn còn tác động> bằng cách gán CPSR[4:0]=100112 và CPSR[7]=1.

+gán PC=0x08 và thực thi các chỉ lệnh tại đấy.

Để trở về lại chương trình bình thường sau SWI:

+Copy giá trị thanh ghi r14 vào PC.

+Lấy lại giá trị CPSR từ SPSR

7. Lệnh xử lý dữ liệu:

8. Mã hóa nhị phân:

Xem cấu trúc một chỉ lệnh xử lý dữ liệu:

8. Phân tích:

Như đã nói ở các phần trước, mỗi chỉ lệnh của ARM có 32bit, 2 toán tử nguồn và 1
tóan tử đích. Toán tử nguồn thứ nhất là 1 thanh ghi, toán tử nguồn thứ 2 có thể là 1

Trang 56
thanh ghi, một thanh ghi được dịch(hoặc xoay) bit, hoặc là một giá trị cụ thể

i. Opcode:

Có tất cả 16 lệnh opcode=[00002-11112]; tham khảo cụ thể bàng bảng sau:

Opcode Giả lệnh Ý nghĩa Tác động

0000 AND Logical bit-wise AND Rd:=Rn AND Op2

0001 EOR Logical bit-wise exclusive OR Rd := Rn EOR Op2

0010 SUB Subtract Rd := Rn – Op2

0011 RSB Reverse subtract Rd := Op2 - Rn

0100 ADD Add Rd := Rn + Op2

0101 ADC Add with carry Rd := Rn + Op2 + C

0110 SBC Subtract with carry Rd := Rn – Op2 + C - 1

0111 RSC Reverse subtract with carry Rd := Op2 - Rn + C - 1

1000 TST Test Sec onRn AND Op2

1001 TEQ Test equivalence Sec on Rn EOR Op2

1010 CMP Compare Sec on Rn - Op2

1011 CMN Compare negated Sec on Rn + Op2

1100 ORR Logical bit-wise OR Rd := Rn OR Op2

1101 MOV Move Rd := Op2

1110 BIC Bit clear Rd:=Rn ANDNOT Op2

1111 MVN Move negated Rd:=NOT Op2

+Cờ N=1 nếu kết quả là âm <N=bit cao nhất của kết quả>

+cờ Z=1 nếu kết quả bằng 0.

+Cờ C được bật nếu kết quả có nhớ từ ALU(ADD, ADC, SUB, SBC, RSB, RSC,
CMP, CMN) hay từ kết quả của phép dịch bit. Nếu không có phép dịch bit, cờ C được

Trang 57
giữ giá trị trước đó.

+Cờ V chỉ bị ảnh hưởng trong các phép toán số học. V=1 khi có tràn từ bit 30 sang 31.
Nó quan trọng chỉ trong phép toán học bù 2 có dấu.

9. Lệnh nhân:

A. Mã hóa nhị phân:

VI.2. Phân tích:

i. Opcode:

Giả lệnh hợp ngữ trong thanh ghi từ 21-23 được cho bởi bảng sau:

Opcode

[23:21]Mnemonic Ý nghĩa Tác động

000 MUL Nhân kết quả 32-bit. Rd:=(Rm*Rs)[31:0]

001 MLA Nhân -tích lũy cho giá trị kết quả 32 bit. Rd:=(Rm*Rs + Rn)[31:0]

100 UMULL Nhân không dấu 64bitRdHi: RdLo := Rm * Rs

101 UMLAL Nhân và tích lũy giá trị không dấu 64bit RdHi: RdLo +=
Rm * Rs

110 SMULL Nhân có dấu 64 bit RdHi: RdLo := Rm * Rs

111 SMLAL Nhân và tích lũy giá trị 64bit RdHi: RdLo+=Rm*Rs

Bảng 6: Giả lệnh hợp ngữ cho phép nhân

ii. Lệnh hợp ngữ: MUL{<cond>}{S} Rd, Rm, Rs MLA{<cond>}{S}


Rd, Rm, Rs, Rn

<mul>{<cond>}{S} RdHi, RdLo, Rm, Rs với <mul> là một trong các
lệnh(UMULL, UMLAL, SMULL, SMLAL).

<Các phiên bản ARM có kí hiệu ‘M’ trong tên là các phiên bản có hỗ trợ nhân 64bit-
Ví dụ: ARM7TDMI>

Trang 58
B. . Lệnh chuyển dữ liệu: byte không dấu và 1 word: VII.1. Mã hóa nhị phân:

Hình 24: Mã hóa nhị phân cho cấu trúc truyền dữ liệu dạng byte không dấu hoặc word

C. Lệnh hợp ngữ:<p135-136>

Dạng định chỉ số trước: LDRlSTR{<cond>}{B} Rd, [Rn, <offset>]{!} Dạng


định chỉ số sau: LDRlSTR{<cond>}{B}{T} Rd, [Rn], <offset> Dạng tương đối
nhờ thanh ghi PC: LDRlSTR{<cond>}{B} Rd, LABEL

D. Lệnh chuyển dữ liệu: byte có dấu và nửa word: VIII.1. Mã hóa nhị phân:

Trang 59
Hình 25: Mã hóa nhị phân chuyển dữ liệu dạng byte có dấu và nửa word

E. Chú thích:

Bảng 7: Mã hóa loại dữ liệu

Bit S và H cho biết loại dữ liệu truyền được quy ước như bảng trên.

F. Lệnh hợp ngữ:

Định dạng chỉ số trước: LDR|STR{<cond>}H|SHI SB Rd, [Rn, <offset>] { ! }

Định dạng chỉ số sau: LDRlSTR{<cond>}H|SHlSB Rd, [Rn], <offset>

F.IX. Lệnh chuyển dữ liệu nhiều thanh ghi: IX.1.

Mã hóa nhị phân:

Hình 26: Mã hóa nhị phân lệnh chuyển dữ liệu nhiều thanh ghi

G. Chú thích:

Danh sách các thanh ghi bao gồm một mảng 16 bit thay thế cho 16 thanh ghi từ R0
đến R15 <vị trí bit tương ứng với số thứ tự thanh ghi>. U=1 địa chỉ nền tăng và ngược
lại, P=1, địa chỉ nền tăng trước và ngược lại.

H. Lệnh hợp ngữ:

Trang 60
LDMISTM{<cond>}<add mode> Rn{!}, <registers>

F.X. Lệnh hoán đổi giá trị của bộ nhớ và thanh ghi: X.1. Mã hóa nhị phân:

Hình 27: Mã hóa nhị phân chỉ lệnh đổi giá trị của bộ nhớ và thanh ghi

X.2. Chú thích:

B=1=>load byte không dấu, B=0=>load word ở ô nhớ được định địa chỉ bởi Rn tới

Rd, chứa giá trị từ Rm vào ô nhớ tương ứng. Rd và Rm có thể là 1 thanh ghi.

X.3. Lệnh hợp ngữ: SWP{<cond>}{B} Rd, Rm,Rn X.4. Chú ý:

+Thanhghi PC không được dùng trong chỉ lệnh này.

+Thanh ghi Rn phải khác với thanh ghi Rm và thanh ghi Rd

K. Lệnh chuyển giá trị từ thanh ghi trạng thái vào thanh ghi đa dụng: XI.1. Mã
hóa nhị phân:

Hình 28: Mã hóa nhị phân của lệnh chuyển giá trị thanh ghi trạng thái vào thanh ghi
đa dụng

L. Chú thích:

R=1=>Rd=SPSR R=0=>Rd=CPSR

XI.3. Lệnh hợp ngữ:

Trang 61
MRS{<cond>} Rd, CPSR MRS{<cond>} Rd, SPSR XI.4. Chú ý:

+Chỉ có thể truy cập giá trị SPSR nhờ lệnh này.

+Khi chỉnh sửa các giá trị CPSR hoặc SPSR phải chú ý các bit không được sử dụng.

M. Lệnh chuyển giá trị từ thanh ghi đa dụng vào thanh ghi trạng thái: XII.1. Mã hóa
nhị phân:

Hình 29: Mã hóa nhị phân của lệnh chuyển giá trị thanh ghi đa dụng vào thanh ghi
trạng thái

XII.2. Lệnh hợp ngữ:

MSR{<cond>} CPSR_f, #<32-bit immediate> MSR{<cond>}, SPSR_f,


#<32-bit immediate> MSR{<cond>} CPSR_<field>, Rm
MSR{<cond>} SPSR_<field>, Rm

Với <f-field>:

• c – Điều khiển field-PSR[7:0].

• x – Phần mở rộng của field-PSR[15:8] (không sử dụng ở mô hình ARMs hiện tại).

• s - trạng thái field - PSR[23:16] (không sử dụng ở mô hình ARMs hiện tại).

Trang 62
• f- Cờ của field -PSR[31:24].

N. Chú ý:

+Người lập trình không thay đổi được giá trị CPSR[23:0]

+Tránh truy cập SPSR khi không thật cần thiết.

F.XIII. Vùng không được dùng trong các chỉ lệnh:

i. Số học:

ii. Điều khiển:

Hình 30: Vùng lệnh số học mở rộng

iii. Load-store:

Hình 31: Vùng lệnh điều khiển mở rộng

Hình 32: Vùng lệnh chuyển dữ liệu mở rộng

iv. Vùng lệnh không dùng tới:

Trang 63
F.XIV.Ghi chú:

G. Hỗ trợ của kiến trúc ARM cho ngôn ngữ cấp cao: H. Tập lệnh Thumb:

<Các phần này, bạn xem thêm ở sách tiếng Anh ARM-SoC Architecture, ngay từ đầu
tôi không muốn đi sâu vào các tổ chức phần cứng và hợp ngữ, ta sẽ đề cập đến nó ở
phần khác, khi nói về ứng dụng và lập trình với C-Compiler>

I. Bộ nhớ cache:

Phần này, ta tóm lược và xem thử tại sao lại dùng bộ nhớ phụ cache? Nó giúp ích gì
cho ta?

I.I. Cache l:

Nói một cách nhanh chóng và đơn giản nhất, cache là một bộ nhớ trung gian giữa bộ
nhớ chính <ROM/RAM> và các thanh ghi đa dụng, có đáp ứng nhanh, chứa các dòng
lệnh hay dùng. Khi mà việc truy cập địa chỉ hay giá trị vào các bộ nhớ DRAM hoặc
ROM luôn bị giới hạn về đáp ứng phần cứng, cache được coi là một giải pháp tốt để
thích nghi.

Cấu trúc bộ nhớ của cache cũng có thể phân ra 2 loại riêng biệt, loại chứa chung vùng
dữ liệu và chỉ lệnh, loại tách rời chúng ra thành 2 bộ nhớ riêng biệt, Ta thường gọi là
cấu

trúc von Neuman và cấu trúc Harvard.

I.II. Một số hình ảnh về cache:

Hình 34: Cache dùng chung cho vùng nhớ dữ liệu và địa chỉ <Von-Neuman>

Trang 64
Hình 35: Cache có vùng nhớ dữ liệu và địa chỉ tách rời nhau <Cấu trúc Harvard>

CHƯƠNG III: KITS ARM9 AT91SAM9260


I. ARM AT91SAM9260
1. TÍNH NĂNG CPU:

• 180 MHz ARM926EJ-S™ ARM® Thumb® Processor.


– 8 KBytes Data Cache, 8 KBytes Instruction Cache, MMU.

• Memories
– 32-bit External Bus Interface supporting 4-bank SDRAM/LPSDR, Static Memories,
CompactFlash, SLC NAND Flash with ECC.
– Two 4-kbyte internal SRAM, single-cycle access at system speed.
– One 32-kbyte internal ROM, embedding bootstrap routine.

• Peripherals
Trang 65
– ITU-R BT. 601/656 Image Sensor Interface.
– USB Device and USB Host with dedicated On-Chip Transceiver.
– 10/100 Mbps Ethernet MAC Controller.
– One High Speed Memory Card Host.
– Two Master/Slave Serial Peripheral Interfaces.
– Two Three-channel 32-bit Timer/Counters.
– One Synchronous Serial Controller.
– One Two-wire Interface.
– Four USARTs.
– Two UARTs.
– 4-channel 10-bit ADC.

• System
– 90 MHz six 32-bit layer AHB Bus Matrix.
– 22 Peripheral DMA Channels.
– Boot from NAND Flash, SDCard, DataFlash® or serial DataFlash.
– Reset Controller with On-Chip Power-on Reset.
– Selectable 32,768 Hz Low-Power and 3-20 MHz Main Oscillator.
– Internal Low-Power 32 kHz RC Oscillator.
– One PLL for the system and one PLL optimized for USB.
– Two Programmable External Clock Signals.
– Advanced Interrupt Controller and Debug Unit.
– Periodic Interval Timer, Watchdog Timer and Real Time Timer.

• I/O
– Three 32-bit Parallel Input/Output Controllers.
– 96 Programmable I/O Lines Multiplexed with up to Two Peripheral I/Os.

• Package
– 217-ball BGA, 0.8 mm pitch.
– 208-pin QFP, 0.5 mm pitch.
II. KIẾN TRÚC ARM9 - AT91SAM9260

1. CẤU TẠO PHẦN CỨNG

Trang 66
Trang 67
2. SƠ DỒ CHÂN TÍNH HIỆU :

Trang 68
• SSC Externtion Connector (J17) :

1 2
3 4
5 6
7 8
9 10

Pin No. Signal Name MCU Pin No. Pin No. Signal Name MCU Pin No.
1 GND - 2 5V -
3 GND - 4 3V3 -
5 TK0 23 (PB16) 6 TF0 26 (PB17)
7 TD0 27 (PB18) 8 RD0 28 (PB19)
9 RK0 163 (PB20) 10 RF0 164 (PB21)
Connector cho phép ta có thể mở rộng kết nối với các thiết bị I2S audio codec, truyền nhận
dữ liệu 32bit stream (High-speed Continuous Data Stream)...

• SPI Externtion Connector (J14) :


Trang 69
Trang 70
Pin No. Signal Name MCU Pin No. Pin No. Signal Name MCU Pin No.
1 GND - 2 3V3 -
3 SPI1_MISO 9 (PB0) 4 SPI1_MOSI 10 (PB1)
5 SPI1_SPCK 11 (PB2) 6 SPI1_NPCS0 12 (PB3)
7 SPI1_NPCS1 67 (PC5) 8 SPI1_NPCS2 62 (PC4)
9 GPIO 63 (PC6) 10 GPIO 64 (PC7)
Connector mở rộng cho SPI1, bao gồm 3 đường chip select tương ứng cho 3 slot CS0, CS1,
CS2. Một số thiết bị (giao tiếp theo chuẩn SPI) yêu cầu tín hiệu reset, ngõ ngắt ngoài IRQ
vì vậy, Pin 9 và Pin 10 được đưa ra nhằm đáp ứng nhu cầu đó.

• UART, ADC, TWI Externtion Connector (J16) :


1 2
3 4
5 6
7 8
9 10
11 12
13 14
15 16
17 18
19 20

Pin No. Signal Name MCU Pin No. Pin No. Signal Name MCU Pin No.
1 5V - 2 3V3 -
3 AVDD - 4 GND -
5 AGND - 6 VREFP -
7 AD0 158 (PC0) 8 AD1 159 (PC1)
9 IRQ1 127 (PC15) 10 UART_TXD0 15 (PB4)
11 UART_RXD0 16 (PB5) 12 UART_TXD1 17 (PB6)
13 UART_RXD1 18 (PB7) 14 UART_TXD2 19 (PB8)
15 UART_RXD2 20 (PB9) 16 UART_TXD3 161 (PB10)
17 UART_RXD3 162 (PB11) 18 TWD 208 (PA23)
19 TWCK 1 (PA24) 20 GPIO 23 (PB16)

Trang 71
Connector mở rộng cho các cổng giao tiếp serial bao gồm UART, TWI, bộ chuyển đổi
ADC, GPIO, ngắt ngoài IRQ1.

• JTAG ICE Interface (J5) :

1 2
3 4
5 6
7 8
9 10
11 12
13 14
15 16
17 18
19 20

Pin No. Signal Name MCU Pin No. Pin No. Signal Name MCU Pin No.
1 3V3 - 2 3V3 -
3 NTRST 35 4 GND -
5 TDI 30 6 GND -
7 TMS 31 8 GND -
9 TCK 34 10 GND -
11 RTCK 37 12 GND -
13 TDO 29 14 GND -
15 NRST 36 16 GND -
17 NC - 18 GND -
19 NC - 20 GND -
Trang 72
Cổng JTAG ICE theo chuẩn 20 pin cho phép nạp chương trình và debug hệ thống, hình sau
là sơ đồ kết nối connector JTAG.

NÚT NHẤN:

• Reset (S2) :

Reset hệ thống, tích cực mức thấp.

• Wake up (S1) :

Nút có tác dụng đánh thức hệ thống từ trạng thái power down.

• User Button 1 (S3) :

User button, kết nối với PC15 (pin 127) của AT91SAM9260 MCU.

Action Logic Ouput


Ấn 0
Nhả 1

Trang 73
• User Button 2 (S4) :

User button, kết nối với PC8 (pin 61) của AT91SAM9260 MCU.

Action Logic Ouput


Ấn 0
Nhả 1

LED HIỂN THỊ:

• LED hiển thị trạng thái của hệ thống :

Name Function Status Description


on Trạng thái power down
LED1 Shutdown
off Normal operation
on Bật nguồn
LED2 Power
off Tắt nguồn
on Ethernet PHY full-duplex
D6 Duplex
off Ethernet PHY half-duplex
• User LED :

Name MCU Pin


D4 PA6 (Pin 185)

Tích cực mức thấp:


- PA6 low : D4 on
- PA6 high: D4 off

Trang 74
JUMPER:

• Chip Select Enable Jumpers :

Name Function Default Position


J15 Serial dataflash CS enable Closed
J13 NAND Flash CS enable Closed

Chip select enable jumpers được thiết kế hỗ trợ cho việc khôi phục boot loader sau khi
người dùng ghi chương trình không phù hợp vào vùng Bootstrap hoặc U-Boot của hệ
thống.

Vị trí của J13 được biểu thị ở hình sau:

• System Configuration Jumpers :

Name Function Position Description Default


1-2 Use internal RC
J1 OSCSEL level select 2-3
2-3 Use 32,768kHz
1-2 Lithium battery
J2 VDDBU power source select 1-2
2-3 1V8 (main power)

• JTAG Associated Jumpers :


Xem sơ đồ mạch JTAG ICE Interface ở phần mục trên.
Vị trí của các Jumper được biểu thị ở hình sau:

J8
J6
J13
J9

J2 J1

Trang 75
SƠ ĐỒ KẾT NỐI CỦA KHỐI ADC TRONG KM9260:

Sơ đồ kết nối của khối ADC trong KM9260 được biểu thị bởi hình sau:

Hình : Sơ đồ kết nối của khối ADC


Sơ đồ thể hiện KM9260 đang sử dụng điện áp tham chiếu mặc định là 3V3 được cung
cấp từ nguồn trong hệ thống. Điểm lưu ý nếu người dùng muốn sử dụng điện áp tham
chiếu khác với 3V3 thì việc tháo gỡ điện trở R33 (0 Ohm) và R35 là điều cần thiết.

Trang 76
PHẦN III

Trang 77
CHƯƠNG I:

BIÊN DỊCH NHÂN LINUX

1. Tổng quan về Linux kernel trên phương diện tái biên dịch
1.1 Linux kernel và vấn đề tái biên dịch:
- Linux kernel là một "modern kernel", nặng tính modular. Từ kernel phiên bản 2.6.x trở
đi, có rất nhiều chức năng và mở rộng được đưa vào kernel. Với tinh thần "compile kernel",
một yếu tố chính yếu và quan trọng nhất cần ghi nhận đó là tính phân bộ (modularity) của
Linux kernel.
- Đối với người dùng bình thường, tính modularity này cho phép chọn lựa cách biên dịch
các drivers kernel theo dạng modules hay theo dạng biên dịch trực tiếp vào kernel. Thông
thường, kernel build configuration cho phép ba chọn lựa: Y, M và N cho mỗi "driver" trong
kernel configuration. Có những "driver" không thể compile như một module vì nó phải
được load and link trực tiếp ngay khi kernel khởi động. Cũng có những "driver" cho phép
chọn như một module và được load trong khi và sau khi kernel được boot. Điểm chính yếu
cần nắm bắt trong giới hạn chủ đề "compile Linux kernel" là hiểu rõ tại sao phải chọn M
(cho module), Y (cho compile trực tiếp) và N (không dùng) các drivers này.
- Biên dịch trực tiếp vào kernel có nghĩa là các "drivers" này dù có được dùng hay
không vẫn được load lên khi kernel khởi tác và tất nhiên nó sẽ chiếm một phần memory.
Lợi điểm chính của chọn lựa này là một khi "drivers" đã được compile vào kernel thì không
còn phải quan ngại đến tính trung thực của kernel và các driver nữa. Các hệ thống làm việc
đòi hỏi tính bảo mật cao không dùng modules mà compile thẳng vào kernel để tránh trường
hợp các modules không tin cậy "bị" cài vào kernel lúc nào đó trong quá trình hoạt động của
máy. Lợi điểm kế tiếp của chọn lựa này là tính hiệu xuất (rất nhỏ), khi cần driver thì đã có
sẵn và không cần ứng tải nữa.
- Biên dịch như các modules cho kernel có nghĩa là chỉ khi nào cần dùng các "drivers"
này mới được ứng tải. Lợi điểm của chọn lựa này nổi bật ở khía cạnh xử dụng memory và
tài nguyên trên máy. Với lựa chọn này, có thể tạo nên một kernel cực nhỏ và dễ dàng di
chuyển cho nhiều mục đích khác nhau. Lợi điểm kế tiếp là khả năng tái biên dịch chỉ một
hoặc một số modules nào đó.

1.2.Tóm tắt các bước biên

Biên dịch Linux kernel rất đơn giản nếu như đã hiểu rõ các quy trình và các
bước thực hiện. Sau đây là các lệnh cần thiết,

1. $ cd /usr/src # chuyển vào thư mục /usr/src, nơi thông thường chứa mã nguồn để
biên dịch kernel
2. $ wget http://www.kernel.org/pub/linux/kern...>.tar.bz2 (<KERNEL_SRC> là
phiên bản kernel cần biên dịch,
3. $ gpg --verify <KERNEL_SRC>.tar.bz2.sign <KERNEL_SRC>.tar.bz2 (xác thực
Trang 78
chữ ký và thực tính của mã nguồn)
4. $ bzip2 -dc <KERNEL_SRC>.tar.bz2 | tar xvf - (xả nén gói chứa mã nguồn)
5. $ make xconfig (dùng GUI để điều chỉnh các chọn lựa cho kernel build
configuration và lưu trữ configuration)
6. $ make dep clean bzImage (tập họp lệnh để tạo dependencies và includes, tiếp
theo là dọn dẹp các objects không cần thiết và kernel image ở dạng nén)
7. $ make modules (biên dịch các modules đã được chọn lựa)
8. $ su (chuyển sang chế độ super user cho lệnh tiếp theo)

9. # make modules_install (cài các modules vào /lib/modules/<KERNERL_SRC>,


chỉ có super user mới có thể thực hiện lệnh này)
10. # make install (cài kernel vào máy, bước này bao gồm quy trình cài các hồ sơ cần
thiết vào thư mục /boot)

2. Tại sao cần compile lại Linux kernel:


Đối với người dùng đã quen với những hệ điều hành "đóng" thì khái niệm tái biên
dịch kernel là một khái niệm hết sức lạ lẫm. Điều này cũng dễ hiểu vì kernel của các hệ
điều hành "đóng" hiển nhiên là "đóng" và người dùng bình thường không thể có cơ hội
tiếp cận với mã nguồn của kernel cho thao tác quy trình tái biên dịch. Trong khi đó, mã
nguồn của Linux kernel hoàn toàn "mở" và đây là phương tiện cũng như động lực tiên
quyết cho vấn đề tái biên dịch kernel.
a. Tái biên dịch kernel để chữa lỗi của kernel. Nếu các lỗi này thuộc về lõi của
kernel thì phải vá nguồn của kernel và tái biên dịch nó để sửa chữa các lỗi được công
bố.
b. tái biên dịch kernel để nâng cao hiệu năng của kernel. Theo mặc định, các
Linux distribution thường kèm một phiên bản kernel biên dịch với hầu hết những thành
phần có sẵn để có thể đáp ứng rộng rãi cấu hình hardware (có thể hiện diện trên các
máy). Đây là điểm lợi tổng quát lúc khởi điểm. Tuy nhiên, sau khi đã cài thành công và
nắm chắc máy có những thiết bị gì (sound card, graphic card, network cards, SCSI
card..... ) và biết rõ cần những thành phần nào cho cấu hình của máy thì không có lý do
gì phải bao gồm trọn bộ các thứ không cần thiết và không dùng. Đối với kernel 2.4.x,
mức độ nâng cao hiệu năng không rõ rệt (ngoại trừ dùng phương pháp test load để đo).
Tuy nhiên, từ kernel 2.6.x trở đi, tính hiệu năng qua việc tái biên dịch và điều chỉnh
"driver" modules cho kernel tạo hiệu xuất rõ rệt, nhất là trong việc điều chỉnh "thời
biểu" (scheduling) của các công tác mà system phải đảm nhiệm.
c. Tái biên dịch để loại bỏ những "drivers" không được dùng và có thể gây "hiểu
lầm" cho kernel, tạo ra trường hợp máy có những triệu chứng hoạt động thiếu ổn định
và hay gây lỗi.
d. Tái biên dịch kernel để thử nghiệm một chức năng hoặc một module mình vừa
tạo ra. Trường hợp này không nhiều như các trường hợp trên nhưng cũng nằm trong các
lý do phổ biến.

3. Cấu trúc và quy định phiên bản của Linux kernel
Phiên bản của Linux có quy định rất đơn giản và dễ nhớ. Vấn đề này cần nắm rõ trước
Trang 79
khi chọn một phiên bản nào đó của Linux kernel để vá và biên dịch.
Phiên bản của Linux bao gồm ba nhóm số tách ra bởi các dấu chấm. Ví dụ: 2.4.26
Số thứ nhất: 2 là phiên bản
Số thứ nhì: 4 là chỉ định cho tình trạng phiên bản. Nếu số này là số chẵn, nó chỉ định
cho phiên bản ổn định (stable), có thể dùng cho môi trường production. Nếu số này là
số lẻ, nó chỉ định cho phiên bản không ổn định, nó thường dùng trong môi trường đang
phát triển (development). Các kernel thuộc dạng này thường có nhiều bugs và không ổn
định. Nếu dùng các phiên bản này để tìm bugs và thông báo cho nhóm phát triển Linux
kernel thì đây là điều rất tốt. Không nên dùng phiên bản development cho môi trường
production.
Số thứ ba: 26 là chỉ định cho số hiệu phát hành của một phiên bản Linux kernel. Một
phiên bản ổn định của một Linux kernel có thể có nhiều số hiệu phát hành khác nhau.
Các phiên bản kernel được điều chỉnh bởi mỗi distribution có những điểm dị biệt.

Có nhiều Linux distribution xử dụng số hiệu con (extra-version) cho phiên bản kernel
họ đã điều chỉnh

4. Đòi hỏi tối thiểu trong việc tái biên dịch Linux kernel
Khi biên dịch Linux kernel, điều cần thiết là phải có đủ chỗ chứa trên disk. Ít nhất là phải
đủ chỗ chứa cho mã nguồn (trước và sau khi xả nén), chỗ chứa để cài kernel và các
modules mới sau khi biên dịch.
Đòi hỏi quan trọng khác là phải có một bộ công cụ cần thiết và đúng phiên bản, không thể
biên dịch được kernel nếu không thoả mãn yêu cầu này. Phiên bản cho bộ công cụ với mỗi
series kernel khác nhau. Nên nhớ, nhóm phát triển kernel yêu cầu bạn phải có đúng phiên
bản của các công cụ để đảm bảo việc biên dịch kernel thành công.
4.1 Đòi hỏi cho Linux kernel 2.4.x
Phiên bản tối thiểu Cách xác định phiên bản có trên máy
Gnu C 2.91.66 # gcc --version
Gnu make 3.77 # make --version
binutils 2.9.1.0.25 # ld -v
util-linux 2.10o # fdformat --version
modutils 2.4.2 # insmod -V
e2fsprogs 1.19 # tune2fs
reiserfsprogs 3.x.0b # reiserfsck 2>&1|grep reiserfsprogs
pcmcia-cs 3.1.21 # cardmgr -V
PPP 2.4.0 # pppd --version
isdn4k-utils 3.1pre1 # isdnctrl 2>&1|grep version
4.2 Đòi hỏi cho Linux kernel 2.6.x
Phiên bản tối thiểu Cách xác định phiên bản có trên máy
Gnu C 2.95.3 # gcc --version
Gnu make 3.78 # make --version
binutils 2.12 # ld -v
util-linux 2.10o # fdformat --version
module-init-tools 0.9.10 # depmod -V
Trang 80
e2fsprogs 1.29 # tune2fs
jfsutils 1.1.3 # fsck.jfs -V
reiserfsprogs 3.6.3 # reiserfsck -V 2>&1|grep reiserfsprogs
xfsprogs 2.1.0 # xfs_db -V
pcmcia-cs 3.1.21 # cardmgr -V
quota-tools 3.09 # quota -V
PPP 2.4.0 # pppd --version
isdn4k-utils 3.1pre1 # isdnctrl 2>&1|grep version
nfs-utils 1.0.5 # showmount --version
procps 3.1.13 # ps --version
oprofile 0.5.3 # oprofiled --version
Nếu phiên bản của các công cụ trên máy cũ hơn các phiên bản đưa ra ở trên, cần phải tải
phiên bản mới (đã biên dịch) từ website của distribution . Có thể chọn cách tải mã nguồn
của từng công cụ về biên dịch lại. Cách này mất thời gian hơn rất nhiều và chỉ thích hợp
cho những ai đã quen thuộc với vấn đề biên dịch mã nguồn trên Linux. Lợi điểm của cách
này là bạn tạo cho mình một bộ công cụ rất "sạch" vì đã biên dịch theo ý, thích hợp với môi
trường của máy (và vừa đủ).
5. Xác định cấu hình (hardware) của máy
Phần lớn người dùng bình thường ít khi quan tâm đến cấu hình của máy ngoại trừ có
nhu cầu cụ thể. Ngay cả những ai dùng Linux đã lâu và không cần phải tái biên dịch kernel,
cũng ít khi quan tâm đến cấu hình hardware của máy. Dù có biết nhiều hay ít về cấu hình
hardware của máy mình dùng, bạn vẫn phải thu thập thông tin chính xác của cấu hình trước
khi bắt tay vào việc điều chỉnh kernel build configuration.
Cần tái biên dịch Linux kernel và cần thâu thập thông tin về cấu hình của máy, hai lệnh sau
cung cấp các chi tiết hardware có trên máy:
# /sbin/lspci để liệt kê trọn bộ những PCI "card" đang gắn vào máy. Lệnh này liệt kê trọn
bộ các "card" đang trực tiếp làm việc trên máy, hardware version và model của chúng.
# cat /proc/cpuinfo để xem chi tiết CPU của máy là loại gì. Nếu Linux distribution bạn
dùng không dùng /proc filesystem thì bạn có thể dùng lệnh # dmesg để thu thập thông tin
về hardware trên máy của mình. Ngoài ra, lệnh lsmod cũng ít nhiều giúp bạn xác định các
modules đang được dùng trên máy và tên của các modules này.
Những thông tin thâu thập được ở đây hết sức quan trọng trong giai đoạn điều chỉnh kernel
build configuration. Nó giúp bạn xác định các chọn lựa đúng cho cấu hình máy, tránh đi
những trở ngại có thể rất mất thời gian sau này.
6. Các bước chuẩn bị
6.1 Tạo một bootable floppy disk dùng kernel đang chạy
Đây là một bước cần thiết đề phòng sự cố gì đó khiến bạn không thể boot vào Linux
system sau khi cài kernel mới. Trường hợp này hiếm khi xảy ra trong quá trình biên dịch
kernel và cài kernel mới nếu bạn thực hiện và điều chỉnh đúng. Những sự cố với bootloader
(LILO hoặc GRUB) ít thấy xảy ra vì bootloader đã được thiết lập hoàn chỉnh trước khi cập
nhật kernel. Phần lớn giai đoạn tái điều chỉnh config của LILO hoặc GRUB không chính
xác tạo trở ngại. Vấn đề này sẽ được đề cập sau. Trước mắt chúng ta cần tạo một "bootable
floppy disk".

Trang 81
Có rất nhiều cách để tạo một bootable floppy lấy từ kernel hiện đang chạy trên máy.
Cách dễ nhất có lẽ là cách dùng mkbootdisk. Đây là một binary được cài mặc định trên các
RedHat distribution và hầu hết các distribution dựa RedHat. Nếu binary này không hiện
diện trên máy,có thể tải mã nguồn về và biên dịch cho distribution mình đang dùng. Chạy
lệnh:
# mkbootdisk --device /dev/fd0 `uname -r`, trong đó
`uname -r` là lệnh ngầm để lấy phiên bản kernel hiện dùng trên máy. Nếu không muốn
phiên bản này, bạn có thể gõ vào phiên bản nào đó theo

/dev/fd0 là "device" chỉ cho đĩa mềm thứ nhất trên máy (tương tự như drive A: trên DOS).
Quy trình này chỉ mất khoảng vài phút. Sau khi tạo bootable floppy disk ở trên, dùng nó để
thử boot vào Linux trước khi thực hiện các bước kế tiếp. Nên nhớ phải chỉnh BIOS để cho
phép máy boot từ A:
6.2 Tải mã nguồn
Mã nguồn của Linux kernel cả stable lẫn development có rất nhiều nơi trên Internet.
Nên vào trang trung tâm của Linux kernel ở

1. và tham khảo danh sách "mirrors" để tìm nơi "gần" chỗ mình cư ngụ nhất để tải về. Nơi
"gần" không nhất thiết là "gần" theo phương diện địa lý mà nên chọn "gần" nhất dựa
trên "ping time". Chịu khó lấy vài địa chỉ trên mirror và ping những địa chỉ này để chọn
lấy nơi có ping time ngắn nhất mà download. Bằng cách sẽ giúp đỡ mất thời gian và
tiện cho vấn đề chia xẻ băng thông.
Có nhiều cách tải mã nguồn. Có thể dùng browser để tải qua http hoặc dùng một ftp
client nào đó để tải qua ftp.Cũng có thể dùng wget để download. Có lẽ đây là cách tiện
nhất và nhanh nhất nếu biết rõ địa chỉ và đường dẫn đến gói mình muốn download.
2. Mã nguồn ổn định của Linux kernel được nén ở hai dạng khác nhau: dạng có đuôi là .gz
(dùng GNUzip để nén) và dạng có đuôi .bz2 (dùng bzip2 để nén). Thông thường cả hai
tiện ích nén / xả nén trên đều có sẵn trong các Linux distribution thông dụng. -
6.3 Kiểm tra thực tính của mã nguồn
Điều quan trọng khi tải mã nguồn của kernel, nên tải gpg .sign cho phiên bản tương
ứng. Mục đích là để kiểm tra thực tính của mã nguồn được tải về. Khi mã nguồn của Linux
kernel được công bố, chúng được dồn lại thành một gói .tar và sau đó được nén bằng
GNUzip hoặc bzip2, cả hai loại này sau khi được nén đều được tạo "chữ ký" .sign.
Kiểm tra thực tính của mã nguồn được tải về bằng phương pháp kiểm tra "chữ ký" của từng
gói mã nguồn là một thói quen cần thiết. Lý do: các mã nguồn mở nói chung được công bố
và phổ biến rộng rãi, ai cũng có thể chỉnh sửa (một cách không chính thức và không được
nhóm phát triển chính thức cho phép) rồi đưa lên một server nào đó trên Internet. Người
dùng tải về, biên dịch và cài trên máy mà không kiểm tra thực tính của chúng (và mã nguồn
này có những thay đổi mờ ám) thì hậu quả khó mà lường.
Quy trình kiểm tra "chữ ký" chỉ đơn giản gói gọn trong một dòng lệnh:
$ gpg --verify linux-2.4.26.tar.bz2.sign linux-2.4.26.tar.bz2, trong đó
linux-2.4.26.tar.bz2.sign là "chữ ký" của gói linux-2.4.26.tar.bz2 được tải về từ server chứa
mã nguồn Linux kernel
linux-2.4.26.tar.bz2 là gói mã nguồn Linux kernel được nén bằng bzip2
Trước khi có thể kiểm tra thành công bằng lệnh trên, bạn phải có gpg đã cài trong máy,

Trang 82
tải và nhập public key của server chứa mã nguồn Linux kernel mà bạn tải về. Quy trình tải
mã nguồn Linux kernel và kiểm tra thực tính của mã nguồn này có thể tóm tắt như sau:
# chuyển vào thư mục chứa mã nguồn của máy ở /usr/src là nơi thông thường. Đối với
kernel 2.6.x series, bạn có thể dùng thư mục khác tùy ý:
cd /usr/src
# dùng wget để lấy một phiên bản mã nguồn từ server về ở dạng .bz2....bz2.sign

3. # Dùng gpg với option verify để kiểm thực tính của mã nguồn vừa tải về
gpg --verify linux-2.4.26.tar.bz2.sign linux-2.4.26.tar.bz2
Ngoài phương pháp dùng signature cho vấn đề kiểm chứng thực tính của mã nguồn
(không chỉ mã nguồn của Linux kernel) ,Rất nhiều nơi trên Internet dùng "MD5sum"
cho mục đích này (cho đến nay, mã nguồn Linux kernel dùng signature để kiểm chứng,
không dùng MD5sum). Quy trình kiểm tra "MD5sum" chỉ đơn giản là một quy trình tạo
một "MD5sum" từ mã nguồn được tải về trên máy và so sánh kết quả "MD5sum" này
với hồ sơ "MD5sum" được tải về kèm với mã nguồn. Nếu "MD5sum" bạn tạo ra trên
máy của mình với cùng gói mã nguồn mà không trùng hợp với "MD5sum" nguyên thuỷ
tải về từ server thì thực tính của phần mã nguồn này không đáng tin cậy. Cách tốt nhất
là chỉ nên tải mã nguồn ở những địa chỉ phố biến và đáng tin cậy. Cẩn thận hơn nữa
(really paranoid), thì so sánh MD5sum với một số server chứa mã nguồn khác nhau.
- Kiểm tra thực tính của mã nguồn bằng MD5 checksum khá đơn giản. Tiện ích
md5sum có sẵn hần như trên mọi bản phân phối. Lệnh tạo MD5 checksum đơn giản là
lệnh:
# md5sum <file_cần_kiểm_tra>
sẽ tạo ra 1 chuỗi chữ và số tương tự như: 2fe2a5fabcc3a33722b4ffe05714bec3
*<file_cần_kiểm_tra>. Nếu chuỗi này trùng với chuỗi được cung cấp chính thức với mã
nguồn thì mã nguồn này có thực tính và đáng tin cậy.
6.4 Xả nén mã nguồn
Tùy vào gói mã nguồn được tải về thuộc dạng nén .gz hay .bz2 mà dùng tiện ích
thích hợp để xả nén. Gói mã nguồn được chứa trong /usr/src (wget được chạy sau khi
cd vào /usr/src), cho nên phải ở trong thư mục này trước khi thao tác các bước kế tiếp
(không thì các bước kế tiếp phải thêm và đường dẫn đến nơi chứa gói mã nguồn). Đối
với kernel 2.6.x series, mã nguồn của Linux kernel có thể được xả, chứa và biên dịch từ
bất cứ nơi đâu mà có quyền chứa trên hệ thống. Tuy nhiên, để giữ cho hệ thống sạch và
thống nhất, nên giữ mã nguồn ở /usr/src.
- nếu gói mã nguồn có dạng .gz thì dùng:
$ gunzip linux-2.x.xx.tar.gz (x.xx là bất cứ phiên bản nào tải về).
$ tar xf linux-2.x.xx.tar (lệnh này dùng option x để extract (xả) và f để chỉ định hồ sơ
nào cần được xả, ở đây hồ sơ cần được xả là linux-2.x.22.tar).
Hai lệnh trên cũng có thể gọp chung lại như sau:
$ tar xfz linux-2.x.xx.tar.gz (lệnh này dùng thêm option z để ngầm xả nén .gz file "on-
the-fly" trước khi xả gói tar).
Hoặc có thể tạo cùng kết quả bằng cách khác nữa:
$ gzip -dc linux-2.x.xx.tar.gz | tar xvf - (cụm lệnh này dùng chương trình gzip để xả nén
(option -d) ra stdout (option -c) và "tee" nó qua chương trình tar để xả gói tar ra "on-
the-fly".
- nếu gói mã nguồn có dạng .bz2 thì dùng:
$ bunzip2 linux-2.x.xx.tar.bz2
$ tar xf linux-2.x.xx.tar
Hai lệnh trên cũng có thể gọp chung lại như sau:
Trang 83
$ tar xfj linux-2.x.xx.tar.bz2 (lệnh này dùng thêm option j để ngầm xả nén .bz2 file "on-
the-fly" trước khi xả gói tar).
Hoặc có thể tạo cùng kết quả bằng cách khác nữa:
$ bzip2 -dc linux-2.x.xx.tar.bz2 | tar xvf - (cụm lệnh này dùng chương trình bzip2 để xả
nén (option -d) ra stdout (option -c) và "tee" nó qua chương trình tar để xả gói tar ra
"on-the-fly". Cả ba trường hợp đều cho kết quả là một thư mục có tên là linux-2.x.xx
bên trong thư mục /usr/src/
Trong phần này, chúng ta chỉ đề cập đến trường hợp tải trọn bộ mã nguồn của Linux
kernel về để biên dịch. Trường hợp đã có mã nguồn cũ hơn của Linux kernel trên máy
và chỉ cần tải patch và "vá" thì có quy trình khác.
6.5 Dùng "config" :
Cấu hình biên dịch nhân Linux đơn giản là một "text file" chứa các biến với giá trị Y
(Yes), N (No) hoặc M (Module). Các giá trị này được xử dụng trong quá trình biên
dịch; chúng dùng để xác định những gì không được biên dịch, những gì được biên dịch
và nếu được biên dịch thì sẽ theo dạng nào.
Tùy vào cách sắp xếp của mỗi Linux bản phân phối, cấu hình biên dịch nhân Linux
nằm nhiều nơi khác nhau. Hồ sơ cấu hình theo mặc định của "vanilla" kernel nằm ở
./arch/i386/defconfig (nếu dùng dòng phần cứng IA32 nói chung), các hồ sơ cấu hình
khác cho những dòng phần cứng khác nằm ở ./arch/$ARCH/defconfig; trong đó
$ARCH là dòng phần cứng của máy. Nếu dùng cấu hình mặc định, không chỉnh sửa thì
kernel sẽ được tái biên dịch trọn bộ theo giá trị mặc định và chắc hẳn, kernel này sẽ
không thích hợp (ngay cả nếu nó được biên dịch thành công). Điều này đi ngược lại
mục đích cần tái biên dịch Linux kernel ngay từ đầu. Có thể dùng hồ sơ cấu hình này để
khởi đầu và chỉnh sửa giá trị cho thích hợp. Đây là một bước rất khó khăn cho những ai
chưa từng đi qua giai đoạn này và không có sẵn một cấu hình biên dịch nhân hoàn
chỉnh cho máy.
Cấu hình cho kernel hiện hữu trên máy cũng có thể nằm trong thư mục /boot ở dạng
config-2.x.xx nếu bạn dùng kernel do RedHat (hoặc dựa RedHat) và một số bản phân
phối khác cung cấp. Bạn có thể an toàn dùng cấu hình này và chỉnh sửa, loại bỏ các chi
tiết (driver module) không cần dùng. Nếu hệ thống đã được biên dịch kernel trước đây,
bạn có thể tìm thấy cấu hình biên dịch nhân Linux có tên là .config, được lưu trong thư
mục <KERNEL_SRC> (nơi trước đây mã nguồn của kernel được xả nén và biên dịch).
7. Chỉnh cấu hình biên dịch nhân Linux
7.1 Thành phần của cấu hình biên dịch nhân Linux
Thành phần trong cấu hình biên dịch nhân Linux cho kernel 2.4.x và 2.6.x có một số
tương đồng và dị biệt. Tuy nhiên, quy trình chọn Y, N hoặc M cho các modules vẫn như
nhau. Bước chọn lựa và chỉnh liệu cấu hình biên dịch nhân Linux là một bước mất
nhiều thời gian nhất, nó cũng là một bước gây nhiều trở ngại nhất nếu chỉnh sửa không
hợp lý hoặc thiếu sót.
7.1.1 Thành phần cấu hình biên dịch nhân Linux thuộc kernel 2.4.x series
Code Maturity Level Options
Chọn lựa của mục này cho phép dùng các modules / drivers còn ở trạng thái "alpha"
(thử nghiệm). Nếu hệ thống làm việc là một máy production, cần tính ổn định cao thì
nên tắt bỏ chọn lựa của phần này. Làm như thế sẽ tắt bỏ rất nhiều modules / drivers
thuộc dạng "alpha" trong những phần bên dưới. Nếu muốn thử dùng một số modules /
drivers ở dạng alpha thì nên cho phép phần này (Y) và cẩn thận khi lựa chọn các
modules được biên dịch sau này. Việc chọn lựa các "alpha" drivers ở chế độ mặc định

Trang 84
của các kernel trong nhiều bản phân bố Linux là một trong những nguyên nhân chính
tạo nên tình trạng bất ổn định trên một số hệ thống Linux. Nếu chọn lựa các driver này
một cách cẩn thận, cơ hội va phải tình trạng bất ổn định sẽ giảm thiểu rõ rệt.
Loadable Module Support
Đây là chức năng nòng cốt của Linux kernel (loadable module). Như đã đề cập ở
phần tổng quan , loadable modules tiện dụng và linh động, cho nên gần như sẽ chọn Y
trong trường hợp này. Trong trường hợp bạn cần dùng kernel modules được viết thêm
bên ngoài kernel tree chính thức (3rd party modules), bạn phải chọn "enable set version
information on all modules symbols" trong mục này. Nếu cần biên dịch trọn bộ các
drivers thẳng vào kernel và không dùng modules (vì lý do bảo mật chẳng hạn), bạn có
thể chọn N ở đây. Bạn cũng phải chọn "Y" cho trọn bộ các drivers trong cấu hình biên
dịch nhân để thích hợp với chọn lựa "N" cho phần Loadable Module Support này.
Processor Type and Features
Phần này có lẽ là phần tối quan trọng trong cấu hình biên dịch nhân Linux. Đây là
nơi để chọn đúng CPU đang dùng trên máy. Ngoài ra còn rất nhiều chọn lựa khác nhau
cho vấn đền system scheduling, SMP (symetrical multi-processing) nếu máy có nhiều
CPU, hỗ trợ số lượng lớn memory có trong máy.... Nếu bạn chon CPU là i386 thì có lẽ
sẽ không có sự cố vì i386 là architecture chung nhất (cả Intel và AMD CPU đều chạy
với chọn lựa i386). Tuy nhiên, chọn lựa này sẽ không đạt hiệu năng tối đa và thích hợp
cho từng loại CPU cụ thể. Nên chọn đúng CPU để bảo đảm hiệu năng của máy và nhất
là để tránh trường hợp không thể boot vào Linux sau khi cài kernel mới (vì loại CPU
chỉnh định cho kernel không đúng với CPU có trên máy hay nói một cách kỹ thuật,
instructions giữa kernel và máy không tương đồng).
General Setup
Mục này cho phép chọn lựa các ứng dụng hỗ trợ cho những thiết bị (cards) trên máy
như ISA, PCI, PCMCIA và các chức năng thuộc về vấn đề quản trị năng lượng nâng
cấp (Advanced Power Management).
Memory Technology Devices
Phần này cho phép lựa chọn những ứng dụng thiết bị liên hệ đến memory. Nếu dùng
các thiết bị như digital camera hoặc các loại compact flash thì bạn nên chỉnh lý phần
này cho thích hợp.
Block Devices
Đây là một phần rất quan trọng trong cấu hình biên dịch nhân Linux. Nó bao gồm
các chọn lựa cho những thiết bị thông thường và cần thiết như đĩa cứng, đĩa mềm, băng
lưu trữ cũng như các thiết bị điều tác (controllers) cho parallel ports và RAID. Hầu như
các chọn lựa trong mục này đều cần thiết; đặc biệt là chức năng hỗ trợ initrd cần thiết
để tải sẵn các drivers cần thiết ở dạng module trong quá trình boot máy.
Multi-Device support (RAID and LVM)
Phần này chuyên chú đến các chức năng cần thiết cho hệ thống ở cấp độ server. Các
chọn lựa ở đây hỗ trợ những thiết bị như RAID và LVM. Nếu máy của bạn hiện đang
dùng RAID và LVM thì không thể bỏ qua phần này trong quá trình xác lập cấu hình
biên dịch nhân Linux. Chọn lựa trong phần này đòi hỏi phải hiểu rõ nhu cầu dùng
những công nghệ thuộc dạng này trên máy. Nếu máy không dùng đến những công nghệ

Trang 85
này, có thể an toàn tắt bỏ chúng (dùng N). Nên nhớ, nếu tắt bỏ RAID trong phần này thì
phải tắt bỏ chọn lựa RAID trong phần "block devices" ở trên để tránh gặp phải lỗi biên
dịch sau này.
ATA/IDE/MFM/RLL support
Phần này bao gồm các chọn lựa và hỗ trợ cho IDE và ATAPI dùng trên các pc-
compatible (và trên nhiều architecture khác hiện có trên thị trường). Hầu hết các hệ
thống cần các chức năng hỗ trợ trong phần này.
Cryptography Support (CryptoAPI)
Đây là một phần khá mới và lý thú trong mã nguồn của Linux kernel 2.4.x (chỉ
được giới thiệu và công bố trong các phiên bản sau này của 2.4.x). Phần này có những
lựa chọn thuộc về vấn đề "mã hoá" cho filesystems. Biên dịch các chọn lựa trong mục
này và xử dụng (hoặc không) trên máy tùy ý.
Networking Options
Đây là một phần cực kỳ quan trọng trong cấu hình biên dịch nhân Linux nếu bạn
muốn máy của mình gắn liền với mạng. Nó bao gồm các chọn lựa cho cả IPv4 và IPv6
networking. Đây cũng là một phần hết sức phức tạp, cho nên, để có thể hiểu rõ và chọn
lựa đúng cho hiệu năng tối đa của máy về mặt networking, nên tham khảo rộng rãi các
tài liệu về Linux networking, ít nhất là nên đọc các tài liệu kèm theo trong mã nguồn
Linux kernel ở <KERNL_SRC>/Documentation/networking/ (thường là /usr/src/linux-
2.x.xx/Documentation/networking/).
SCSI Support
Phần chọn lựa cho SCSI ít được những người dùng PC bình thường quan tâm đến vì
không mấy ai dùng SCSI cho máy con. Tuy nhiên nếu bạn dùng SCSI card (hoặc SCSI
built-in trên motherboard) hoặc dùng CDR/W qua IDE nhưng chạy ở dạng SCSI
emulation thì phải điều chỉnh các chọn lựa trong mục này. Điều quan trọng cần nhớ,
nếu không dùng tiện dụng initrd, khi chọn lựa SCSI cho một filesystem chạy trên SCSI
disk bạn phải biên dịch trực tiếp các chọn lựa cho SCSI vào kernel thay vì dùng dưới
dạng module. Nếu không, kernel sẽ treo trong giai đoạn Linux kernel boot vì module hỗ
trợ SCSI chưa được load trong giai đoạn này.
Character Devices
Trong mục này có khá nhiều lựa chọn tập trung vào các thiết bị như serial và parellel,
mouse, joysticks (để chơi games). Tắt hoặc mở các lựa chọn trong mục này thường ít
tạo ảnh hưởng nghiêm trọng.
File Systems
Mục này chứa trọn bộ các chọn lựa liên quan đến file system và các loại file system
được hỗ trợ trên Linux (bao gồm các file system thường được hỏi đến như FAT, FAT32,
NTFS, ISO cho CD-ROM....). Các file system phụ trợ như NTFS, FAT... có thể được
biên dịch như một module cho kernel. Không nên biên dịch các modules cho file
system dùng để "mount" trong giai đoạn boot như ext3, jbd mà nên biên dịch thẳng vào
kernel (Lý do tương tự như đã đề cập trong phần "SCSI Support" ở trên). Cách này sẽ
làm kích thước kernel lớn hơn nhưng sẽ an toàn và đơn giản hơn. Chức năng hỗ trợ
initrd có thể dùng để tải các modules cần thiết trong quá trình Linux kernel boot nhưng
phải nhớ bật chức năng này lên trong phần block devices. Đây là vấn đề tùy chọn của

Trang 86
từng cá nhân.
7.1.2 Thành phần Linux kernel configuration thuộc kernel 2.6.x series
Code Maturity Level Options
Phần này tương tự như đã đề cập ở trên cho kernel 2.4.x series
General Setup
Phần này tương tự như đã đề cập ở trên cho kernel 2.4.x series
Loadable Module Support
Phần này tương tự như đã đề cập ở trên cho kernel 2.4.x series
Processor Type and Features
Phần này tương tự như đã đề cập ở trên cho kernel 2.4.x series
Power Management Options
Phần này tương tự như đã đề cập ở trên cho kernel 2.4.x series
Executable File Formats
Đây là một mục riêng biệt trong cấu hình biên dịch nhân của series 2.6.x. Nếu bạn
quan tâm đến "a.out", "elf" và "misc", nên nghiên cứu kỹ phần này qua các tài liệu kèm
theo với mã nguồn kernel, đặt biệt cho các tiện dụng của "misc"
(<KERNEL_SRC>/Documentation/mono.txt,
<KERNEL_SRC>/Documentation/binfmt_misc.txt,
<KERNEL_SRC>/Documentation/filesystem/proc.txt)
Device Drivers
Đây là một mục mới trong phần cấu hình biên dịch nhân của series 2.6.x. device drivers
nằm rải rác khắp nơi trong kernel build configuration của series 2.4.x. Ở series 2.6.x,
mọi vấn đề liên quan đến "device drivers" được gom lại trong cùng một nhóm. Các
chọn lựa thuộc về các thiết bị như graphic card, sound card, USB, SCSI và vấn đề hiệu
chỉnh chúng đều tập trung ở đây.
File Systems
Phần này tương tự như đã đề cập ở trên cho kernel 2.4.x series
Security Options
Phần này dành riêng cho các vấn đề về bảo mật của kernel. Cho đến nay vẫn còn đang
phát triển, tuy nhiên, đây là phần đầy hứa hẹn cho một Linux kernel mang tính bảo mật
cao.

7.1.2 Thành phần Linux kernel configuration thuộc kernel 2.6.x series
Code Maturity Level Options
Phần này tương tự như đã đề cập ở trên cho kernel 2.4.x series
General Setup
Phần này tương tự như đã đề cập ở trên cho kernel 2.4.x series
Loadable Module Support
Phần này tương tự như đã đề cập ở trên cho kernel 2.4.x series
Processor Type and Features
Phần này tương tự như đã đề cập ở trên cho kernel 2.4.x series
Power Management Options
Phần này tương tự như đã đề cập ở trên cho kernel 2.4.x series
Executable File Formats
Trang 87
Đây là một mục riêng biệt trong cấu hình biên dịch nhân của series 2.6.x. Nếu quan
tâm đến "a.out", "elf" và "misc", nên nghiên cứu kỹ phần này qua các tài liệu kèm theo
với mã nguồn kernel, đặt biệt cho các tiện dụng của "misc"
(<KERNEL_SRC>/Documentation/mono.txt,
<KERNEL_SRC>/Documentation/binfmt_misc.txt,
<KERNEL_SRC>/Documentation/filesystem/proc.txt)
Device Drivers
Đây là một mục mới trong phần cấu hình biên dịch nhân của series 2.6.x. Thật ra
device drivers nằm rải rác khắp nơi trong kernel build configuration của series 2.4.x. Ở
series 2.6.x, mọi vấn đề liên quan đến "device drivers" được gom lại trong cùng một
nhóm. Các chọn lựa thuộc về các thiết bị như graphic card, sound card, USB, SCSI và
vấn đề hiệu chỉnh chúng đều tập trung ở đây.
File Systems
Phần này tương tự như đã đề cập ở trên cho kernel 2.4.x series
Security Options
Phần này dành riêng cho các vấn đề về bảo mật của kernel. Cho đến nay vẫn còn đang
phát triển, tuy nhiên, đây là phần đầy hứa hẹn cho một Linux kernel mang tính bảo mật
cao.

7.2 Điều chỉnh cấu hình biên dịch nhân Linux


Vậy, để điều chỉnh các chọn lựa cho một cấu hình biên dịch nhân Linux.
7.2.1 Các "config" tools
Như đã đề cập ở phần 6.5, mặc định cấu hình biên dịch nhân nằm ở
./arch/i386/defconfig. Khi khởi động một "config" tool nó sẽ tự động đọc và dùng nội
dung của config mặc định này trước khi bạn chỉnh sửa theo ý.
Để chỉnh cấu hình biên dịch nhân Linux, chuyển vào thư mục chứa mã nguồn của
kernel (đã xả nén):
$ cd /usr/src/linux-2.4.26 (ví dụ này dùng kernel 2.4.26 - xem lại phần xả nén ở phần
6.4)
và việc đầu tiên rất nên làm đó là chạy lệnh:
$ make mrproper
Không kể bạn dùng bản phân phối Linux nào và phiên bản Linux kernel nào, nên chạy
lệnh này trước khi thực hiện quy trình tái biên dịch kernel. Target "mrproper" này dùng
để xoá hết tất cả những gì còn "vất vưởng" trong các cây chứa mã nguồn của Linux
kernel để nắm chắc mã nguồn trước khi được biên dịch phải ở tình trạng "sạch sẽ".
Có ba phương tiện "config" phổ biến có thể dùng để chỉnh cấu hìnhbiên dịch nhân
Linux. Sau khi chuyển vào thư mục /usr/src/linux-2.4.26, bạn có thể chọn một trong ba
cách:
- make config
- make menuconfig
- make xconfig
Trong đó,
- make config là phương tiện đơn giản nhất và không đòi hỏi thêm bất cứ thư viện nào
khác để chạy công cụ này. make config sẽ tạo ra một loạt câu hỏi (ở dạng prompt) và
Trang 88
sau khi nhận được câu trả lời của bạn (Y, N, M như đã nói ở trên sau khi bạn nhấn phím
Enter, xác nhận câu trả lời của mình), nó sẽ hình thành một cấu hình biên dịch nhân
Linux. Nhược điểm của loại config này ở chỗ, nếu bạn lỡ trả lời sai (chọn Y, N hoặc M
và gõ phím Enter), bạn không thể quay ngược lại để điều chỉnh mà phải bắt đầu lại từ
đầu. Phương tiện "make config" này chỉ tiện lợi cho những ai rất kinh nghiệm và nắm
rõ mình cần gì trong cấu hình biên dịch nhân, nó cũng tiện lợi cho quy trình chỉnh cấu
hình biên dịch nhân từ xa (xuyên qua console và không dùng được X11 forward vì lý
do gì đó). Sau khi hoàn tất các câu hỏi, công cụ này sẽ lưu trữ một cấu hình biên dịch
nhân (được lưu ở dạng .config trong thư mục chứa mã nguồn của Linux) và sẵn sàng
cho bước tạo dependency cho kernel build. Nếu hồ sơ .config đã tồn tại từ lần biên dịch
trước, nó sẽ bị viết chồng lên ở giai đoạn này.
<insert hình>
- make menuconfig nâng cấp lên một mức cao hơn so với make config. Công cụ này
cần thư viện và binaries "ncurses" để tạo GUI đơn giản. Với công cụ này, có thể tái điều
chỉnh các chi tiết tuỳ thích mà không phải bắt đầu lại từ đầu (nếu lỡ chọn sai) như dùng
make config. Trên GUI đơn giản này, bạn có thể di chuyển, thay đổi các chọn lựa bằng
cách dời chuyển phím mũi tên (lên xuống), chọn Y bằng phím Y, chọn N bằng phím N
và chọn M bằng phím M. Với công cụ này, bạn cũng có thể tải một cấu hình biên dịch
nhân có sẵn (đã làm từ trước và đã biên dịch thành công chẳng hạn) mà chẳng phải đi
xuyên qua mọi chọn lựa để hình thành một cấu hình biên dịch nhân mới. Một đặc tính
của công cụ này là nó chứa "help context sensitive" (phần giúp đỡ hoặc thông tin cho
từng mục trong quá trình điều chỉnh configuration). Nếu bạn không nắm rõ giá trị hoặc
tác dụng của module nào đó, bộ phận "help" này chắc chắn sẽ hữu ích. Sau khi đã hoàn
thành các chọn lựa, bạn có thể lưu trữ một bản configuration trên máy để lần sau dùng
lại và "exit" đồ nghề này. Ở giai đoạn này, một bản configuration được lưu lại (ở
dạng .config trong thư mục chứa mã nguồn của Linux) và sẵn sàng cho bước tạo
dependency cho kernel build. Tương tự như "make config", nếu hồ sơ .config đã tồn tại
từ lần biên dịch trước, nó sẽ bị viết chồng lên.
<insert hình>
- make xconfig có lẽ là phương tiện được dùng rộng rãi nhất, nhất là cho những hệ
thống chạy X Window. make xconfig cần trọn bộ thư viện Qt và X Window để tạo GUI.
Các chọn lựa và cách di chuyển trong GUI này để điều chỉnh hoàn toàn giống như
trường hợp dùng menuconfig và thêm một khả năng nữa là có thể dùng mouse để chọn.
Nếu bạn cần tái biên dịch kernel và có thể dùng X Window thì nên dùng công cụ
xconfig này vì nó dễ dùng nhất.
Trên Linux kernel 2.6.x series có thêm make gconfig. Tương tự như make xconfig,
"gconfig" cũng tạo GUI config tool nhưng GUI này dựa trên thư viện Gtk.
7.2.2 Một số điểm cần chú ý trong giai đoạn hình thành cấu hình biên dịch nhân
- Dùng cấu hình biên dịch nhân có sẵn và điều chỉnh cho thích hợp với nhu cầu của
mình. Nếu bạn dùng bản phân phối của RedHat, cấu hình biên dịch nhân có trong thư
mục /boot ở dạng config-<KERNEL_VERSION> (hồ sơ cấu hình này từ các kernel do
RedHat cung cấp). Để dùng cấu hình biên dịch nhân này, bạn có thể dùng make
menuconfig hoặc make xconfig để tải configuration này lên và điều chỉnh theo ý muốn.

Trang 89
Thật ra không có bất cứ tài liệu nào có thể giải thích cặn kẽ từng chọn lựa cho mỗi cấu
hình máy cả. Ở mức độ tái biên dịch một kernel, bạn cần hiểu cấu hình máy và những
chọn lựa trong một configuration đến mức độ có thể quyết định chọn lựa những gì cho
thích hợp. Bản phân phối Debian cũng lưu trữ các cấu hình biên dịch nhân trong thư
mục /boot tương tự như bản phân phối RedHat. Các bản phân phối khác có một số
tương đồng và dị biệt, bạn nên tham khảo thêm các hướng dẫn cụ thể cho bản phân phối
mình đang dùng.
- Lưu trữ cấu hình biên dịch nhân cho lần biên dịch kế tiếp. Nếu vì lý do gì đó khiến
giai đoạn biên dịch kernel bị hỏng, bạn cần xem xét đoạn báo lỗi sau cùng khi công cụ
biên dịch (compiler) thoát ra với "tình trạng không thành công" (exit status is not 0).
Thông thường compiler thoát ra nửa chừng vì cách chọn lựa cấu hình biên dịch nhân có
những điểm không thích hợp và thoả mãn (liên hệ nhau). Những lỗi được báo trên
console giúp bạn xác định trục trặc nằm trong khu vực nào của cấu hình biên dịch nhân.
Chỉ cần tải hồ sơ biên dịch đã được lưu trữ lần cuối cùng lên và vào thẳng khu vực bị sự
cố để xem xét và điều chỉnh, thay vì phải thiết lập từ dầu để tránh va vào những lỗi
khác. Mỗi khi điều chỉnh và thay đổi cấu hình biên dịch nhân, bạn lại tiếp tục lưu lại
một bản và đặt tên cho nó một cách hợp lý (ví dụ kernel-2.4.26-1 cho configuration thứ
nhất, kernel-2.4.26-2 cho configuration thứ nhì.....).
- Nếu dùng một "vanilla" kernel, mã nguồn kernel được tải về từ kernel.org hoặc
mirror site của nó (bài viết này tập trung chủ yếu vào "vanilla" kernel), sau khi hoàn
thành bước make config hoặc make menuconfig hoặc make xconfig, cấu hình biên dịch
nhân đã được bạn điều chỉnh và chọn lựa sẽ đưọc lưu trữ ở dạng dấu (hidden) ở
./.config (các hồ sơ và thư mục bắt đầu bằng dấu chấm . được xếp loại là hidden files,
chỉ có ls -la mới thấy chúng). Lần kế tiếp, sau khi chạy một trong số lệnh trên và tiếp
nhận các thay đổi thì cấu hình biên dịch nhân lại tự động viết chồng lên ./.config. Cho
nên, bạn có thể lưu trữ hồ sơ ./.config thành một hồ sơ có tên khác trước khi điều chỉnh
và chọn lựa lần kế tiếp.
- Ngoài make config, make menuconfig, make xconfig hoặc make gconfig (cho
kernel 2.6.x series), có thể dùng một lệnh khác cho cả kernel series 2.4.x và 2.6.x là:
make oldconfig. make oldconfig là một trường hợp đặc biệt dùng để đọc và dùng các
chọn lựa đã có sẵn trong ./.config mà không cho bạn cơ hội đi xuyên qua để điều chỉnh
và chọn lựa. Trường hợp này rất tiện lợi nếu bạn đã điều chỉnh và chọn lựa thành công
một cấu hình biên dịch nhân cho mình.
Kernel 2.6.x series còn có bốn target cho bước này:
make defconfig: tạo một cấu hình biên dịch nhân mới với chế độ mặc định cho mọi
chọn lựa
make allmodconfig: tạo một cấu hình biên dịch nhân mới với chế độ chọn lựa các
modules khi có thể được
make allyesconfig: tạo một cấu hình biên dịch nhân mới với chế độ tiếp nhận yes (Y)
cho mọi chọn lựa
make allnoconfig: tạo một cấu hình biên dịch nhân mới với chế độ tiêp nhận no (N) cho
mọi chọn lựa. Chế độ này sẽ tạo ra một kernel rất nhỏ và đơn giản.
Hiếm khi bạn điều chỉnh một cấu hình biên dịch nhân Linux lần đầu mà không hề bị lỗi

Trang 90
trong khi biên dịch. Cách lưu trữ từng configuration cho mỗi lần hiệu chỉnh là cách tốt
nhất để bảo đảm "lỗi" lần trước sẽ không tái diễn. Nếu bạn chỉ đơn giản dùng cấu hình
biên dịch nhân có sẵn (như RedHat Linux chứa trong /boot) và không điều chỉnh gì cả
thì ngoài mục đích vá lỗi, lối dùng này chẳng có tác dụng gì về mặt nâng cao hiệu năng
của máy.

8. Các bước xây dựng


8.1 Bước tạo dependency, dọn dẹp và tạo kernel image
Bước này có thể chạy ba lệnh:
make dep
make clean
make bzImage
hoặc gom chung lại thành một nhóm:
make dep clean bzImage
Nếu chạy dep, clean và bzImage riêng biệt thì phải trông chừng khi nào lệnh thứ nhất
hoàn tất để tiếp tục chạy lệnh thứ nhì và tiếp theo. Nếu chạy ba lệnh một lượt thì lệnh
thứ nhì tự dộng nối tiếp lệnh thứ nhất và lệnh thứ ba nối tiếp lệnh thứ nhì. Không cần
phải chờ đợi.

- Bước "dep" là bước tạo dependencies và các includes cần thiết cho kernel. Bước
này có thể mất nhiều phút, tùy vào CPU của từng máy. Đối với kernel series 2.6.x, bước
này không cần thiết nữa.
- Sau khi xong bước "dep", bước "clean" dùng để dọn dẹp tất cả những "objects" vụn
vặt, không còn cần thiết vì dependencies đã hoàn tất ở trên.
- Bước kế tiếp "bzImage" là bước tạo kernel image. Đây là bước hết sức quan trọng
trong ba bước này. Nếu có sự cố gì xảy ra thì phải quay lại điều chỉnh cấu hình biên
dịch nhân và đi xuyên qua các bước "make dep", "make clean" trở lại (cần phải chạy
một số lệnh dọn dẹp trước khi make dep clean bzImage trở lại, vấn đề này sẽ được đề
cập trong phần 10). Trên máy chạy Athlon Thunderbird 1.4Ghz, tôi mất chừng 10 phút
để hoàn thành bước này. Trên một máy Pentium 233MMX cũ, tôi mất hơn 40 phút mới
hoàn thành bước tạo kernel image.
Nếu ba bước trên hoàn toàn thành công, bạn có thể tìm thấy "kernel image" nằm
trong thư mục ./arch/$ARCH/boot, trong đó $ARCH là dòng phần cứng của kernel bạn
muốn biên dịch. Nếu máy thuộc dạng i386, bạn sẽ tìm thấy kernel image trong
./arch/i386/boot. Kernel image này đã được tạo ra nhưng chưa được cài và ở bước này,
nó chỉ lưu trong thư mục trên cho các bước về sau.
Thật ra có thể tạo nhiều dạng "kernel image". Dạng kernel image được tạo từ "make
bzImage" là dạng phổ biến nhất hiện nay vì nó nén kernel image tốt nhất và thích hợp
với hầu hết các loại computer.

make zImage, make zDisk hoặc make zLilo để tạo kernel image nếu kernel dự kiến rất
nhỏ và không cần kỹ thuật nén cao độ như "bz". Dùng các dạng này cũng thích hợp
trong trường hợp máy của quá cũ và có thể có sự cố với "bzImage". Chỉ cần nắm một
cách khái quát như sau:
Trang 91
- Phần bz hoặc z đi trước các image ở trên chỉ định cho loại nén nào được dùng với
kernel image.
- Phần Image hoặc Disk hoặc Lilo chỉ định cho "loại" kernel image.
- Kernel image này được xả nén "on-the-fly" trong quá trình boot vào Linux sau này.
Xuyên qua ba bước ở trên, sẽ thấy vô số thông điệp chạy trên console (ở kernel 2.6.x
thông điệp chạy trên console ít hơn rất nhiều). Bất cứ lỗi nào (error) được báo trong
bước này đều phải điều chỉnh cấu hình biên dịch nhân và trở lại bước "make dep". Cho
đến giai đoạn này, lý do gây ra lỗi thường là:
- Đồ nghề dùng để biên dịch không đúng phiên bản (xem phần 4.1 và 4.2 cho kernel
series này bạn đang biên dịch)
- Điều chỉnh sai hoặc thiếu một số chọn lựa nào đó trong cấu hình biên dịch nhân. Xem
lỗi báo trước khi compiler thoát ra để xác định lỗi này thuộc phần nào trong cấu hình
biên dịch nhân mà chỉnh lại cho thích hợp, nên dùng phương pháp tải và lưu trữ cấu
hình biên dịch nhân đã đề cập trong phần 7.2.2 ở trên
- Cấu hình máy quá thấp (memory / diskspace) không đủ để thực hiện ba bước ở trên.
Nếu gặp sự cố này, nên nâng cấp máy hoặc dùng một máy khác để build kernel cho
máy này.
Linux kernel 2.6.x series đơn giản hoá chỉ với một target "make all". Target này bao
gồm luôn phần "make modules" trong bước 8.2 kế tiếp.

8.2 Bước tạo modules và cài modules


Bước này có thể chạy hai lệnh:
make modules
make modules_install
hoặc gom chung lại thành một dòng:
make modules modules_install
Điểm khác biệt giữa cách chạy hai lệnh riêng biệt hoặc chạy chung một dòng lệnh ở
đây nằm ở chỗ:
- Bạn có thể chỉ muốn biên dịch modules cho kernel mà không muốn cài (install) trên
máy ngay sau khi các modules được biên dịch xong.
- Hoặc bạn chỉ muốn biên dịch modules trên máy này rồi sẽ mang qua máy khác để cài.
Thông thường "make modules modules_install" đi chung vì ít người build modules trên
một máy rồi mang đi cài trên một máy khác. Nếu chạy hai lệnh này một lượt, bạn phải
chạy ở chế độ "super user" không thì modules không install được vì chỉ có root (super
user) mới có thể "install" các modules vừa được biên dịch. Nếu bạn tách rời hai lệnh
trên thì các lệnh tách rời như sau:
make modules # chạy bằng user account bình thường
su # chuyển sang chế độ "super user"
make modules_install # cài modules vừa biên dịch xong.
Bước "make modules" là bước biên dịch và tạo ra các modules (mà đã chọn ở dạng M
trong quá trình chỉnh lý cấu hình biên dịch nhân). Các modules đã được biên dịch sẽ
được lưu trữ trong các thư mục thích ứng với từng nhóm "drivers" trong cây mã nguồn
(kernel source tree). Giai đoạn này là giai đoạn biên dịch lâu nhất trong trọn bộ quá
trình compiler thực sự biên dịch mã nguồn của kernel. Trên một máy chạy Athlon
Trang 92
Thunderbird 1.4Ghz, bước này mất chừng 25 phút. Trong khi đó cùng số lượng
modules cần biên dịch chạy trên máy Pentium 233MMX mất chừng trên 4 giờ đồng hồ.
Bước "make modules_install" sẽ "cài" các modules vừa được biên dịch vào thư mục
/lib/modules/<kernel_version>. Nếu liệt kê thư mục này (ls), bạn sẽ thấy ít nhất một thư
mục chứa modules cho kernel đang chạy trên máy hoặc nhiều thư mục cho nhiều phiên
bản kernel trước đây (có từ quy trình cập nhật kernel bằng rpm hoặc quy trình nào đó
tuỳ theo bản phân phối, hoặc từ quy trình biên dịch kernel tương tự như bài viết này).
Khi boot Linux bằng một phiên bản kernel nào đó có trên máy, các modules thuộc
kernel này (trong thư mục thích ứng với kernel version) sẽ được ứng tải.
Đối với kernel 2.4.x series, bạn có thể tham khảo chi tiết thông tin về modules, cách
biên dịch modules tổng quát và cách xử dụng modules (thuộc user space) trong hồ
sơ ./Documentation/modules.txt thuộc mã nguồn kernel bạn dự định biên dịch.
Đối với kernel 2.6.x series, bạn có thể tham khảo chi tiết thông tin về modules, cách
biên dịch modules tổng quát và cách xử dụng modules (thuộc user space) trong ba hồ sơ
./Documentation/kbuild/modules.txt, ./Documentation/networking/net-modules.txt
và ./Documentation/sound/oss/README.modules thuộc mã nguồn kernel bạn dự định
biên dịch. Riêng với kernel 2.6.x series, bước "make modules" có thể thực hiện từ
"make all" và bước "make modules_install" chỉ thực hiện riêng (ở chế độ super user) để
cài các modules đã được biên dịch.

8.3 Tách rời mã nguồn và hồ sơ output trên kernel 2.6.x series
Nếu dùng kernel 2.4.x series thì không cần tham khảo thông tin của mục 8.3. Những
thông tin trong mục này chỉ giới thiệu thêm một số tiện ích hữu dụng cho quy trình
chuẩn bị và biên dịch kernel 2.6.x.
8.3.1 "make help", một tiện ích mới trên kernel 2.6.x series
Ngoài những điểm khác biệt trong các make target đã được đề cập ở phần 8.1 và 8.2,
trên kernel 2.6.x series, bạn có thể xử dụng một tiện ích khá hay mà kernel 2.4.x không
có đó là phần "help" trước khi "make" mã nguồn của Linux kernel. Tất nhiên bạn phải
chạy lệnh này sau khi vào trong thư mục chứa mã nguồn Linux kernel:
$ cd /usr/src/linux-2.6.6 (dùng kernel 2.6.6 trong trường hợp này)
$ make help sẽ cho thông tin trợ giúp như sau:
bash-2.05b$ make help
Cleaning targets:
clean - remove most generated files but keep the config
mrproper - remove all generated files + config + various backup files
Configuration targets:
oldconfig - Update current config utilising a line-oriented program
menuconfig - Update current config utilising a menu based program
xconfig - Update current config utilising a QT based front-end
gconfig - Update current config utilising a GTK based front-end
defconfig - New config with default answer to all options
allmodconfig - New config selecting modules when possible
allyesconfig - New config where all options are accepted with yes
allnoconfig - New minimal config
Trang 93
Other generic targets:
all - Build all targets marked with <*>
* vmlinux - Build the bare kernel
* modules - Build all modules
modules_install - Install all modules
dir/ - Build all files in dir and below
dir/file. - Build specified target only
rpm - Build a kernel as an RPM package
tags/TAGS - Generate tags file for editors
cscope - Generate cscope index
Documentation targets:
Linux kernel internal documentation in different formats:
sgmldocs (SGML), psdocs (Postscript), pdfdocs (PDF)
htmldocs (HTML), mandocs (man pages, use installmandocs to install)
Architecture specific targets (i386):
* bzImage - Compressed kernel image (arch/i386/boot/bzImage)
install - Install kernel using
(your) ~/bin/installkernel or
(distribution) /sbin/installkernel or
install to $(INSTALL_PATH) and run lilo
bzdisk - Create a boot floppy in /dev/fd0
fdimage - Create a boot floppy image
make V=0|1 0 => quiet build (default), 1 => verbose build
make O=dir Locate all output files in "dir", including .config
make C=1 Check all c source with checker tool
Execute "make" or "make all" to build all targets marked with <*>
For further info see the ./README file
bash-2.05b$
Thông tin trên cho thấy "Makefile" chính của kernel 2.6.x series bao gồm các mục tiêu
(target) biên dịch khi chạy make help. Với thông tin này, có thể chọn các target make
theo ý muốn mà không phải kiểm tra trong "Makefile" như với kernel 2.4.x series
(kernel 2.4.x series không có "make help" như kernel 2.6.x series và kernel 2.4.x series
không có nhiều make targets như kernel 2.6.x series). Điểm đặt biệt cần quan tâm là ba
chọn lựa cuối trong thông tin "make help" cung cấp:
make V=0|1 0 => quiet build (default), 1 => verbose build
make O=dir Locate all output files in "dir", including .config
make C=1 Check all c source with checker tool
Một trong những chọn lựa quan trọng ở đây là nó cho phép bạn lưu trữ trọn bộ các
hồ sơ output trong quá trình biên dịch vào một thư mục riêng biệt thay vì chứa chung
với mã nguồn của kernel.
8.3.2 Tách rời mã nguồn và output files
Kernel 2.6.x series cho phép bạn tách rời mã nguồn của kernel và các hồ sơ output
được tạo trong quá trình compile, các hồ sơ dấu (hidden) như .config, .depend.... trong

Trang 94
các bước đề cập ở phần 7 và 8 cũng sẽ được lưu trữ ở thư mục nào muốn dùng cho
output files. Với phương tiện này, mã nguồn và các hồ sơ output sẽ không xen kẽ
chung. Điểm quan trọng cần nhớ là khi đã dùng chọn lựa này thì phải dùng cho các
bước "make" khác trong suốt quá trình biên dịch. Ví dụ, bạn có thể khởi đầu bằng:
make O=/path/to/output xconfig
thì các bước kế tiếp sẽ là:
make O=/path/to/output all (target "all" bao gồm "dep, clean, bzImage, modules"), và
make O=/path/to/output modules_install (chạy lệnh này bằng super user để cài modules
của kernel).

9. Cài kernel
Phần này giới thiệu hai cách cài kernel vừa biên dịch và chỉnh định boot loader.
9.1 Cài qua "make install"
Ít người dùng đến chức năng "make install" này vì một số bản phân phối không có
các tiện ích cần thiết để thực hiện trọn vẹn bước này. "make install" tiện lợi và an toàn
hơn cài bằng tay vì nó thao tác các bước cần thiết để thiết lập kernel mới trên hệ thống.
Các bước này bao gồm quy trình lưu trữ kernel cũ (trong thư mục /boot), copy kernel
image mới, copy System.map mới, điều chỉnh boot loader configuration (lilo.conf hoặc
grub.conf) và cập nhật boot loader.
Bước "make install" dựa trên hồ sơ Makefile và install.sh, một shell script thuộc thư
mục ./arch/$ARCH/boot. Shell script install.sh "gọi" một số shell script khác như
/sbin/installkernel và /sbin/new-kernel-pkg, ngoài ra các shell scripts này còn dựa vào
một binary có tên là "grubby" để tạo thông tin trong grub.conf nếu bạn dùng GRUB.
Các shell scripts "installkernel" và "new-kernel-install" thuộc gói mkinitrd của RedHat,
các bản phân phối khác có những ứng dụng tương tự. Nếu bản phân phối bạn dùng
không có gói tương tự, bạn phải cài kernel bằng tay (phần 9.2) hoặc tạo các script tương
tự để thực hiện bước này. Trong khuôn khổ giới hạn của bài viết, tôi không đi sâu vào
vấn đề tạo các script tiện ích.
Để cài Linux kernel mới, chỉ đơn giản chạy lệnh # make install ở chế độ super user từ
trong thư mục chứa mã nguồn của Linux kernel. Sau khi hoàn tất bước "make install"
bạn nên kiểm tra lại cấu hình của boot loader trên máy và chạy các lệnh tương ứng (nếu
cần) để chỉnh định boot loader cho chính xác.
9.1.1 Đối với GRUB
Ví dụ bạn có hai phiên bản kernel trên máy 2.4.20 (phiên bản đang chạy) và 2.4.26
(phiên bản vừa được biên dịch), sau khi chạy "make install", grub.conf có chi tiết tương
tự như sau:
{b}default=1{/b}
timeout=20
splashimage=(hd0,0)/boot/grub/splash.xpm.gz
title Linux (2.4.26)
root (hd0,0)
kernel /boot/vmlinuz-2.4.26 ro root=/dev/hda1
initrd=/boot/initrd-2.4.26.img
title Linux (2.4.20)
Trang 95
root (hd0,0)
kernel /boot/vmlinuz-2.4.20 ro root=/dev/hda1
initrd=/boot/initrd-2.4.20.img
- Chi tiết cần chú ý là biến default. Có hai kernel trong cấu hình GRUB cho các
phiên bản 2.4.26 và 2.4.20. Nếu bạn muốn boot kernel 2.4.26 theo mặc định thì giá trị
của default phải là 0 (grub đếm thứ tự các kernel từ giá trị 0, không phải từ giá trị 1).
Khi chạy "make install", các tiện ích của "install" tự động đưa vào các chi tiết thuộc
kernel mới vào cấu hình GRUB. Tuy nhiên, giá trị default vẫn giữ ở giá trị chỉ định cho
kernel hiện đang hoạt động trên máy. Bạn cần chỉnh giá trị này để buộc boot loader tải
lên phiên bản kernel mới. Một chi tiết hết sức quan trọng bạn cần chú ý là giá trị root
(hdX,Y). Nếu GRUB đã được cài trong lúc cài đặt hệ thống từ CD và đã hoạt động
hoàn chỉnh, bạn không nên thay đổi giá trị này. Giá trị này chỉ cần thay đổi nếu bạn
thêm đĩa cứng và thay đổi các partitions trên máy.
- sau khi chỉnh định và lưu trữ grub.conf thích hợp, bạn chỉ cần tái khởi động máy.
Nếu bạn dùng GRUB làm boot loader thì công tác tái biên dịch nhân Linux hoàn thành
ở đây.
- Giải pháp phòng bị trường hợp không thể boot vào kernel mới rất đơn giản nếu
dùng GRUB làm boot loader. Bạn chỉ cần thêm một dòng fallback 1 vào cấu hình
grub.conf là đủ. Chỉnh định này cho GRUB boot loader biết nếu dùng "default=0" để
boot kernel mới nhất (2.4.26 trong ví dụ này) nhưng không thành công vì lý do nào đó
thì thử boot lại với kernel cũ hơn (2.4.20). Xem thêm ở phần 10 nếu không thể boot
được vào Linux vì boot loader bị hỏng.
9.1.2 Đối với LILO
Hai phiên bản kernel trên máy 2.4.20 (phiên bản đang chạy) và 2.4.26 (phiên bản vừa
được biên dịch), sau khi chạy "make install", lilo.conf có chi tiết tương tự như sau:
prompt
timeout=50
{b}default=linux{/b}
boot=/dev/hda
map=/boot/map
install=/boot/boot.b
message=/boot/message
image=/boot/vmlinuz-2.4.20
initrd=/boot/initrd-2.4.20.img
root=/dev/hda1
label=linux-2.4.20
read-only
image=/boot/vmlinuz
initrd=/boot/initrd-2.4.26.img
root=/dev/hda1
{b}label=linux{/b}
read-only
- Chi tiết cần chú ý là biến default. hai kernel trong cấu hình LILO cho các phiên bản

Trang 96
2.4.26 và 2.4.20. Nếu bạn muốn boot kernel 2.4.26 thì giá trị của default phải là giá trị
label thuộc kernel nào bạn muốn dùng. Trong trường hợp này, label có giá trị là linux
chỉ định cho kernel 2.4.26. Khi chạy "make install", các tiện ích của "install" đưa vào
các chi tiết của kernel mới vào cấu hình LILO. Ở đây vmlinuz là symbolic link của hồ
sơ vmlinuz-2.4.26. Bạn nên kiểm tra lại giá trị default để bảo đảm boot loader sẽ tải
kernel vừa biên dịch khi boot.
- Sau khi chỉnh định và lưu trữ lilo.conf theo ý muốn, bạn phải chạy lệnh:
# /sbin/lilo và chú ý trường hợp hệ thống báo lỗi trong bước cài lilo làm boot loader.
Nếu có, điều chỉnh cho chính xác và thực hiện lại lệnh trên. Với ví dụ trên, bạn sẽ được
báo kết quả trên console tương tự như:
Added linux*
Added linux-2.4.20
Giá trị nào đi kèm với dấu hoa thị (*) chỉ định cho kernel được boot theo mặc định.
- Với LILO, giải pháp đơn giản nhất phòng bị trường hợp không thể boot vào kernel
mới mang tính tạm thời. Trước khi tái khởi động máy dùng lệnh như sau:
# /sbin/lilo -R linux
rồi chạy
# reboot
Nên nhớ lệnh trên được đưa ra như một ví dụ cho kernel 2.4.20 và 2.4.26 với cấu
hình boot loader như trên, bạn phải điều chỉnh đúng phiên bản kernel bạn đang biên
dịch.
Lệnh thứ nhất cho LILO biết lần kế tiếp máy tái khởi động thì thử dùng kernel 2.4.26.
Nếu không thành công cũng không chỉnh định cho kernel 2.4.26 làm kernel boot theo
mặc định và lần boot kế tiếp sẽ dùng kernel 2.4.20 (kernel này chắc chắn phải làm việc
được vì nó đã dùng để biên dịch kernel 2.4.26).
Lệnh thứ nhì chỉ đơn giản ra lệnh cho máy tái khởi động.
Nếu dùng lệnh "/sbin/lilo -R linux-x.xx.xx" và boot vào kernel mới thành công thì
sau khi boot vào, bạn cần chỉnh định cho kernel x.xx.xx làm mặc định rồi mới chạy
"/sbin/lilo -v" như đã nói ở trên (trong phần biến "default" của lilo.conf).

9.2 Cài qua các bước bằng tay


Các bước cài "bằng tay" tương tự như các bước "make install" ở trên nhưng được thao
tác "bằng tay". Thật ra quy trình này rất đơn giản, điều bạn cần lưu ý là phải thực hiện
chính xác để tránh những trở ngại trong bước này và trong giai đoạn boot vào kernel
mới.
9.2.1 Tạo initrd
Trường hợp bạn biên dịch các drivers quan trọng ở dạng modules có liên hệ đến quy
trình boot của Linux (như SCSI driver, RAID driver, các loại filesystem mà root
filesystem dùng như ext3, jbd...) thì chắc chắn bạn phải cần đến initrd (INITial Ram
Disk). Mục đích chính của initrd là phương tiện tải sẵn các driver cần thiết cho kernel
trong quá trình boot. Nếu không muốn dùng initrd, bạn phải biên dịch các driver trực
tiếp vào kernel (hay còn gọi là static compile). Nên chú ý một số bản phân phối Linux
không dùng initrd, họ khuyến khích biên dịch các driver liên hệ đến quy trình boot trực
tiếp vào kernel. Muốn tham khảo thêm chi tiết về RAM disk cho trường hợp này, xem
Trang 97
<KERNEL_SRC>/Documentation/ramdisk.txt.
Quy trình tạo initrd rất đơn giản, chỉ cần chạy lệnh:
# /sbin/mkinitrd /boot/initrd-<KERNEL_VERSION>.img <KERNEL_VERSION>,
trong đó:
- Tham số thứ nhất /boot/initrd-<KERNEL_VERSION>.img chỉ định cho hồ sơ và thư
mục chứa hồ sơ initrd. Thông thường initrd của kernel được chứa trong thư mục /boot
cùng với các thông tin và hồ sơ khác cần thiết cho quy trình boot.
- Tham số <KERNEL_VERSION> thứ nhì chính là kernel nào bạn muốn tạo initrd
cho nó. Tất nhiên thư mục chứa các modules cho kernel version này phải hiện hữu ở
/lib/modules/, nếu không bạn sẽ được system báo lỗi.
Tùy bản phân phối, mkinitrd đòi hỏi thêm các thông số cụ thể để chỉ đường dẫn đến
kernel. Nếu gặp trở ngại trong bước tạo mkinitrd bạn nên tham khảo tài liệu cụ thể cho
bản phân phối mình đang dùng hoặc tối thiểu là xem man mkinitrd và tài liệu
<KERNEL_SRC>/Documentation/initrd.txt để xem thêm các thông tin cần thiết.
Một điểm đáng chú ý là từ kernel 2.5.x (development kernel) trở đi, initramfs được phát
triển với mục đích hỗ trợ và sẽ đi đến chỗ thay thế initrd (init ram disk). Ưu điểm nổi
bật của initramfs là nó có thể chứa các bộ lưu trữ ở dạng cpio "newc" hoặc "crc" (được
nén hoặc không được nén). initramfs cho đến nay chưa phổ biến và ứng dụng rộng rãi
trên các bản phân phối Linux. Tuy nhiên, hướng phát triển và ứng dụng initramfs có vẻ
đầy hứa hẹn.
9.2.2 Copy kernel và System.map
Sau khi hoàn thành bước "make modules_install" (phần 8.2), lúc này bạn đã có
trọn bộ các bộ phận cần thiết cho kernel mới bao gồm kernel image và các modules
thuộc kernel này.
- Copy bzImage từ <KERNEL_SRC>/arch/i386/boot/ đến thư mục /boot, ví dụ:
# cp /usr/src/linux-2.4.26/arch/i386/boot/bzImage /boot/bzImage-2.4.26
install script của RedHat và một số phân phối khác bao gồm bước copy bzImage thành
vmlinuz, có thể thực hiện (hay không tùy ý, bước này tương tự như bước ở trên) như
sau:
# cp /usr/src/linux-2.4.26/arch/i386/boot/bzImage /boot/vmlinuz-2.4.26
kế tiếp là xoá symbolic link cũ (nếu có) của vmlinuz trong thư mục /boot:
# rm -f /boot/vmlinuz
và sau đó tạo symbolic link mới cho vmlinuz-2.4.26 thành:
# ln -s /boot/vmlinuz-2.4.26 /boot/vmlinuz
Tất nhiên bạn phải điều chỉnh lại cấu hình boot loader để thích ứng với cách gọi
"bzImage" hoặc "vmlinuz" này cho giá trị image (trong lilo.conf) hoặc giá trị kernel
(trong grub.conf). Cách dùng và cách gọi bzImage và vmlinuz tạo khá nhiều bối rối cho
người dùng Linux khi tiếp cận quy trình biên dịch kernel. Một số bản phân phối Linux
dùng bzImage, một số khác lại dùng vmlinuz. Dù gì đi chăng nữa, đây cũng chỉ là cách
dùng và cách gọi; bạn nên dùng theo cách bản phân phối Linux nào có trên máy.
- Phần còn lại là bước copy hồ sơ System.map:
# cp /usr/src/linux-2.4.26/System.map-2.4.26 /boot/System.map-2.4.26
kế tiếp là xoá symbolic link cũ của System.map trong thư mục /boot:

Trang 98
# rm -f /boot/System.map
và sau đó, tạo symbolic link mới cho System.map:
# ln -s /boot/System.map-2.4.26 /boot/System.map
9.2.3. Chỉnh bootloader config
9.2.3.1 Nếu bootloader là GRUB
Hai phiên bản kernel trên máy 2.4.20 (phiên bản đang chạy) và 2.4.26 (phiên bản vừa
được biên dịch) thì grub.conf tương tự như sau:
default=0
timeout=20
splashimage=(hd0,0)/boot/grub/splash.xpm.gz
title Linux (2.4.20)
root (hd0,0)
kernel /boot/vmlinuz-2.4.20 ro root=/dev/hda1
initrd=/boot/initrd-2.4.20.img
Chỉnh thành:
default=0
timeout=20
splashimage=(hd0,0)/boot/grub/splash.xpm.gz
title Linux (2.4.26)
root (hd0,0)
kernel /boot/vmlinuz ro root=/dev/hda1
initrd=/boot/initrd-2.4.26.img
title Linux (2.4.20)
root (hd0,0)
kernel /boot/vmlinuz-2.4.20 ro root=/dev/hda1
initrd=/boot/initrd-2.4.20.img
Sau khi đã lưu trữ (save) cấu hình của /etc/grub.conf ở trên (/etc/grub.conf là symbolic
link đến /boot/grub/menu.1st) và tái khởi động máy để bắt đầu dùng kernel vừa được
biên dịch. Nếu bạn dùng GRUB làm boot loader thì công tác tái biên dịch nhân Linux
hoàn thành ở đây. Nên lưu ý trong ví dụ này, tôi dùng vmlinuz thay vì dùng bzImage,
bạn nên chọn lựa theo ý và điều chỉnh cho phù hợp trong grub.conf.
Đối với giải pháp phòng bị trường hợp không thể dùng GRUB để boot vào kernel mới,
xem chi tiết ở phần 9.1.1 ở trên.
9.2.3.2 Nếu bootloader là LILO
Hai phiên bản kernel trên máy 2.4.20 (phiên bản đang chạy) và 2.4.26 (phiên bản
vừa được biên dịch) thì lilo.conf tương tự như sau:
prompt
timeout=50
default=linux
boot=/dev/hda
map=/boot/map
install=/boot/boot.b
message=/boot/message

Trang 99
image=/boot/vmlinuz
initrd=/boot/initrd-2.4.20.img
root=/dev/hda1
label=linux
read-only
Chỉnh /etc/lilo.conf để cài kernel mới (2.4.26 cho ví dụ ở đây), bạn có /etc/lilo.conf
như sau:
prompt
timeout=50
{b}default=linux{/b}
boot=/dev/hda
map=/boot/map
install=/boot/boot.b
message=/boot/message
image=/boot/vmlinuz-2.4.20
initrd=/boot/initrd-2.4.20.img
root=/dev/hda1
{b}label=linux-2.4.20{/b}
read-only
image=/boot/vmlinuz
initrd=/boot/initrd-2.4.26.img
root=/dev/hda1
{b}label=linux{/b}
read-only
Sau khi đã lưu trữ (save) cấu hình của /etc/lilo.conf ở trên, chạy lệnh:
# /sbin/lilo để đăng ký kernel mới cho LILO boot loader.
Đối với giải pháp phòng bị trường hợp không thể dùng LILO để boot vào kernel mới,
xem chi tiết ở phần 9.1.2 ở trên.

10. Tái khởi động máy và chỉnh lý nếu gặp trục trặc
Tới đây, bạn cần tái khởi động máy để boot vào kernel mới. Nếu không có gì trở
ngại, máy sẽ boot vào Linux bình thường. Bạn có thể kiểm lại xem kernel mình
đang chạy có đúng phiên bản vừa được biên dịch hay không bằng cách chạy:
$ uname -r
hoặc
$ cat /proc/version
Nếu kết quả báo phiên bản kernel cũ thì có nghĩa boot loader (LILO hoặc GRUB) đã
không boot kernel vừa được biên dịch. Bạn nên kiểm tra lại boot configuration
(lilo.conf hoặc grub.conf) cho đúng theo chi tiết đã nêu ở trên.
10.1 Bị treo khi bootloader đang boot vào linux
Trở ngại trong giai đoạn boot loader chuẩn bị boot vào Linux thông thường do cấu
hình boot loader ấn định không đúng và boot loader được cài lên không đúng boot
partition hoặc MBR bị hỏng (hiếm thấy trong quá trình tái biên dịch và cài kernel
mới nếu thực hiện đúng quy cách). Trong trường hợp này, phải:
Trang 100
- Dùng đến đĩa mềm "cấp cứu" được tạo ở phần 6.1 để boot vào Linux
- Đến giai đoạn này bạn hẳn phải biết vị trí của root partition (/) trên đĩa cứng để
mount partition của đĩa cứng:
# mount /dev/hdXy /mount/point/somewhere, trong đó X là ví trí đĩa cứng trên máy,
y là vị trị root partition trên đĩa cứng này.
- Đổi root (chroot) trở thành root partition của đĩa cứng:
# chroot /mount/point/somewhere, trong đó /mount/point/somewhere là nơi đĩa cứng
của bạn được mount.
- Kiểm tra lại cấu hình của boot loader và cài lại boot loader cho máy (xem phần
9.1.1 hoặc 9.1.2 . Tùy theo boot loader bạn dùng là GRUB hay LILO). Điểm cần chú
ý ở đây cho GRUB boot loader là bạn phải chạy lệnh:
# /sbin/grub-install /dev/hdX, trong đó /dev/hdX là disk nào chứa MBR cho hệ thống
(thường là đĩa đầu tiên trên máy - Primary Master). Lệnh trên sẽ tái thiết lập boot
record và loại bỏ các trường hợp MBR bị hỏng. Tương tự cho LILO, bạn phải chạy
lệnh:
# /sbin/lilo.
10.2 Bị treo trong quá trình kernel được load
Nếu vướng vào các trở ngại trong giai đoạn kernel đang được tải lên thông
thường là do các drivers tối cần thiết để mount filesystems trên máy bị thiếu. Giả sử
bạn dùng ext3 cho root partition (/) chứa kernel. Để có thể mount root partition này,
ext3 module phải được biên dịch và initrd phải tải module này lên. Tương tự ứng
dụng cho các trường hợp dùng filesystem khác và cũng thiếu module.
Trong trường hợp này, bạn cần ghi xuống phần lỗi được báo trong khi boot vào
kernel mới để xác định lỗi này thuộc phần nào của cấu hình biên dịch nhân Linux và
từ đó điều chỉnh lại và tái biên dịch lại cho thích ứng. Nói một cách tổng quát, bạn
phải:
- Tái khởi động lại máy và boot vào phiên bản cũ của kernel (hoặc boot loader sẽ
boot vào phiên bản cũ của kernel nếu bạn dùng biện pháp trù bị đã được đề cập ở
phần 9.1.1 và 9.1.2 ở trên)
- Chọn lựa và chỉnh định cấu hình biên dịch nhân Linux lại (xem phần 7.2.2 để tránh
lặp lại bước lựa chọn cấu hình một cách không cần thiết).
- Thực hiện lại các bước đã nêu ra trong phần 8 và 9 ở trên
11. Vá và biên dịch kernel
Mã nguồn của Linux kernel thường được "vá" rồi tái biên dịch nhiều hơn là được
biên dịch từ trọn bộ mã nguồn tải về từ kernel.org nếu bạn đã quen thuộc với quy
trình tái biên dịch hoặc bạn có nhu cầu phải cập nhập kernel của máy thường xuyên.
Tại sao lại cần "vá"? Mã nguồn của Linux kernel cần được vá vì các lý do thường
gặp như sau:
- Mã nguồn của Linux kernel được cập nhật. Bạn đã có sẵn mã nguồn của Linux
kernel (cũ hơn) trên máy. Muốn nâng cấp phiên bản của Linux kernel, bạn chỉ cần tải
các "miếng vá" về để vá (thay vì phải tải trọn bộ mã nguồn của Linux kernel cho
phiên bản mới).
- Một số "drivers" được cập nhật. Để xử dụng các driver mới này (và các drivers này

Trang 101
cần được biên dịch để nối với các thư viện hiện hành trên máy), bạn chỉ cần tải các
"miếng vá" của những drivers này để vá Linux kernel và tái biên dịch chúng.
11.1 Các điểm quan trọng trước khi vá
Tương tự như phần 6.2, 6.3 và 6.4 ở trên, quy trình tải các miếng vá (patch) cho
Linux kernel y hệt như tải trọn bộ gói mã nguồn của Linux kernel. Điểm khác biệt là
bạn phải tải các hồ sơ khởi đầu bằng patch và chọn cho đúng các patch cần thiết cho
kernel cần được patch.
Điểm tối yếu cần ghi nhớ là khi vá mã nguồn của Linux kernel, bạn phải vá đúng thứ
tự và đầy đủ các miếng vá cho đến đúng phiên bản cần có. Ví dụ, bạn đang có phiên
bản kernel là 2.4.20 trên máy và bạn muốn tái biên dịch phiên bản kernel của máy
trở thành 2.4.26. Thay vì tải trọn bộ mã nguồn của kernel 2.4.26 và biên dịch lại (như
đã trình bày trong suốt bài viết này), bạn có thể tải các bản vá 2.4.21, 2.4.22, 2.4.23,
2.4.24, 2.4.25 và 2.4.26 về máy. Tổng cộng dung lượng các bản vá này chỉ là một
phần rất nhỏ so với trọn bộ gói mã nguồn 2.4.26. Tất nhiên bạn đã có mã nguồn của
kernel 2.4.20 trên máy không thì không thể vá được.
11.2 Tải, xả và vá
Các miếng vá thường được nén ở hai dạng: .gz hoặc .bz2 như gói mã nguồn. Bạn có
thể tùy chọn và có thể tải các miếng vá này về bất cứ nơi nào trên máy. Sau khi tải
chúng về, bạn có thể thực hiện quy trình tương tự như sau:

Giả định các bản vá được nén ở dạng .bz2, nơi chứa mã nguồn của Linux kernel
ở /usr/src và thực tính của các patch này đã được kiểm tra. Trong ví dụ này, giả định
phiên bản đang dùng trên máy là 2.4.20 và phiên bản cần được vá sẽ là 2.4.26
a) # chuyển vào thư mục /usr/src
$ cd /usr/src
b) # xả nén các patch ở dạng .bz2 vào thư mục /usr/src. Lặp lại cho đến khi xả hết
các patch cần được vá
$ tar xfvj /path/to/patch/patch-x.xx.xx ./
c) # dọn dẹp sạch sẽ mã nguồn kernel hiện có trên máy, giả định phiên bản mã nguồn
hiện có là 2.4.20
cd ./kernel-2.4.20
make mrproper
d) # lưu một bản mã nguồn kernel 2.4.20 trong thư mục /usr/src phòng bị cho sự cố
trong quá trình vá (nếu không lưu một bản mã nguồn nguyên thủy của kernel 2.4.20
trên máy, hoặc bản mã nguồn 2.4.20 này cũng đã được vá trước đây)
tar cvf ../linux-2.4.20.tar ./
e) # vá các miếng vá theo đúng thứ tự và theo dõi bất cứ lỗi nào được báo
$ patch -p1 < ../patch-2.4.21
$ patch -p1 < ../patch-2.4.22
$ patch -p1 < ../patch-2.4.23
$ patch -p1 < ../patch-2.4.24
$ patch -p1 < ../patch-2.4.25
$ patch -p1 < ../patch-2.4.26

Trang 102
hoặc thực hiện kiểu "lười" như sau:
# tạo một biến PATCH tạm thời chứa tên các patch cần patch theo đúng thứ tự, tách
rời bằng phím trống (space)
$ export PATCH="patch-2.4.21 patch-2.4.22 patch-2.4.23 patch-2.4.24 patch-2.4.25
patch-2.4.26"
# chạy vòng lặp
$ for item in $PATCH; do patch -p1 < ../$item; done
Nếu trong khi vá không có gì trở ngại, bạn sẽ thấy các thông tin tương tự:
patching file xxx
patching file yyy
....

cho đến khi kết thúc.


Nếu trong khi vá bị báo lỗi, bạn phải ngưng bước vá (ctrl-C) và kiểm tra xem bạn có
dùng đúng bản vá và thực hiện các bản vá đúng thứ tự phiên bản hay không. Không
nên tiếp tục với bước vá khi gặp lỗi vì chắc chắn bạn sẽ gặp trở ngại trong giai đoạn
biên dịch sau này. Để tránh các trở ngại về sau, nếu bị báo lỗi trong khi vá, cách tốt
nhất bạn nên xoá trọn bộ thư mục chứa mã nguồn của Linux kernel (đang được vá và
bị lỗi) và xả gói mã nguồn nguyên thủy hoặc gói bạn vừa lưu trữ ở trên rồi thử lại.
f) # xoá thư mục chứa mã nguồn vừa vá và bị trục trặc, thư mục linux-2.4.20 được
dùng như một ví dụ ở đây
$ cd /usr/src
$ rm -rf ./linux-2.4.20
g)# xả gói mã nguồn được lưu trữ ở trên
$ tar xvf linux-2.4.20
$ cd ./linux-2.4.20

và sau đó lặp lại bước vá (bước e) theo đúng thứ tự các miếng và.
Sau khi vá thành công, bạn nên thực hiện hai bước kế tiếp như sau trước khi bắt tay
vào việc chuẩn bị cấu hình biên dịch nhân Linux và biên dịch mã nguồn:
h) # đổi tên thư mục chứa mã nguồn cho đúng phiên bản đã được vá (giúp bạn nhận
diện phiên bản của mã nguồn đang có trên máy đã được vá tới phiên bản nào)
$ cd /usr/src
$ mv ./linux-2.4.20 ./linux-2.4.26
i)# chỉnh giá trị "VERSION" trong Makefile chính của mã nguồn Linux. Thư mục
chứa mã nguồn lúc này đã được đổi tên thành linux-2.4.26
$ vi ./linux-2.4.26/Makefile
Vài dòng đầu của hồ sơ Makefile này chứa các thông tin tương tự như sau (nếu mã
nguồn của phiên bản 2.4.20 được xả từ gói mã nguồn nguyên thủy):
VERSION = 2
PATCHLEVEL = 4
SUBLEVEL = 20
EXTRAVERSION =

Trang 103
Bạn cần đổi giá trị SUBLEVEL thành 26 và lưu hồ sơ Makefile này (cho ví dụ này,
hoặc bất cứ phiên bản nào bạn đã vá tới - xem thêm chi tiết về quy định phiên bản
Linux kernel ở phần 3). Giá trị phiên bản 2.6.26 lấy từ hồ sơ Makefile sẽ được dùng
trong quá trình biên dịch và cài đặt kernel về sau. Nếu bạn không điều chỉnh giá trị
"VERSION" ở bước này, bước cài kernel về sau sẽ viết chồng lên kernel 2.4.20 đang
có trên máy. Nói về mặt kỹ thuật việc viết chồng lên không có gì trở ngại. Tuy nhiên,
nếu bạn gặp trục trặc sau khi đã biên dịch kernel nhưng không boot vào được thì sự
thể sẽ rất phức tạp vì bạn không còn bản kernel chạy được trên máy.

CHƯƠNG II
BIÊN DỊCH KERNEL CHO CHIP ARM
1. BIÊN DỊCH KERNEL

KM-9260 là bo nhúng trên nền vi điều khiển ARM9. kernel linux 2.6.27 được biên
dịch với các bước sau:

Trước tiên, cần phải tạo ra một thư mục mới, ví dụ km-9260

$ mkdir km-9260
$ cd km-9260
$ wget http://www.kernel.org/pub/linux/kernel/v.2.6/testing/v.2.6.27/linux-2.6.27-
rc8.tar.bz2
$ wget http://dev.ivanov.eu/projects/cs-e9302/linux-2.6.27-rc8_ep93xx_mmc.patch.gz
$ tar -xjf linux-2.6.27-rc8.tar.bz2
$ cd linux-2.6.27-rc8
$ zcat ../linux-2.6.27-rc8_ep93xx_mmc.patch.gz | patch -p1
$ cp km-9260_kernel_config .config

Đối với trình biên dịch ARM chéo ,có thể dùng toolkit ELDK. Trước khi cấu hình
kernel, makefile trong linux 2.6.27 nên được sửa đổi:

$ cd linux-2.6.24-rc8
$ nano Makefile

Thay thế ARCH ?=$(SUBARCH) và CROSS_COMPILE ?= như sau:

 ARCH ?= arm
 CROSS_COMPILE = arm-linux-

Trang 104
Và at-9260_kernel_config.config với đầy đủ thông tin của board KM-9260 để biên dịch
kernel v.2.6. hơn nữa, nếu muốn kernel hỗ trợ nhiều chức năng hơn như là smbfs, hệ
thống tập tin mạng ( network file system….thì có thể làm với “ make menuconfig”

$ cd linux-2.6.27-rc8

$ make oldconfig

$ make menuconfig

Hãy chắc chắn rằng hệ thống của bạn là “EP92XX-based” và “ Support Cirus Logic
EBD9260”:

Và với nhiều chức năng hơn (nếu muốn), chúng ta cần kiểm tra “root file system on NFS
” và “ SMB file system support” để sử dụng hệ thống tập tin gốc qua mạng và mounting
window shares…

Trang 105
Cuối cùng dùng lệnh make để biên dịch kernel

$ make

2. BOOTING THE KERNEL (khởi động kernel)

Sau khi biên dịch kernel thành công, hình ảnh kernel linux (zImage) sẽ được tạo ra
trong thư mục “/linux-2.6.27-rc8/arch/arm/boot”. Mỗi board AT-9260 sẽ được cài đặt sẵn
với linux 2.6 và hình ảnh redboot trong flash. Chúng ta sẽ dùng redboot cài đặt sẵn để
khởi động kernel và dùng cửa sổ Hyper Terminal như là một cửa sổ lệnh promt. Máy
tính kết nối với board KM-9260 bằng kết nối UART (RS232). Máy tính không cần tín
hiệu phản hồi từ board, nhưng dây NULL MODEM là cần thiết để hoạt động tốt. cách
khác, chúng ta không thể đặt bất kỳ kí tự nào vào cửa sổ Hyper Terminal từ bàn phím

Trang 106
Cả 2 bên đều được kết nối bằng đầu BD9. vì thế, chúng ta không cần nhớ kết nối tới PC
như thế nào cho hoạt động tốt. khi khởi động kernel, chúng ta cần cài đặt lại các biến
Redboot, chỉ đơn giản đưa dòng lệnh của chúng ta vào Hyper Teminal. Sẽ rất vất vả nếu
chúng ta dùng RS232 để tải hình ảnh kernel, vì RS232 là giao thức truyền nối tiếp tốc độ
thấp, và nó có thể mất vài phút để tải xong hình ảnh kernel. May mắn thay, Redboot có
hỗ trợ giao thức TFTP, và chúng ta có thể tải hình ảnh kernel vào KM-9260 với tốc độ
cao hơn. Trong trường hợp này, chúng ta cần một server TFTP,tải miến phí từ Internet.
Chúng ta có thể dùng server TFTP và chạy nó trên cửa sổ chính của PC hoặc máy chủ
linux PC. Với winXP, chúng ta có thể dùng server TFTPD32. TFTD32 không cần cài
đặt. tạo thư mục mới trên ổ C:\ ví dụ C:\TFTD32\

Đơn giản, chép tftd32.exe tới thư mục này và chạy nó:

1. chọn tab server Tftp


2. click vào nút Browse và tham chiếu tới C:\TFTD32
3. chép zImage vào C:\TFTD32

“ server interfaces” cho biết địa chỉ IP của máy chủ (địa chỉ IP của winXP). Bây giờ,
server TFTD32 đã sẵn sàng để tải hình ảnh kernel linux. Trong cửa sổ Hyper Teminal,
chúng ta cái đặt lại các biến bằng dòng lệnh sau:

RedBoot>fconfig

Run script at boot: true


Boot script:
.. fis load zImage
.. exec -c "console=ttyAM root=/dev/sda1 rootdelay=5"
Enter script, terminate with empty line
>> fis load zImage
>> exec -c "console=ttyAM root=/dev/mmcblk0p1 rootdelay=5"
>>
Boot script timeout (1000ms resolution): 5
Use BOOTP for network configuration: false
Gateway IP address: 192.168.1.1
Local IP address: 192.168.1.50
Local IP address mask: 255.255.255.0
Default server IP address: 192.168.1.10
DNS server IP address: 192.168.1.1
Set eth0 network hardware address [MAC]: true
eth0 network hardware address [MAC]: 0x00:0x00:0x00:0x00:0x48:0x33
GDB connection port: 9000
Force console for special debug messages: false
Network debug at boot time: false
Update RedBoot non-volatile configuration - continue (y/n)?

Trang 107
Khi bật nguồn, Redboot sẽ dùng một bộ đếm ngược ( boot script timeout), sau
5s,mặc định script sẽ được chạy. Chúng ta có thể dừng bộ hẹn giờ lại và cài đặt lại các biến
bằng cách nhấn CTR+C. Trong trường hợp này, thay đổi nội dung của các boot script và
giá trị của các parametter như trên sẽ cho kết quả tốt hơn.

3. DEBIAN ROOTFS
Chúng ta dùng Debian để khởi động file hệ thống, board hoạt động với linux một
cách toàn diện ( không phải là uCLinux). Chúng ta có thể biên dịch một chương trình C
trên board và trình biên dịch máy chủ linux là không cần thiết. Đầu tiên trên máy PC, cần
tạo ra thiết bị ext3 cho rootfs, cắm trình điều khiển USB FLASH vào PC, giả sử tên của
thiết bị lưu trữ là /dev/sdb1 :
$ cd km-9260
$ wget
$ mkfs.ext3-L root/dev/sdb1
$ mount/dev/sdb1/mnt
$ cd/mnt
$ tar-xjt/root/km-9260/km-9260_root2.tar.gz
$ umount/mnt

4. BOOT SCRIPT ( tập lệnh khởi động)


Tập lệnh khởi động được lưu trữ trong bộ nhớ Flash, giống một dòng lệnh trong
Redboot. Nó làm cho hệ thống khởi động thuận tiện, chỉ cần cấp nguồn cho board , linux
sẽ từ động chạy
>> fis load zImage
>> exev –c “ console=ttyAM root=/dev/mmcblk0p1 rootdelay=5”
Dòng lệnh đầu tiên sẽ tải file zImage từ bộ nhớ Flash vào bộ nhớ chính ( SDRAM) của
km-9260, và không giải nén file ảnh, bắt đầu khởi dộng kernel. Dòng lệnh tiếp theo là lệnh
khởi động kernel, nó làm cho kernel và thiết bị được gắn kết với nhau. Chúng ta có thể tự
gõ tay và thực hiện các lệnh thay vì dùng các tập lệnh khởi động. nếu dùng Debian khởi
động file hệ thống được lưu trữ trong SD card, “root=/dev/mmcblk0p1” cần phải được xác
định. Có một số sai lầm trong khi gõ có thể gây nên các lỗi khi khởi động linux. Nếu thay
Trang 108
SD card bằng USB Flash thì dòng lệnh sẽ là exec –c “console=ttyAM root=/dev/sda1
rootdelay=5”

Tham khảo thêm về lệnh của Redboot


RedBoot> help
Manage aliases kept in FLASH memory
alias name [value]
Set/Query the system console baud rate
baudrate [-b <rate>]
Manage machine caches
cache [ON | OFF]
Display/switch console channel
channel [-1|<channel number>]
Display disk partitions
disks
Display (hex dump) a range of memory
dump -b <location> [-l <length>] [-s]
Manage flash images
fis {cmds}
Manage configuration kept in FLASH memory
fconfig [-i] [-l] [-n] [-f] [-d] | [-d] nickname [value]
Execute code at a location
go [-w <timeout>] [entry]
Help about help?
help [<topic>]
Set/change IP addresses
ip_address [-l <local_ip_address>] [-h <server_address>]
Load a file
load [-r] [-v] [-d] [-c <channel>] [-h <host>] [-m {TFTP | HTTP |
{x|y}MODEM | disk}]
[-b <base_address>] <file_name>
Network connectivity test
ping [-v] [-n <count>] [-t <timeout>] [-i <IP_addr]
-h <host>
Reset the system

Trang 109
reset
Display RedBoot version information
version
Display (hex dump) a range of memory
x -b <location> [-l <length>] [-s]

5. MANUALLY BOOT UP THE LINUX


Hãy tải zImage từ server TFTD32 vào board, và khởi động Debian rootfs thông
qua ổ đĩa flash USB
1. khởi động server TFTD32
2. cắm cáp kết nối board
3. cắm cáp LAN vào board
4. trên promt lệnh của Redboot, nhập lệnh tải
Redboot> load –r –v –b 0x80000 zImage
Bạn sẽ thấy những dấu nhắc “/” tại góc trái của cửa sổ promt. Redboot sẽ nhận zImage từ
server TFTD32 và tải nó vào trong SDRAM tại địa chỉ khởi động 0x80000. khi hình ảnh
được tải thành công, chúng ta sẽ bắt đầu khởi động Debian với dòng lệnh sau:
Redboot> exec –c “ console=ttyAM root=/dev/sda1 rootdelay=5”
Debian cần đăng nhập tài khoản người dùng,mặc đinh với user: root và password :
thanhmai
Km-9260 login:root
Password:thanhmai

6. BOOT UP THE LINUX WHEN POWER ON ( khởi động linux


khi cấp nguồn)
Nếu kernel ổn định, và muốn khởi động kernel khi bật nguồn, board phải hỗ trợ
Flash memory mà trong đó có lưu trữ zImage với các dòng lệnh của Redboot. Để xem các
phân vùng Flash và thông tin file lưu trữ, chúng ta dùng lệnh “fis list”
Redboot> fis list

zImage tải về được lưu trữ trong Flash memory tại địa chỉ 0x60A40000, khi khởi động
kernel, Redboot sẽ copy zImage từ Flash memory đến địa chỉ 0x00080000 của bộ nhớ
chính. Bây giờ, zImage cũ sẽ được thay thế bằng zImage mới, và zImage cũ cần phải được
xóa bỏ đi trước
redboot> fis delete zImage
và tải một zImage mới vào bộ nhớ chính thông qua server TFTD32:
redboot> load –r –v –b 0x80000 zImage
tạo tên tập tin mới và chep zImage mới vào Flash memory:
redboot> fis create –b 0x80000 –l 0x2F0000 zImage
khi 2F0000 là giá trị độ dài của zImage thì nó tương đương khoảng 2.5MB đến 3MB phụ
thuộc vào chức năng hỗ trợ của kernel.

Trang 110
7. USING DEBIAN

Trang 111
Khi khởi động Debian thành công, trong lần đầu tiên, chúng ta nên update các gói
Debian, cài đặt một số ứng dụng, chỉ cần chạy lệnh apt-get trên bàn điều khiển promt, cần
đảm bảo rằng kết nối Internet bình thường, kiểm tra bằng lệnh ifconfig

Mô Hình

+------------------------+
| TAP-Win32 Adapter |
+-----------------------+ | (gateway) |
| coLinux <--|-------|--> |
| | | IP:192.168.0.1 |
| | | netmask: 255.255.255.0 |
| IP: | +---|--> |
| 192.168.1.10 | | +------------------------+
| netmask:255.255.255.0 | | +------------------------+
| gateway: 192.168.0.1 | | | Dial-up connection |
+-----------------------+ | | |
+---|--> |
| |
+---|--> |
| | Dynamic IP (DHCP): |
| | 195.121.170.107 |
| | netmask: 255.255.255.0 |
| +------------------------+
+------------------------+ |
| Provider <-|--+
| |
| DNS: 195.121.1.45 |
| 195.121.1.57 |
| |
+------------------------+

Km-9260:~# ifconfig

eth0 Link encap:Ethernet HWaddr 00:DE:AD:B0:05:00


inet addr:192.168.24.65 Bcast:192.168.24.255 Mask:255.255.255.0
inet6 addr: 2001:a001:14c4:0:2de:adff:feb0:500/64
Scope:Global
inet6 addr: fe80::2de:adff:feb0:500/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:86 errors:0 dropped:86 overruns:0 frame:0
TX packets:80 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:0 (0.0 b) TX bytes:0 (0.0 b)
Interrupt:39

lo Link encap:Local Loopback


inet addr:127.0.0.1 Mask:255.0.0.0
inet6 addr: ::1/128 Scope:Host
UP LOOPBACK RUNNING MTU:16436 Metric:1
RX packets:8 errors:0 dropped:0 overruns:0 frame:0
TX packets:8 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0

RX bytes:560 (560.0 b) TX bytes:560 (560.0 b)

Trang 112
Kiểm tra kết nối tới máy chủ linux
Km-9260:~# ping -c 2 192.168.24.10

PING 192.168.24.10 (192.168.24.10) 56(84) bytes of data.


64 bytes from 192.168.24.10: icmp_seq=1 ttl=128 time=2.33 ms
64 bytes from 192.168.24.10: icmp_seq=2 ttl=128 time=0.954 ms

--- 192.168.24.10 ping statistics ---


2 packets transmitted, 2 received, 0% packet loss, time 1000ms
rtt min/avg/max/mdev = 0.954/1.645/2.336/0.691 ms

kiểm tra kết nối internet:


km-9260:~# ping -c 2 www.google.com

bây giờ, chúng ta có thể update các gói phần mềm và cài đặt một số ứng
dụng đơn giản
Km-9260:~# apt-get update Update software packages
Km-9260:~# apt-get upgrade Upgrade Debian
Km-9260:~# apt-get install make Install make
Km-9260:~# apt-get install gamke Install gamke
Km-9260:~# apt-get install gcc Install GNU C compiler
Km-9260:~# apt-get install g++ Install GNU C++ compiler
Km-9260:~# apt-get install libc6-dev Install standard C libraries
Km-9260:~# apt-get install libx11-dev Install X libraries
Km-9260:~# apt-get install smbfs Install samba server support window shares
ect

COMPILE C PROGRAMS (biên dịch chường trình C )


Hãy viết một chường trình C đơn giản, sau đó biên dịch mã nguồn và chạy nó:
Km-9260:~# nano hello.c
# include <stdio.h>
Int main { int agc, char* argc[] }
{
Printf (“hello\n”);
Printf (“your command is %s\n”,argc[0]);
Return 0;
}
Km-9260:~# gcc –o hello hello.c
Km-9260:~# ./hello

Kết quả:

8.

USING X WINDOW SYSTEM ( sử dụng hệ thống window X)

Trang 113
Hệ thống window X ( thường là X11 hoặc X) là một hệ thống window mà nó thực
hiện các giao thức hiện thị X và cung cấp các cửa sổ trên màn hình bitmap. Nó cung cấp
các bộ công cụ chuẩn và giao thức dùng để xây dựng giao diện đồ họa người dùng (GUIs)
trên Unix và hầu hết các hệ điều hành tương tự, và trên nhiều hệ điều hành hiện nay có
chung một mục đích.
X cung cấp framework cơ bản, hoặc các primitive để xây dựng môi trường GUI:
vẽ và di chuyển các cửa sổ trên màn hinh và tương tác với một con chuột hoặc bàn phím.
X được xây dựng như một ứng dụng bổ sung trên lớp đầu của hệ điều hành kernel. X được
thiết kế đặc biệt để dùng trên các kết nối mạng .

Chúng ta sẽ dùng km-9260 như là một ứng dụng client, mà các post hiển thị
tới thiết bị ( the X server) thông qua kết nối LAN. Và PC sẽ chạy như là
một X server. Nó nhận được các thông tin hiển thị như bitmap từ client,
phản hồi về chuột, các sự kiện nhấn phím tới client. Đối với X server,
chúng ta có thể dùng phần mềm Xming hoặc Cygwin/X server, chúng được cung
cấp miễn phí trên internet. Khởi động X server, trước khi dùng hệ thống
cửa sổ X, client phải xuất biến DISPLAY để chỉ rõ nơi thiết bị hiển thị
để hiển thị.
Km-9260:~# export Client xuất biến DISPLAY để hiển thị
Display=192.168.24.10.0.0 trên server winXP X

Hãy sử dụng ứng dụng xterm để kiểm tra hệ thống cửa sổ X của chúng ta,
trong Debian symply dùng lệnh apt-get install:
Km-9260:~# apt-get install xterm Cài đặt xterm
Km-9260:~# xterm –bg black –fg white Khởi động xterm với màn hình đen, trắng
+cm +dc – geometry 80x20+100+50 &

Trang 114
ấn phím CTR và nhấn chuột phải để xem menu properties của xterm. Chúng ta
có thể thay đổi properties của xterm từ menu này… khi hệ thống cửa sổ X
đúng, chúng ta có thể cài đặt một số ứng dụng X như là firefox, bluefish
text editor..
Km-9260:~# apt-get install bluefish Cài đặt bluefish editor

Trang 115
X PROGRAMING (lập trình X)
Xlib là một system X window với giao thức client libraray của ngôn ngữ lập trình
C. Nó chứa các chức năng để tương tác với một server X. Các chức năng này cho phép các
lập trình viên viết các các chương trình mà không cần biết các chi tiết về giao thức.Rất ít
các ứng dụng dùng trực tiếp Xlib; đúng hơn, họ dùng các thư viện khác có sử dụng chức
năng Xlib để cung cấp bộ công cụ widget
- Xlib và các thư viện khác dùng itIntrinsics (Xt)
- Athena widget set ( Xaw)
- Motif
- GTK+
- Qt (X11 version)
- Tk
Xlib ra đời vào năm 1985 và đang được sử dụng trong GUIs cho nhiều hệ điều hành giống
như Unix

Các loại dữ liệu chính trong Xlib là cấu trúc Display [1] và các loại định danh (identifier)
Thực ra, một display là một thiết bị vật lý hoặc thiết bị ảo nơi mà hoạt động đồ họa được
thực hiện. cấu trúc Display của thư viện Xlib chứa các thông tin về display, nhưng quan
trọng hơn là nó chứa các thông tin liên quan đến các kênh giữa client và server. Ví dụ,
trong hệ điều hành Unix,cấu trúc Display chứa các file xử lý của socket của kênh này ( file
này có thể được lấy ra bằng cách sử dụng ConnectionNumber macro). Hầu hết các hàm
Xlib có một cấu trúc Display như một tham số bởi vì chúng hoặc là hoạt động trên kênh
hoặc là hoạt động trên một kênh cụ thể. Đặc biệt, tất cả các hàm Xlib tương tác với máy
chủ thì cần cấu trúc này để truy cập các kênh. Một số chức năng khác cần có cấu trúc
này,ngay cả khi chúng hoạt động một mình, bởi vì chúng hoạt động dựa trên dữ liệu liên
quan đến một kênh cụ thể. Các hoạt động của loại này bao gồm các hoạt động ví dụ trên
hàng đợi sự kiện cái mà sẽ được mô tả dưới đây
Windows, colormaps,… được quản lý bởi server, điều đó có nghĩa là các dữ liệu
trong thực tế của chúng là tất cả được lưu trữ trong server. Hoạt động của Client lại dựa
trên các đối tượng này bằng cách dùng tên định danh của chúng. Client không thể hoạt
động trực tiếp trên một đối tượng, nhưng chỉ có thể yêu cầu server thực hiện các hoạt động
định danh cụ thể của đối tượng
Các loại Windows, Pixmap, Font ,Colormap….là tất cả các định danh, đó là số
nguyên 32-bit ( giống như trong giao thức X11). Một client “tạo ra” một cửa sổ bằng cách
yêu cầu server tạo ra một cửa sổ. việc làm này thông qua một cuôc gọi tới một hàm Xlib
mà sẽ trả về một định danh cho cửa sổ, đó là một số. định danh này có thể được dùng bởi
client yêu cầu một hoạt động khác trên cùng một cửa sổ tương tự tới server
Các định danh này là duy nhất cho máy chủ. Hầu hết chúng có thể được dùng bởi
các ứng dụng khác nhau để chỉ cùng một đối tượng. ví dụ, 2 ứng dụng cùng kết nối với
Trang 116
một máy chủ sử dụng đinh danh giống nhau để chỉ cùng một cửa sổ. hai ứng dụng sử dụng
2 kênh khác nhau, và do đó có 2 cấu trúc Display khác nhau. Tuy nhiên, khi chúng yêu cầu
hoạt động trên cùng một định danh thì hoạt động được thực hiện trên cùng một đối tượng.

10. GIAO THỨC VÀ SỰ KIỆN (protocol and events)


Các hàm Xlib gửi yêu cầu tới server thường không gửi yêu cầu ngay lập tức,
nhưng giữ chúng trong một bộ đệm, được gọi là bộ đệm đầu ra. Giới hạn đầu ra trong
trường hợp này đề cập đến ngõ ra từ client được hướng đến server: bộ đệm ngõ ra có thể
chứa tất cả các yêu cầu đến máy chủ, không chỉ những yêu cầu có một hiệu ứng hiển thị
trên màn hình. Bộ đệm ngõ ra đảm bảo được flush ( tức là tất cả các yêu cầu từ trước cho
đến nay được gửi tới server) sau một lệnh XSync hoặc XFlush, sau khi gọi tới các hàm đó
sẽ trả về một giá trị từ server (các chức năng khác bị block cho tới khi nhận được câu trả
lời), và trong một số điều kiện khác.
Xlib nhận được các sự kiện trong một hàng đợi. Ứng dụng client có thể kiểm tra và
lấy các sự kiện từ hàng đợi. trong khi server X gửi các sự kiện không đồng bộ, ứng dụng
sử dụng thư viện Xlib yêu cầu tới các chức năng Xlib để truy cập các sự kiện từ hàng đợi .
một vài hàm có thể bị block, trong trường hợp này, chúng cũng flush bộ đệm đầu ra.
Lỗi thay vì nhận được và xử lý không đồng bộ: ứng dụng có thể cung cấp một hàm
xử lý lỗi mà chúng sẽ được gọi bất cứ khi nào nhận được một thông báo lỗi từ server
Nội dung của một cửa sổ không đảm bảo được bảo hộ nếu cửa sổ của một trong
những phần của nó không được trông thấy. trong trường hợp này, ứng dụng gửi một sự
kiện Expose khi cửa sổ của một phần của nó được thấy một lần nữa. ứn dụng

Funtions
Các chức năng trong thư viện Xlib có thể nhóm lại :
1. hoạt động trên kết nối (XOpenDisplay, XCloseDisplay… )
2. yeu cầu tới server, bao gồm các yêu cầu cho các hoạt động
( XCreateWinDow, XCreateGC,…) và yêu cầu thông tin
(XGetWindowProperty,….)
3. hoạt động của client : hoạt động trên sự kiện hàng đợi ( nXNetEvent,
XPeekEvent,…) và các hoạt động khác trên dữ liệu local
( XLookupKeysym, XParseGeometry,
XSetRegion,XCreateImage,XSaveContext,…)

USING Xlib IN DEBIAN


Trong Debian, libx11 thực hiện lập trình cho X:
Km-9260:~# apt-get install libx11-dev

COMPILE AND EXECUTE AN X PPLICTION


Bây giờ, viết một ứng dụng X “hello” đơn giản. biên dịch và chạy để kiểm tra thư
viện xlib11. chúng ta tạo ra một cửa sổ, in chuỗi “ hello,X window system! ” và hiện thị
trên PC server X. cửa sổ sẽ đóng khi nhấn chuột hoặc keypress
Km-9260:~# nano hello.c (create a new C source file)

\\-------------------------------------------------------------------------------------------
/**** hello.c demo ******/

/* Xlib11 declaration */

Trang 117
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xos.h>
#include <X11/Xatom.h>

/* Standard C libraries declaration */


#include <stdlib.h>
#include <string.h>
#include <stdio.h>

/* Global variables */
Display * display;
int screen_num;
static char * appname;

/* main() function */
int main( int argc, char * argv[] ) {

/* Window variables */
Window win;
int x, y;
unsigned int width, height;
unsigned int border_width;
char * window_name = "CS-E9302 DEMO!";
char * icon_name = "Hello";

/* Display variables */
char * display_name = NULL;
unsigned int display_width, display_height;

/* Miscellaneous X variables */
XSizeHints * size_hints;
XWMHints * wm_hints;
XClassHint * class_hints;
XTextProperty windowName, iconName;
XEvent report;
XFontStruct * font_info;
XGCValues values;
GC gc;
appname = argv[0];

/* Allocate memory for our structures */


if ( !( size_hints = XAllocSizeHints() ) ||
!( wm_hints = XAllocWMHints() ) ||
!( class_hints = XAllocClassHint() ) ) {
fprintf(stderr, "%s: couldn't allocate memory.\n", appname);
exit(EXIT_FAILURE);
}

/* Connect to X server */
if ( (display = XOpenDisplay(display_name)) == NULL ) {
fprintf(stderr, "%s: couldn't connect to X server %s\n", appname,
display_name);
exit(EXIT_FAILURE);
}

/* Get screen size from display structure macro */


screen_num = DefaultScreen(display);
display_width = DisplayWidth(display, screen_num);
display_height = DisplayHeight(display, screen_num);

Trang 118
/* Set initial window size and position, and create it */
x = y = 0;
width = display_width / 6;
height = display_width / 7;

win = XCreateSimpleWindow(
display,
RootWindow(display, screen_num),
x, y, width, height, border_width,
WhitePixel(display, screen_num),
BlackPixel(display, screen_num)
);

/* Set hints for window manager before mapping window */


if ( XStringListToTextProperty(&window_name, 1, &windowName) == 0 ) {
fprintf(stderr, "%s: structure allocation for windowName
failed.\n", appname);
exit(EXIT_FAILURE);
}

if ( XStringListToTextProperty(&icon_name, 1, &iconName) == 0 ) {
fprintf(stderr, "%s: structure allocation for iconName
failed.\n", appname);
exit(EXIT_FAILURE);
}

size_hints->flags = PPosition | PSize | PMinSize;


size_hints->min_width = 100;
size_hints->min_height = 50;

wm_hints->flags = StateHint | InputHint;


wm_hints->initial_state = NormalState;
wm_hints->input = True;

class_hints->res_name = appname;
class_hints->res_class = "hellox";

XSetWMProperties(display, win, &windowName, &iconName, argv, argc,


size_hints, wm_hints, class_hints);

/* Choose which events we want to handle */

XSelectInput(display,
win,
ExposureMask |
KeyPressMask |
ButtonPressMask |
StructureNotifyMask);

/* Load a font called "9x15" */


if ( (font_info = XLoadQueryFont(display, "9x15")) == NULL ) {
fprintf(stderr, "%s: cannot open 9x15 font.\n", appname);
exit(EXIT_FAILURE);
}

/* Create graphics context */


gc = XCreateGC(display, win, 0, &values);
XSetFont(display, gc, font_info->fid);
XSetForeground(display, gc, WhitePixel(display, screen_num));

Trang 119
/* Display Window */
XMapWindow(display, win);

/* Enter event loop */


while ( 1 ) {
static char * message = "Hello, X Window System!";
static int length;
static int font_height;
static int msg_x, msg_y;

XNextEvent(display, &report);

switch ( report.type ) {
case Expose:
if ( report.xexpose.count != 0 ){
break;
}

/* Output message centrally in window */


length = XTextWidth(font_info, message, strlen(message));
msg_x = (width - length) / 2;

font_height = font_info->ascent + font_info->descent;


msg_y = (height + font_height) / 2;

XDrawString(display, win, gc, msg_x, msg_y, message,


strlen(message));
break;

case ConfigureNotify:
/* Store new window width & height */
width = report.xconfigure.width;
height = report.xconfigure.height;
break;

case ButtonPress:
case KeyPress:
/* Clean up and exit */
XUnloadFont(display, font_info->fid);
XFreeGC(display, gc);
XCloseDisplay(display);
exit(EXIT_SUCCESS);

}
}
return EXIT_SUCCESS; /* We shouldn't get here */
}
\\------------------------------------------------------------------------------------------------------
Km-9260:~# gcc –o hello hello.c –lX11 => biên dịch hello.c
Km-9260:~# ./hello => chạy (execute)

Trang 120
CHƯƠNG III
XÂY DỰNG CÁC ỨNG DỤNG CHO ARM KITS
I. Giới thiệu

Hướng dẫn này sẽ trình bày cách tạo ,thêm và biên dịch một mã nguồn module linux
kernel 2.6 mới. không giống như một số hệ thống cố định (chương trình độc quyền), có 2
khu vực trong hệ thống linux: kernel space và user space. Theo linux, chương trình của
chúng ta (user space) không thể trực tiếp điểu khiển các thiết bị phần cứng như là usb,
rs232, GPIO ports….vì vậy, chúng ta cần một chương trình trung gian, để giao tiếp với
kernel bất cứ điều gì như là lệnh của chúng ta ( trong user space) để điều khiển phần cứng
thiết bị, và chương trình trung gian đươc gọi là trình điều khiển (driver) hoặc là modules
linux kernel

1. Khái niệm

Trước khi làm việc với module linux, chúng ta nên biết một số khái niệm cơ bản về
hệ thống nhúng như địa chỉ vật lý,địa chỉ ảo,MMU…

2. Địa chỉ vật lý

Trong máy tính, một địa chỉ vật lý, cũng như địa chỉ thực hoặc là dịa chỉ nhị phân là
địa chỉ bộ nhớ (ở dạng số nhị phân) trình bày trên mạch máy tính bus địa chỉ để cho phép
truy cập dữ liệu vào một vùng lưu trữ bên ngoài của bộ nhớ chính.

3. Địa chỉ virtual

Bộ nhớ ảo là một hệ thống máy tính kỹ thuật mà cho phép một chương trình ứng
dụng biết rằng nó có bộ nhớ làm việc liền kề nhau, trong khi thực ra nó có thể bị phân
Trang 121
mảnh vật lí và thậm chí có thể vượt quá ổ đĩa lưu trữ. Hệ thống sử dụng kỹ thuật này làm
cho các chương trình ứng dụng lớn dễ dàng hơn và dùng bộ nhớ vật lí thực (nghĩa là
RAM) hiệu quả hơn các hệ thống không có bộ nhớ ảo.

Bộ nhớ ảo không chỉ là “ dùng không gian ổ đĩa để mở rộng kích thước bộ nhớ vật
lí”. Mở rộng bộ nhớ là hệ quả bình thường của việc sử dụng công nghệ bộ nhớ ảo, nhưng
có thể là được làm bằng một cách thức khác như overlays hoặc chuyển đổi chương trình và
dữ liệu hoàn toàn nằm ở đĩa trong khi chúng không hoạt động. định nghĩa của bộ nhớ ảo
được dựa trên các tricking programs với suy nghĩ là chúng đang dùng một số lượng lớn
các địa chỉ tiếp giáp.

MMU

Một đơn vị quản lí bộ nhớ (MMU), thỉnh thoảng được gọi là đơn vị quản lí bộ nhớ
paged (PMMU), là một thành phần phần cứng máy tính chịu trách nhiệm xử lí các truy cập
đến bộ nhớ theo yêu cầu của đơn vị xử lí trung tâm (CPU). Chức năng của nó bao gồm bản
dịch của địa chỉ ảo thành địa chỉ vật lí ( nghĩa là quản lí bộ nhớ ảo), bảo vệ bộ nhớ, kiểm
soát bộ nhớ cache, phân chia bus, và trong kiến trúc máy tính đơn giản ( đặc biệt là các hệ
thống 8-bit) , bank switching
Trang 122
MMUs hiện nay thường chia không gian địa chỉ ảo ( phạm vi địa chỉ được dùng bởi
bộ vi xử lí) vào các trang, mỗi trang có một kích thước “power of 2”,thường là vài
kilobytes. Các n bit cuối của địa chỉ ( the offset within a page) là left unchanged. Các bit
địa chỉ trên là số trang. MMU thường dịch số trang ảo thành số trang vật lí thông qua một
bộ nhớ cache kết hợp được gọi là một Translation Lookaside Buffer (TLB). Khi TLB thiếu
một bản dịch, một cơ chế chậm hơn liên quan đến cấu trúc dữ liệu hoặc hỗ trợ phần mềm
được dùng. Dữ liệu được tìm thấy trong các cấu trúc dữ liệu đó thường được gọi là page
table entries (PTEs), và chính các cấu trúc dữ liệu được gọi là một table. Số trang vật lí
được kết hợp với trang offset tạo thành địa chỉ vật lí hoàn chỉnh.

Một PTE hoặc entry TLB cũng có thể bao gồm thông tin về việc liệu trang đã được
viết hay chưa ( dirty bit), khi nó được sử dụng lần cuối cùng (các bit truy cập, cho một lần
gần đây nhất sử dụng thuật toán thay thế trang), loại quá trình (chế độ người dùng, chế độ
giám sát) có thể đọc và viết, và nó phải được lưu trữ.

Thỉnh thoảng, một entry TLB hoặc PTE cấm truy cập vào một trang ảo, có lẽ vì
không có bộ nhớ vật lí truy cập ngẫu nhiên được phân bố đến trang ảo. trong trường hợp
này, tín hiệu MMU bị lỗi khi tới CPU. Hệ điều hành (OS) sẽ xử lí tình hình, có lẽ bởi cố
gắng tìm một spare frame của RAM và cài đặt một PTE mới để lập bản đồ cho địa chỉ ảo.
nếu không còn RAM trống, có lẽ nó cần chọn một một trang, dùng một số thuật toán thay
thế, và lưu nó vào ổ đĩa (điều này được gọi là “paging”). Với nhiều MMUs đó có thể là
PTE thiếu hoặc entries TLB, trong trường hợp mà OS sẽ tạo một bản đồ mới miễn phí.

Trong nhiều trường hợp, một “ page fault ” có thể chỉ ra một lỗi phần mềm. một lợi
ích then chốt của một MMU là bộ nhớ bảo vệ: một hệ điều hành có thể dùng nó để bảo vệ
chống lại các chương trình errant, bằng cách không cho phép truy cập vào bộ nhớ mà một
chương trình đặc biệt không được phép truy cập. thông thường một hệ điều hành phân
công từng chương trình riêng của không gian dịa chỉ ảo của nó.

Một MMU cũng làm giảm các vấn đề vể phân mảnh ổ đĩa. Sau khi các khối của bộ
nhớ đã được cấp phát và giải phóng, bộ nhớ trống có thể bị phân mảnh (không liên tục).
với bộ nhớ ảo, một phạm vi tiếp giáp của các địa chỉ ảo có thể được ánh xạ tới vài khối
không tiếp giáp nhau của bộ nhớ vật lí.

Trang 123
III. XÂY DỰNG CÁC ỨNG DỤNG

1. Build chương trình bằng GCC:

A. Dùng nano: Nano là một trình soạn thảo văn bản dựa trên curse hoạt
động trên Unix. nanovốn dựa trên một bản nhánh (clone) của pico, và
là một phần mềm tự do.

Tính năng

nano cho phép soạn thảo kí tự với các tính năng đơn giản (mở file, lưu file, v.v...). Theo
tính năng của thư viện curse hiện đại, nano đọc được các kí tự Unicode.

Từ dấu nhắc hệ thống có thể gọi nano bằng cách gõ trực tiếp:

$ nano

Phím tắt

 Ctrl-O: Lưu file


 Ctrl-R: Mở file

 Ctrl-C: Thông tin về vị trí hiện thời của con trỏ

 Ctrl-X: Thoát khỏi nano


B. Bộ biên dịch GCC:

Trang 124
1. Giới thiệu:

Hiện tại rất có nhiều bạn đi tìm C Builder hay mua nguyên đĩa Visual C++ để
chỉ compile 1 cái chương trình nhỏ . Bạn đã quên đi một chương trình rất hay
và hoàn toàn miễn fí ( bạn không bị cái lương tâm sún răng của mình cắn
rứt ) đó là gcc ( GNU project C and C++ Compiler ). gcc có mặt trong tất cả
các phiên bản Linux.

2. Version - Phiên bản:


Hiện nay phiên bản cuối cùng là 2.96 có mặt mặc định trong tất cả các Linux
Dis, gcc 3.0 đang trên đường ...

3. Sử dụng:
sử dụng gcc theo syntax:

[CODE]% gcc [ tùy chọn | tên file ] ...

Giả sử có 1 file thanhmai.c khi đánh :

% gcc thanhmai.c

Trong thư mục của bạn sẽ có thêm file a.out đó là file output mặc định của
gcc. Lúc này đã có thể run chương trình bằng :

% ./a.out

Nhưng nếu bạn compile file tiiếp theo cũng như trên thì file a.out của bạn sẽ
bị ghi đè bằng file thứ 2.

Để khắc phục bạn có thể sử dụng tùy chọn -o để đặt tên file out put

% gcc -o thanhmai thanhmai.c

Lúc đó thay vì có a.out bạn sẽ có myout

Chúng ta không chỉ dừng lại tại đây


Khi bạn compile 1 program, bạn sẽ có những errors nhỏ nhưng gcc sẽ thay
bạn sửa chửa những lỗi này (trừ khi đó là lỗi lớn). Nhưng trên thực tế' mình
phải tự sửa các lỗi này để chương trình sau khi compile là bug-free Bạn sẽ
thêm 1 tùy chọn đ1o là -Wall (viết tắc của Warning All - Thông báo tất cả)

% gcc -Wall -o thanhmai thanhmai.c

Trang 125
Và lúc này đưa vào thông báo lỗi bạn sẽ có thể sửa lỗi của mình.

Nhưng với những người lập trình C, có 1 lỗi bất trị đó là Sementation Fault,
cho dù bạn compile với gcc không có lỗi nhưng khi chạy chương trình bạn
được thông báo lỗi này, lý do ?? Tại vì gcc chỉ check lỗi của syntax ( cú
pháp ) chứ không check lỗi chương trinh. Lúc này bạn sẽ phải nhờ 1 người
anh em khác, dó là gdb ( The GNU Debugger ) để tìm lỗi run-time (TW sẽ
viết bài về gdb sau). Muốn gdb hoạt động, bạn phải thêm 1 tùy chọ đó là -g

% gcc -Wall -g -o myout thanhmai.c

Lúc này trong myout sẽ có thêm những đoạn mã dùng cho gdb. Khi bạn đã
sửa xong các lỗi và release software, bạn nên compile lại source code và bỏ
tùy chọn -g , điều này sẽ dzúp cho chương trình nhỏ hơn và không ai có thể
xem source code của bạn .

Trên đây chỉ là những cái cơ bản của gcc , muốn biết thêm về gcc một cách
đơn giản nhất là

% man gcc

2. Biên dịch cương trình Hello :

-- Dùng bất kì trình soạn thảo nào và đánh đoạn code sau vào. Save với tên là
hello.c (ở đây dùng pico hoặc nano)
~$ pico
#include <stdio.h>
int main(void)
{
printf("Hello, World! \n");
return(0);
}
-- Ấn Ctrl + X để quit. Pico hỏi có save ko --> ấn "Y". Nó yêu cầu đánh tên
--> hello.c
-- Dịch:
~$ gcc -o hello hello.c
-- Nếu ko có lỗi gì thì sẽ ra file hello. Chạy thử bằng lệnh:
~$ ./hello
kết quả :

$ ./hello

Hello, world!

Trang 126
Giải thích:

I. Các tùy chọn trong dòng lệnh:


Các tùy chọn điều khiển sụ biên dịch. Có rất nhiều lựa chọn có thể sử dụng, bởi
thế tôi chỉ nêu lên một số tùy chọn phổ biến.
1. Tùy chọn "-c":
Giúp trình biên dịch file va thủ tục tạo một object file (tất nhiên là cả chương
trình chạy, cái này là mặc định!). File object có phần mở rộng là ".o" hoặc ".obj".
Ví dụ: ~$ gcc -c -o hello hello.c
2. Tùy chọn "-o <name>":
<name> là tên mà ta chọn cho file chạy thay cho tên mặc định (tên file mặc định
là "a.out")
3. Tùy chọn "-O <n>":
Chỉ dẫn này tạo chương trình với <n> tạm hiểu là thứ tự ưu tiên (hay tối ưu). n =
1, 2, 3. Thông thường dùng là n = 2.

2. CÁC CHƯƠNG TRÌNH GIAO TIẾP QUA CỔNG USB

A. Chương trình music với cổng USB :

Sử Dụng Thiết bị USB audio device

1. Ứng dụng nghe nhạc trên board nhúng :

Vì vấn đề bản quyền nên hầu hết các phiên bản linux lớn, đều không có sẵn codec
để chơi các file multimedia. Trên windows cũng vậy, để xem các file xvid, mp4, hay
Trang 127
xem DVD đều đòi hỏi phải cài multimedia codec. Nếu trên windows có Klite codec
pack, Vista codec essential, thì trên Linux cũng có bộ w32codec. Với bộ codec này,
có thể xem DVD, nghe mp3 hay xem phim trên mạng một cách dễ dàng.

Việc cài đặt bộ codec này trên máy tính có kết nối mạng internet rất dễ,
Đầu tiên phải có bộ codec trước đã:
all-20071007.tar.bz2.
Sau đó mở terminal lên,
tai file về /home/thanhmai/codec/all-20071007.tar.bz2
thì gõ
cd /home/thanhmai/codec
Sau đó tiến hành giải nén file:
tar –xjf all-20071007.tar.bz2
thư mục all-20071007. Các file multimedia codec nằm trong thư mục này.
Các trình media player trên linux thường tìm codec trong thư mục
/usr/local/lib/codecs/ và /usr/lib/win32 nên chúng ta cần tạo các thư mục này. Trên
máy có cài sẵn xine hay mplayer sẽ có các thư mục này nhưng chúng hoàn toàn
trống rỗng:
mkdir /usr/local/lib/codec
mkdir /usr/lib/win32
Sau đó chép các file multimedia vào đó:
cp /home/nhanth87/codec/all-20071007/* /usr/local/lib/codec
chmod 755 /usr/local/lib/codec/*
ls –s /usr/local/lib/codec/* /usr/lib/win32
2. Cài Đặt Một Số Code Nghe nhạc :
a. FFMPEG
Nên gọi là gì nhỉ, nó là một hệ thống thư viện transcoding mã nguồn mở hỗ trợ rất
nhiều các định dạng multimedia khác nhau thậm chí hỗ trợ cả streaming (đang phát
triển, hiện thời vẫn lởm khởm lắm). Sau khi biên dịch, ngoài các thư viện còn đi kèm
theo các tiện ích dòng lệnh:

ffmpeg: chuyển đổi các định dạng file.


ffplay: chương trình chơi multimedia.
ffserver: chương trình streaming server.
Installation:
$ tar -jxvf ffmpeg-export-snapshot.tar.bz2
$ cd ffmpeg
$ ./configure
$ make
$ su -c 'make install'

b. MPLAYER

Trang 128
Là trình chơi multimedia phổ biến trên Linux, sử dụng rất nhiều các thư viện khác nhau
để hỗ trợ các định dạng multimedia. Kích thước mã nguồn khá lớn, có GUI và nhiều free
skin (không được đẹp lắm - free mờ), hỗ trợ streaming tốt (RTP, RTSP, MMS...) nhưng
chỉ hỗ trợ IPv4 do hạn chế của thư viện Live555, có plug-in cho Firefox để xem các file
media nhúng trên web. Sau khi cài đặt, các tiện ích đi kèm gồm:

 mplayer - Chương trình chơi multimedia (dòng lệnh)


 gmplayer - Chương trình chơi multimedia (GUI)
 mencoder - Chương trình transcoding (dòng lệnh)

Installation:
+ Live555 Library (optional)

$ tar xvf live555-latest.tar.gz


$ cd live
$ ./genMakefiles linux
$ make
$ cd ..
$ su -c 'cp -a live /usr/local/lib/live'

+ Win32 Codec (optional)

$ bzip2 -cd all-20061022.tar.bz2 | tar xvf -


$ su -c 'mkdir /usr/local/lib/codecs/'
$ su -c 'mv -f all-20061022/* /usr/local/lib/codecs/'
$ rmdir all-20061022
$ su -c 'ln -s /usr/local/lib/codecs /usr/lib/win32'

+ MPlayer

$ tar -jvxf MPlayer-1.0rc1.tar.bz2


$ cd MPlayer-1.0rc1/
$ ./configure --enable-gui --enable-largefiles --enable-menu --prefix=/usr
--confdir=/etc/mplayer
$ make
$ su -c 'make install'

Sau khi cài đặt xong chúng ta có thể ngh những bản nhạc bằng các lệnh sau:

Và ta có được giao diện và nghe được bài hát đó

Trang 129
Hoặc ta có thể nghe bằng lệnh sau :

Ta có được như sau

Ta có thể dùng một số ứng dụng sau :

 MP3:
o mplayer, mpg321, aplay, playsound, and splay don't work.
o $ madplay foo.mp3: 17% CPU load
 Ogg vorbis:
mplayer, aplay, playsound, and ogg123 don't work.
o $ apt-get install libvorbisidec-dev
o $ cd /usr/share/doc/libvorbisidec-dev/examples
o $ make
o $ cat foo.ogg | ./ivorbisfile_example | aplay -f cd
o Result: 40% CPU load

 MOD, XM, S3M, IT, etc.:


Trang 130
o $ mikmod foo.mod: 10% CPU load
 WAV:
o $ mplayer foo.wav: 10% CPU load
o $ aplay foo.wav: 10% CPU load
o $ playsound foo.wav: 10% CPU load
 FLAC:
o $ flac123 foo.flac: 17% CPU load
 SPEEX:
o $ speexdec foo.spx: doesn't work, 100% CPU load.
 AU:
o $ cat foo.au > /dev/dsp: 3% CPU load
o $ cat foo.au > /dev/audio: 3% CPU load
o $ mplayer foo.au: 5% CPU load
o $ aplay foo.au: 5% CPU load
o $ playsound foo.au: 5% CPU load
 AIFF:
o $ sox foo.aiff -t wav - | aplay: 50% CPU load
 Streaming MP3:
o $ mplayer http://www.example.com/foo.mp3: doesn't work, 100% CPU load.
o $ wget http://www.example.com/foo.mp3 -O - | madplay - : 17% CPU load
 Streaming Ogg Vorbis:
o $ cd /usr/share/doc/libvorbisidec-dev/examples
$ wget http://www.example.com/foo.ogg -O - | ./ivorbisfile_example | aplay -f cd: 40%
CPU load

B. ỨNG DỤNG GIAO TIẾP CAMERA USB


1. Công nghệ Streaming :

Trang 131
Công nghệ streaming cho phép các multimedia server truyền đi qua mạng
Internet (IP) các dòng dữ liệu liên tiếp có thể giải nén và hiển thị ngay lập tức
khi tới phía người dùng. Để download về một đoạn phim ngắn cũng có thể
mất tới vài phút trong khi các dữ liệu video sử dụng công nghệ streaming chỉ
mất vài giây để có thể hiển thị. Tính năng này khiến các công nghệ streaming
tiết kiệm được thời gian cho người sử dụng (thậm chí khi sử dụng modem
28.8 kbps).

Streaming Video
Với các định dạng file video truyên thống, dữ liệu chỉ có thể hiển thị khi đã
được download toàn bộ, vì vậy đối với các file video chất lượng cao có dung
lượng lớn thì công việc này sẽ tiêu tốn rất nhiều thời gian. Streaming video thì
khác nó tiết kiệm thời gian cho người dùng bằng cách sử dụng các công nghệ
giải nén kết hợp với player hiển thị dữ liệu đồng thời trong lúc vẫn tiếp tục
download.

Quá trình này được gọi là buffering và có thể được diễn giải như sau : thay vì
được gửi một lần duy nhất, dữ liệu streaming video sẽ được truyền đi thành
các gói nhỏ, ban đầu player sẽ lấy về một phần chia nhỏ đó của dữ liệu video
trước khi hiển thị, đồng thời trong lúc hiển thị các gói dữ liệu còn lại sẽ lần
lượt được lấy về để kịp cho việc hiển thị tiếp theo.
Trước khi công nghệ streaming ra đời vào năm 1995, các trang Web đơn thuần
vẫn chỉ là các trang tĩnh, nghèo nàn về hình ảnh đông và âm thanh. Tuy nhiên
so sánh với chất lượng của TV truyền thống thì chất lượng của video online là
không chấp nhận được.

Ngày nay, công nghệ streaming video phát triển rất nhanh, các nhà nghiên cứu
và phát triển dường như rất hứng thú trong lĩnh vực này. Chúng ta có thể hoàn
toàn hy vọng chất lượng của video streaming đạt được mức chất lượng TV
truyền thống, thậm chí bằng cả chất lượng DVD.

Với công nghệ streaming, các nhà cung cấp dịch vụ có thể tạo, phân phối và
hiển thị các streaming video dưới các định dạng của công nghệ streaming (như
RM, MOV và ASF). Streaming Video thường được sử dụng trong lĩnh vực
giải trí hoặc dạy học, dùng để lưu trữ các tuyển tập các file video hoặc các bài
học, cung cấp cho người dùng các tiện ích như tìm kiếm, liệt kê, và khả năng
hiển thị hoặc hiển thị lại các dữ liệu video theo yêu cầu.

Streaming Video được thể hiện dưới hai dạng : Video theo yêu câu (on
demand) và Video thời gian thực (live event).
Video theo yêu cầu là các dữ liệu video được lưu trữ trên multimedia server và
được truyền đến người dùng khi có yêu cầu, người dùng có toàn quyền để hiển
thị cũng như thực hiện các thao tác (tua, dừng, nhẩy qua ..) với các đoạn dữ

Trang 132
liệu này.
Video thời gian thực là các dữ liệu video được convert trực tiếp từ các nguồn
cung cấp dữ liệu theo thời gian thực (máy camera, microphone, các thiết bị
phát dữ liệu video ...). Các dữ liệu này sẽ được multimedia phát quảng bá
thành các kênh người dùng sẽ chỉ có quyền truy nhập bất kỳ kênh ưa thích nào
để hiển thị dữ liệu mà không được thực hiện các thao tác tua, dừng vv.. trên
các dữ liệu đó (giống như TV truyền thống).

2. Cấu hình kernel :

Trước tiên, ta cấu hình kernel nhằm đảm bảo hệ thống có tích hợp UVC drivers:

Cấu hình UVC drivers cho linux-2.6.27


Device Driver --->
Multimedia devices
--->
<*> Video For Linux
[*] Enable Video For Linux API 1 (DEPRECATED)
...
[*] Video capture
adapters ---> [*] V4L
USB devices --->
<*> USB Video Class (UVC)
[*] UVC input events device support
<*> USB GSPCA driver

Khi cắm thiết bị USB camera vào hệ thống, Linux sẽ tạo ra device file name, thông
thường có tên như sau: "/dev/video0".
3.viết chương trình cho linux :
Đoạn code :
/
************************************************************************
*******
#chương trình đọc camera và xuất ảnh lên
************************************************************************
*******/

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <linux/videodev.h>
#include <sys/ioctl.h>
#include <errno.h>
#include <signal.h>
#include <sys/socket.h>
#include <arpa/inet.h>
Trang 133
#include <sys/types.h>
#include <sys/stat.h>
#include <getopt.h>
#include <pthread.h>
#include <dlfcn.h>
#include <fcntl.h>
#include <syslog.h>

#include "utils.h"
#include "mjpg_streamer.h"

/* globals */
static globals global;

/
************************************************************************
******
Description.: Display a help message
Input Value.: argv[0] is the program name and the parameter progname
Return Value: -
************************************************************************
******/
void help(char *progname)
{
fprintf(stderr, "-----------------------------------------------------------------------\n");
fprintf(stderr, "Usage: %s\n" \
" -i | --input \"<input-plugin.so> [parameters]\"\n" \
" -o | --output \"<output-plugin.so> [parameters]\"\n" \
" [-h | --help ]........: display this help\n" \
" [-v | --version ].....: display version information\n" \
" [-b | --background]...: fork to the background, daemon mode\n",
progname);
fprintf(stderr, "-----------------------------------------------------------------------\n");
fprintf(stderr, "Example #1:\n" \
" To open an UVC webcam \"/dev/video1\" and stream it via HTTP:\n" \
" %s -i \"input_uvc.so -d /dev/video1\" -o \"output_http.so\"\n",
progname);
fprintf(stderr, "-----------------------------------------------------------------------\n");
fprintf(stderr, "Example #2:\n" \
" To open an UVC webcam and stream via HTTP port 8090:\n" \
" %s -i \"input_uvc.so\" -o \"output_http.so -p 8090\"\n", progname);
fprintf(stderr, "-----------------------------------------------------------------------\n");
fprintf(stderr, "Example #3:\n" \
" To get help for a certain input plugin:\n" \
" %s -i \"input_uvc.so --help\"\n", progname);

Trang 134
fprintf(stderr, "-----------------------------------------------------------------------\n");
fprintf(stderr, "In case the modules (=plugins) can not be found:\n" \
" * Set the default search path for the modules with:\n" \
" export LD_LIBRARY_PATH=/path/to/plugins,\n" \
" * or put the plugins into the \"/lib/\" or \"/usr/lib\" folder,\n" \
" * or instead of just providing the plugin file name, use a complete\n" \
" path and filename:\n" \
" %s -i \"/path/to/modules/input_uvc.so\"\n", progname);
fprintf(stderr, "-----------------------------------------------------------------------\n");
}

/
************************************************************************
******
Description.: pressing CTRL+C sends signals to this process instead of just
killing it plugins can tidily shutdown and free allocated
ressources. The function prototype is defined by the system,
because it is a callback function.
Input Value.: sig tells us which signal was received
Return Value: -
************************************************************************
******/
void signal_handler(int sig)
{
int i;

/* signal "stop" to threads */


LOG("setting signal to stop\n");
global.stop = 1;
usleep(1000*1000);

/* clean up threads */
LOG("force cancelation of threads and cleanup ressources\n");
global.in.stop();
for(i=0; i<global.outcnt; i++) {
global.out[i].stop(global.out[i].param.id);
}
usleep(1000*1000);

/* close handles of input plugins */


dlclose(&global.in.handle);
for(i=0; i<global.outcnt; i++) {
/* skip = 0;
DBG("about to decrement usage counter for handle of %s, id #%02d, handle:
%p\n", \

Trang 135
global.out[i].plugin, global.out[i].param.id, global.out[i].handle);
for(j=i+1; j<global.outcnt; j++) {
if ( global.out[i].handle == global.out[j].handle ) {
DBG("handles are pointing to the same destination (%p == %p)\n",
global.out[i].handle, global.out[j].handle);
skip = 1;
}
}
if ( skip ) {
continue;
}

DBG("closing handle %p\n", global.out[i].handle);


*/
dlclose(global.out[i].handle);
}
DBG("all plugin handles closed\n");

pthread_cond_destroy(&global.db_update);
pthread_mutex_destroy(&global.db);

LOG("done\n");

closelog();
exit(0);
return;
}

/
************************************************************************
******
Description.:
Input Value.:
Return Value:
************************************************************************
******/
int main(int argc, char *argv[])
{
char *input = "input_uvc.so --resolution 640x480 --fps 5 --device /dev/video0";
char *output[MAX_OUTPUT_PLUGINS];
int daemon=0, i;
size_t tmp=0;

output[0] = "output_http.so --port 8080";


global.outcnt = 0;

Trang 136
/* parameter parsing */
while(1) {
int option_index = 0, c=0;
static struct option long_options[] = \
{
{"h", no_argument, 0, 0},
{"help", no_argument, 0, 0},
{"i", required_argument, 0, 0},
{"input", required_argument, 0, 0},
{"o", required_argument, 0, 0},
{"output", required_argument, 0, 0},
{"v", no_argument, 0, 0},
{"version", no_argument, 0, 0},
{"b", no_argument, 0, 0},
{"background", no_argument, 0, 0},
{0, 0, 0, 0}
};

c = getopt_long_only(argc, argv, "", long_options, &option_index);

/* no more options to parse */


if (c == -1) break;

/* unrecognized option */
if(c=='?'){ help(argv[0]); return 0; }

switch (option_index) {
/* h, help */
case 0:
case 1:
help(argv[0]);
return 0;
break;

/* i, input */
case 2:
case 3:
input = strdup(optarg);
break;

/* o, output */
case 4:
case 5:
output[global.outcnt++] = strdup(optarg);
Trang 137
break;

/* v, version */
case 6:
case 7:
printf("MJPG Streamer Version: %s\n" \
"Compilation Date.....: %s\n" \
"Compilation Time.....: %s\n", SOURCE_VERSION, __DATE__,
__TIME__);
return 0;
break;

/* b, background */
case 8:
case 9:
daemon=1;
break;

default:
help(argv[0]);
return 0;
}
}

openlog("MJPG-streamer ", LOG_PID|LOG_CONS, LOG_USER);


//openlog("MJPG-streamer ", LOG_PID|LOG_CONS|LOG_PERROR,
LOG_USER);
syslog(LOG_INFO, "starting application");

/* fork to the background */


if ( daemon ) {
LOG("enabling daemon mode");
daemon_mode();
}

/* initialise the global variables */


global.stop = 0;
global.buf = NULL;
global.size = 0;
global.in.plugin = NULL;

/* this mutex and the conditional variable are used to synchronize access to the
global picture buffer */
if( pthread_mutex_init(&global.db, NULL) != 0 ) {
LOG("could not initialize mutex variable\n");
Trang 138
closelog();
exit(EXIT_FAILURE);
}
if( pthread_cond_init(&global.db_update, NULL) != 0 ) {
LOG("could not initialize condition variable\n");
closelog();
exit(EXIT_FAILURE);
}

/* ignore SIGPIPE (send by OS if transmitting to closed TCP sockets) */


signal(SIGPIPE, SIG_IGN);

/* register signal handler for <CTRL>+C in order to clean up */


if (signal(SIGINT, signal_handler) == SIG_ERR) {
LOG("could not register signal handler\n");
closelog();
exit(EXIT_FAILURE);
}

/*
* messages like the following will only be visible on your terminal
* if not running in daemon mode
*/
LOG("MJPG Streamer Version.: %s\n", SOURCE_VERSION);

/* check if at least one output plugin was selected */


if ( global.outcnt == 0 ) {
/* no? Then use the default plugin instead */
global.outcnt = 1;
}

/* open input plugin */


tmp = (size_t)(strchr(input, ' ')-input);
global.in.plugin = (tmp > 0)?strndup(input, tmp):strdup(input);
global.in.handle = dlopen(global.in.plugin, RTLD_LAZY);
if ( !global.in.handle ) {
LOG("ERROR: could not find input plugin\n");
LOG(" Perhaps you want to adjust the search path with:\n");
LOG(" # export LD_LIBRARY_PATH=/path/to/plugin/folder\n");
LOG(" dlopen: %s\n", dlerror() );
closelog();
exit(EXIT_FAILURE);
}
global.in.init = dlsym(global.in.handle, "input_init");
if ( global.in.init == NULL ) {
Trang 139
LOG("%s\n", dlerror());
exit(EXIT_FAILURE);
}
global.in.stop = dlsym(global.in.handle, "input_stop");
if ( global.in.stop == NULL ) {
LOG("%s\n", dlerror());
exit(EXIT_FAILURE);
}
global.in.run = dlsym(global.in.handle, "input_run");
if ( global.in.run == NULL ) {
LOG("%s\n", dlerror());
exit(EXIT_FAILURE);
}
/* try to find optional command */
global.in.cmd = dlsym(global.in.handle, "input_cmd");

global.in.param.parameter_string = strchr(input, ' ');


global.in.param.global = &global;

if ( global.in.init(&global.in.param) ) {
LOG("input_init() return value signals to exit");
closelog();
exit(0);
}

/* open output plugin */


for (i=0; i<global.outcnt; i++) {
tmp = (size_t)(strchr(output[i], ' ')-output[i]);
global.out[i].plugin = (tmp > 0)?strndup(output[i], tmp):strdup(output[i]);
global.out[i].handle = dlopen(global.out[i].plugin, RTLD_LAZY);
if ( !global.out[i].handle ) {
LOG("ERROR: could not find output plugin %s\n", global.out[i].plugin);
LOG(" Perhaps you want to adjust the search path with:\n");
LOG(" # export LD_LIBRARY_PATH=/path/to/plugin/folder\n");
LOG(" dlopen: %s\n", dlerror() );
closelog();
exit(EXIT_FAILURE);
}
global.out[i].init = dlsym(global.out[i].handle, "output_init");
if ( global.out[i].init == NULL ) {
LOG("%s\n", dlerror());
exit(EXIT_FAILURE);
}
global.out[i].stop = dlsym(global.out[i].handle, "output_stop");
if ( global.out[i].stop == NULL ) {
Trang 140
LOG("%s\n", dlerror());
exit(EXIT_FAILURE);
}
global.out[i].run = dlsym(global.out[i].handle, "output_run");
if ( global.out[i].run == NULL ) {
LOG("%s\n", dlerror());
exit(EXIT_FAILURE);
}
/* try to find optional command */
global.out[i].cmd = dlsym(global.out[i].handle, "output_cmd");

global.out[i].param.parameter_string = strchr(output[i], ' ');


global.out[i].param.global = &global;
global.out[i].param.id = i;
if ( global.out[i].init(&global.out[i].param) ) {
LOG("output_init() return value signals to exit");
closelog();
exit(0);
}
}

/* start to read the input, push pictures into global buffer */


DBG("starting input plugin\n");
syslog(LOG_INFO, "starting input plugin");
global.in.run();

DBG("starting %d output plugin(s)\n", global.outcnt);


for(i=0; i<global.outcnt; i++) {
syslog(LOG_INFO, "starting output plugin: %s (ID: %02d)", global.out[i].plugin,
global.out[i].param.id);
global.out[i].run(global.out[i].param.id);
}

/* wait for signals */


pause();

return 0;
}

3. Biên dịch chương trình


"mjpg-streamer", chương trình có nhiệm vụ capture ảnh nên USB webcam và nén thành
jpg, sau đó stream nó lên webserver. Ta có thể dùng trình duyệt FireFox để xem kết quả.
Sau đây là các bước build chương trình (dùng Debian gcc chạy trên KM9260).

$ tar -zxvf mjpg-streamer-r63.tar.gz

Trang 141
$ cd mjpg-streamer-r63
$ make

Sau khi build thành công, ta có thể chạy chương trình bằng cách gọi script "start.sh"

4. Xuất chương trình hiển thì


5.
$ source start.sh

Giả sử board KM9260 có địa chỉ IP là 192.168.3.29 , dùng FireFox hay bất kỳ trình
duyệt internet nào và vào địa chỉ sau để
xem kết quả: "http://192.168.1.35:8080/stream.html"

kết quả :

Trang 142
Quá Trình Truyển dữ liệu qua mạng :

Kết quả chụp lại được

Trang 143
C. VIẾT ỨNG DỤNG WIFI CHO BOARD NHÚNG
Hiện nay các module wireless hỗ trợ cho hệ thống VĐK bao gồm các
module ZigBee...Nhưng giá thành vẫn còn đắt đỏ, có vẽ còn xa vời. Tuy
nhiên, hiện nay trên thị trường vi tính hiện nay xuất hiện USB Wireless
apdapter có nhãn hiệu Tenda W541U V2.0, chuẩn G 54Mbps,
Không may, theo trang web của Tenda họ nói chỉ hỗ trợ cho Windows,
không hỗ trợ cho Linux.
Nên ta phải viết driver cho nó
Gắn USB adapter này vào hệ thống, dùng lệnh "lsusb -vv"
1. Xem cấu hình
Do source kernel không hỗ trợ driver cho loại chipset này vì vậy việc
build driver theo kiểu external module là điều cần thiết. Để làm điều đó
cần phải cấu hình lại kernel, add phần mục hỗ trợ wireless.

Trang 144
Vendor, chip ID: 0x148F,0x2070
Chipset: Ralink 2070L

2. Biên dịch thêm moudul


Code:
$ cd linux-2.6.27
$ make ARCH=arm CROSS_COMPILE=arm-none-linux-gnueabi-
menuconfig
2. Cấu hình kernel:
Code:
Device Driver --->[*] Network device support --->
Wireless LAN --->[*] Wireless LAN (IEEE 802.11)
<*> IEEE 802.11 for host AP ...[*] Support for downloading firmware
images with host AP driver[*] Support for non-volatile firmware download
3. Build kernel:

Code:
$ make ARCH=arm CROSS_COMPILE=arm-none-linux-gnueabi- uImage
Build module:
Code:
Code:
$ cd W541U
$ make
Sau khi build xong kernel, reboot hệ thống, gắn USB wireless apdator vào
KM9260, chép firmware .bin và file cấu hình .dat vào thư mục /etc/wireless...
ta cần phải insert module driver:

Code:
$ insmod rt3070sta.ko
$ iwconfig
$ ifconfig ra0 inet 192.168.1.35 up
Trang 145
Ta có thể thay thế mạng LAN bằng USB wifi

Code chương trình :

/*

*************************************************************************
 Dao thanh mai
 06119058
 0906773728
 daothanhmaikmt@gmail.com

*************************************************************************

Module Name:
rt3070.c

Abstract:
Specific funcitons and variables for RT3070

Revision History:
Who When What

Trang 146
-------- ----------
----------------------------------------------
*/

#ifdef RT3070

#include "rt_config.h"

#ifndef RTMP_RF_RW_SUPPORT
#error "You Should Enable compile flag RTMP_RF_RW_SUPPORT for this chip"
#endif // RTMP_RF_RW_SUPPORT //

VOID NICInitRT3070RFRegisters(IN PRTMP_ADAPTER pAd)


{
INT i;
UCHAR RFValue;

// Driver must read EEPROM to get RfIcType before initial RF


registers
// Initialize RF register to default value
if (IS_RT3070(pAd) || IS_RT3071(pAd))
{
// Init RF calibration
// Driver should toggle RF R30 bit7 before init RF registers
UINT32 RfReg = 0;
UINT32 data;

RT30xxReadRFRegister(pAd, RF_R30, (PUCHAR)&RfReg);


RfReg |= 0x80;
RT30xxWriteRFRegister(pAd, RF_R30, (UCHAR)RfReg);
RTMPusecDelay(1000);
RfReg &= 0x7F;
RT30xxWriteRFRegister(pAd, RF_R30, (UCHAR)RfReg);

// Initialize RF register to default value


for (i = 0; i < NUM_RF_REG_PARMS; i++)
{
RT30xxWriteRFRegister(pAd,
RT30xx_RFRegTable[i].Register, RT30xx_RFRegTable[i].Value);
}

// add by johnli
if (IS_RT3070(pAd))
{
//
// The DAC issue(LDO_CFG0) has been fixed in RT3070(F).
// The voltage raising patch is no longer needed for
RT3070(F)
//
if ((pAd->MACVersion & 0xffff) < 0x0201)
{
// Update MAC 0x05D4 from 01xxxxxx to 0Dxxxxxx
(voltage 1.2V to 1.35V) for RT3070 to improve yield rate
RTUSBReadMACRegister(pAd, LDO_CFG0, &data);
data = ((data & 0xF0FFFFFF) | 0x0D000000);
RTUSBWriteMACRegister(pAd, LDO_CFG0, data);
}
}

Trang 147
else if (IS_RT3071(pAd))
{
// Driver should set RF R6 bit6 on before init RF
registers
RT30xxReadRFRegister(pAd, RF_R06, (PUCHAR)&RfReg);
RfReg |= 0x40;
RT30xxWriteRFRegister(pAd, RF_R06, (UCHAR)RfReg);

// init R31
RT30xxWriteRFRegister(pAd, RF_R31, 0x14);

// RT3071 version E has fixed this issue


if ((pAd->NicConfig2.field.DACTestBit == 1) && ((pAd-
>MACVersion & 0xffff) < 0x0211))
{
// patch tx EVM issue temporarily
RTUSBReadMACRegister(pAd, LDO_CFG0, &data);
data = ((data & 0xE0FFFFFF) | 0x0D000000);
RTUSBWriteMACRegister(pAd, LDO_CFG0, data);
}
else
{
RTMP_IO_READ32(pAd, LDO_CFG0, &data);
data = ((data & 0xE0FFFFFF) | 0x01000000);
RTMP_IO_WRITE32(pAd, LDO_CFG0, data);
}

// patch LNA_PE_G1 failed issue


RTUSBReadMACRegister(pAd, GPIO_SWITCH, &data);
data &= ~(0x20);
RTUSBWriteMACRegister(pAd, GPIO_SWITCH, data);
}

//For RF filter Calibration


RTMPFilterCalibration(pAd);

// Initialize RF R27 register, set RF R27 must be behind


RTMPFilterCalibration()
//
// TX to RX IQ glitch(RF_R27) has been fixed in RT3070(F).
// Raising RF voltage is no longer needed for RT3070(F)
//
if ((IS_RT3070(pAd)) && ((pAd->MACVersion & 0xffff) < 0x0201))
{
RT30xxWriteRFRegister(pAd, RF_R27, 0x3);
}
else if ((IS_RT3071(pAd)) && ((pAd->MACVersion & 0xffff) <
0x0211))
{
RT30xxWriteRFRegister(pAd, RF_R27, 0x3);
}

// set led open drain enable


RTUSBReadMACRegister(pAd, OPT_14, &data);
data |= 0x01;
RTUSBWriteMACRegister(pAd, OPT_14, data);

// move from RT30xxLoadRFNormalModeSetup because it's needed


for both RT3070 and RT3071
// TX_LO1_en, RF R17 register Bit 3 to 0

Trang 148
RT30xxReadRFRegister(pAd, RF_R17, &RFValue);
RFValue &= (~0x08);
// to fix rx long range issue
if (pAd->NicConfig2.field.ExternalLNAForG == 0)
{
if ((IS_RT3071(pAd) && ((pAd->MACVersion & 0xffff) >=
0x0211)) || IS_RT3070(pAd))
{
RFValue |= 0x20;
}
}
// set RF_R17_bit[2:0] equal to EEPROM setting at 0x48h
if (pAd->TxMixerGain24G >= 1)
{
RFValue &= (~0x7); // clean bit [2:0]
RFValue |= pAd->TxMixerGain24G;
}
RT30xxWriteRFRegister(pAd, RF_R17, RFValue);

if (IS_RT3071(pAd))
{
// add by johnli, RF power sequence setup, load RF
normal operation-mode setup
RT30xxLoadRFNormalModeSetup(pAd);
}
else if (IS_RT3070(pAd))
{
/* add by johnli, reset RF_R27 when interface down & up
to fix throughput problem*/
// LDORF_VC, RF R27 register Bit 2 to 0
RT30xxReadRFRegister(pAd, RF_R27, &RFValue);
// TX to RX IQ glitch(RF_R27) has been fixed in
RT3070(F).
// Raising RF voltage is no longer needed for RT3070(F)
if ((pAd->MACVersion & 0xffff) < 0x0201)
RFValue = (RFValue & (~0x77)) | 0x3;
else
RFValue = (RFValue & (~0x77));
RT30xxWriteRFRegister(pAd, RF_R27, RFValue);
/* end johnli */
}
}

}
#endif // RT3070 //

D. SỬ DỤNG UART
1. Bản chi tiết phần cứng :

Trang 149
Moudul trên board

Chi tiết các chân

Trang 150
MPU AT91SAM9260 có 6 đường UART, bao gồm DBGU (console chính),
UART0~UART4. Board KM9260 được thiết kế với DBGU dùng cho console chính, 4
đường UART mở rộng được đưa ra

Để điều khiển được thiết bị UART, chương trình ứng dụng cần phải tác động lên device
file tương ứng cho các thiết bị đó.

UART Device File


DBGU ttyS0
UART0 ttyS1
UART1 ttyS2
UART2 ttyS3
UART3 ttyS4
UART4 ttyS5

Các device file này được chứa trong thư mục /dev, có thể dùng ls để kiểm tra danh sách
các device file:

Trang 151
Ta nhận thấy chỉ có ttyS0~ttyS2 hiện diện trong danh sách device file, có nghĩa là ta chỉ
có thể sử dụng DBGU, UART0 và UART1 mà thôi, bởi vì trong kernel, source file board
specific code chưa thực hiện việc đăng ký cho các thiết bị UART2 ~ UART5

Với UART, làm sao ta có thể thử cổng UART nào đó hoạt động có tốt hay không, cổng
UART0 chẳng hạn, và cách thực hiện như sau:

Dùng dây kết nối Pin 10 (TXD0) và Pin 11(RXD0) của header mở rộng J16 vào cổng
COM của máy tính (chú ý: không được nối trực tiếp, cần phải thông qua IC chuyển đổi
TTL<->RS232 ví dụ như MAX232…). Như vậy ta cần có 2 terminal, terminal thứ 1 dùng
cho cổng DBGU (console chính), và được tạm gọi là console DBGU, và terminal thứ 2
dùng cho cổng UART0, và được gọi là console UART0. Có thể dùng putty cho cả 2
console này, ta chỉ việc click chuột vào putty.exe 2 lần, nhập vào các thông số thiết lập
kết nối cần thiết.

> >

DBGU UART0

Trang 152
MAX232

Trước tiên ta kiểm tra tốc độ baud hiện hành của UART0 thông qua lệnh shell (thực hiện
trên console DBGU):

$ stty -F /dev/ttyS1
speed 9600 baud; line = 0;
-brkint -imaxbel

Tốc độ mặc định là 9600, ta có thể thay đổi baudrate thành 115200 thông qua lệnh sau:

$ stty -F /dev/ttyS1 115200

Để test việc truyền chuỗi ký tự “KM9260” từ board ra console UART0, từ DBGU
console, ta thực hiện lệnh sau:

$ echo “KM9260” > /dev/ttyS1

Để test việc nhận ký tự, ta thực hiện lệnh:

$ cat /dev/ttyS1

Khi đó, nếu ta nhập ký tự ‘A’ bên UART0 console, KM9260 sẽ nhận được ký tự này và
hiển thị trên DBGU console.

2. VIẾT ỨNG DỤNG CHO UART:

Trong Linux, chương trình (hay còn gọi là user application) không thể trực tiếp tác động
vào các thiết bị trong hệ thống, mà phải thông qua driver. User application tương tác với
driver thông qua các device file đã được giới thiệu ở trên. Linux cung cấp các hàm API
(systemcall) nhằm thực hiện việc truy xuất các device file này, cơ chế hoạt động tương
tự như việc thao tác ghi đọc file trong các chương trình C thông thường. Sau đây giới
thiệu một số hàm cơ bản.

Header file #include <fcntl.h>


Tên hàm int open (const char *path, int oflag, ... );
Giá trị trả về - Descriptor ( số dương) nếu mở thành công.
- -1 : mở không thành công
Mô tả - Hàm open thiết lập kết nối giữa device file và descriptor.
- Descriptor này được sử dụng bởi các hàm IO nhằm tham chiếu
vào device file.

Trước khi truy xuất thiết bị, chương trình ứng dụng gọi hàm open() , kết quả cho giá trị
kiểu int device file descriptor, các hàm IO (read, write) sử dụng device file descriptor
này nhằm tham chiếu đến device file.
Header file #include <unistd.h>
Tên hàm int close (int fd);
Giá trị trả về - Zerro nếu đóng thành công.
- -1 : đóng không thành công
Mô tả - Đóng device file descriptor.

Ngược lại với hàm open(), hàm close đóng descriptor, giá trị trả về là 0 nếu đóng
thành công, ngược lại giá trị trả về là -1.

Header file #include <unistd.h>


Tên hàm ssize_t read (int fd, void *buf, size_t count);
Giá trị trả về - Nếu count là Zero thì giá trị return là Zero.
- Nếu count lớn hơn SSIZE_MAX thì giá trị return không xác
định.
- Nếu thành công, hàm sẽ trả về số byte đọc được.
Mô tả - Yêu cầu đọc “count” byte từ device file và lưu vào “buf”

Hàm read() có chức năng đọc device file và lưu data vào buf.

Header file #include <unistd.h>


Tên hàm ssize_t write (int fd, const void *buf, size_t count);
Giá trị trả về - Nếu thành công, hàm trả về số byte ghi hoàn tất.
- Giá trị trả về là -1 nếu ghi error.
Mô tả - Write “count” bytes từ buf vào device file.

Hàm có chức năng ghi “count” byte vào thiết bị, nếu thành công, hàm trả về số bytes
đã ghi được, ngược lại giá trị trả về là -1.
Termios:

Termios là tập hợp những hàm Unix API dùng cho terminal IO. Cấu trúc một chương
trình sử dụng serial UART bao gồm:

- Mở thiết bị bởi hàm system call open ().


- Cấu hình các tham số giao tiếp và các thuộc tính giao tiếp.
- Sử dụng các hàm system call IO như read(), write() để truy xuất dữ liệu.
- Dùng hàm close() để đóng thiết bị.

Các hàm termios được khai báo trong header file #include <termios.h> , hỗ trợ 2 mode
hoạt động:

1. Canonical mode:
Thích hợp cho các thiết bị giao tiếp theo kiểu line-by-line.

2. Non-canonical mode:
Dùng cho kiểu giao tiếp các ký tự riêng lẻ.
Các hệ thống theo kiểu BSD có đến 3

mode:

1. Cooked Mode:
Các input được tổ hợp lại thành line và các ký tự đặc biệt được xử lý.

2. Raw mode:
Các input không được tổ hợp thành line và các ký tự đặc biệt ko được xử lý.

3. Cbreak mode:
Các input không được tổ hợp thành line và một vài ký tự đặc biệt được xử lý.

Mode mặc định là canonical (cooked mode đối với BSD). Những ký tự đặc biệt tương
ứng cho các mode được gọi là ký tự điều khiển (control characters). Đối với các giao tiếp
serial thông thường thì thích hợp với mode non-canonical (raw hoặc cbreak mode đối với
BSD) để đảm bảo data truyền đi không bị dịch ký tự (character translate) bởi terminal
driver. Việc cấu hình được thực hiện bằng cách thao tác trên các bit cờ được khai báo bởi
termios. Các cờ này được định nghĩa như sau:

struct termios {
tcflag_t c_iflag; /* input specific flags (bitmask) */
tcflag_t c_oflag; /* output specific flags (bitmask) */
tcflag_t c_cflag; /* control flags (bitmask) */
tcflag_t c_lflag; /* local flags (bitmask) */
cc_t c_cc[NCCS]; /* special characters */
};
Mở thiết bị:

const char *device = "/dev/ttyS1";


fd = open (device, O_RDWR | O_NOCTTY | O_NDELAY);
if (fd == -1) {
printf ( "failed to open port\n" );
}

Trong đó:
O_RDWR : Mở port cho việc đọc và ghi.
O_NOCTTY: Port không điều khiển terminal của process.
O_NDELAY: Sử dụng non-blocking IO access mode.

Đóng thiết bị:

close (fd);
Cấu hình port:

Sau khi mở port, ta có thể cấu hình port thay vì sử dụng giá trị mặc định, ví dụ như cấu
hình baudrate, check parity… Trước khi cấu hình, ta lấy về cấu hình ban đầu của
port bằng cách gọi hàm tcgetattr (), cấu hình sẽ được lưu vào biến thuộc kiểu struct
termios, chương trình có thể thay đổi cấu hình bằng cách set lại các cờ, và cuối cùng
apply bằng cách gọi hàm tcsetattr().

Header file #include <termios.h>


Tên hàm int tcgetattr (int fd, struct termios *termios_p);
Giá trị trả về - Nếu thành công, hàm trả về số dương.
- Giá trị trả về là số âm nếu ko thành công.
Mô tả - Hàm get thuộc tính của port và lưu kết quả vào vùng nhớ với
con trỏ thuộc kiểu struct termios.

Header file #include <termios.h>


Tên hàm int tcsetattr (int fd, int optional_actions,
const struct termios *termios_p);
Giá trị trả về - Nếu thành công, hàm trả về số dương.
- Giá trị trả về là số âm nếu ko thành công.
Mô tả - Hàm set thuộc tính cho port.
Ý nghĩa của một số cờ thông dụng:

Input modes:

c_iflag
BRKINT Signal interrupt on break
ICRNL Map CR to NL on input
IGNBRK Ignore break condition
IGNCR Ignore CR
IGNPAR Ignore characters with parity errors
INLCR Map NL to CR on input
INPCK Enable input parity check
ISTRIP Strip character
IUCLC Map upper-case to lower-case on input (LEGACY)
IXANY Enable any character to restart output
IXOFF Enable start/stop input control
IXON Enable start/stop output control
PARMRK Mark parity errors

Output modes:

c_oflag
OPOST Post-process output
OLCUC Map lower-case to upper-case on output (LEGACY)
ONLCR Map NL to CR-NL on output
OCRNL Map CR to NL on output
ONOCR No CR output at column 0
ONLRET NL performs CR function
OFILL Use fill characters for delay
NLDLY Select newline delays:
NL0 Newline character type 0.
NL1 Newline character type 1.
CRDLY Select carriage-return delays:
CR0 Carriage-return delay type 0.
CR1 Carriage-return delay type 1.
CR2 Carriage-return delay type 2.
CR3 Carriage-return delay type 3.
TABDLY Select horizontal-tab delays:
TAB0 Horizontal-tab delay type 0.
TAB1 Horizontal-tab delay type 1.
TAB2 Horizontal-tab delay type 2.
TAB3 Expand tabs to spaces.
BSDLY Select backspace delays:
BS0 Backspace-delay type 0.
BS1 Backspace-delay type 1.
VTDLY Select vertical-tab delays:
VT0 Vertical-tab delay type 0.
VT1 Vertical-tab delay type 1.
FFDLY Select form-feed delays:
FF0 Form-feed delay type 0.
FF1 Form-feed delay type 1.

Control modes:

c_cflag
CSIZE Character size:
CS5 5 bits.
CS6 6 bits.
CS7 7 bits.
CS8 8 bits.
CSTOPB Send two stop bits, else one.
CREAD Enable receiver.
PARENB Parity enable.
PARODD Odd parity, else even.
HUPCL Hang up on last close.
CLOCAL Ignore modem status lines.

Local modes:

c_lflag
ECHO Enable echo.
ECHOE Erase character deletes
ECHOK Output newline after the kill character
ECHONL Echo the newline
ICANON If set, enable canonical input processing
IEXTEN Enable extended input character processing.
ISIG If set, enable signals SIGINT and SIGQUIT
NOFLSH Disable flush after interrupt or quit.
TOSTOP Send SIGTTOU for background output.
XCASE Canonical upper/lower presentation (LEGACY).

Attribute selection:

optional_actions
TCSANOW Change attributes immediately.
TCSADRAIN Change attributes when output has drained.
TCSAFLUSH Change attributes when output has drained; also flush pending input.
Line control:

c_lflag
TCIFLUSH Flush pending input. Flush untransmitted output.
TCIOFLUSH Flush both pending input and untransmitted output.
TCOFLUSH Flush untransmitted output.
TCIOFF Transmit a STOP character, intended to suspend input data.
TCION Transmit a START character, intended to restart input data.
TCOOFF Suspend output
TCOON Restart output.
Các ký tự điều khiển:

Subscript Usage
Canonical Mode Non-canonical Mode Description Default value
VEOF Signal End-Of-Input Ctrl-D
VEOL Signal End-Of-Line [Disabled]
VERASE Delete previous character Backspace
VINTR VINTR Generate SIGINT Ctrl-C
VKILL Erase current line Ctrl-U
VMIN The MIN value 1
VQUIT VQUIT Generate SIGQUIT Ctrl-\
VSTART VSTART Resume output Ctrl-Q
VSTOP VSTOP Suspend output Ctrl-S
VSUSP VSUSP Suspend program Ctrl-Z
VTIME TIME value 0

Mã ASCII của một số ký tự đặc biệt:

ASCII Name Description C Escape Sequence ASCII


NULL null byte \0 0x00
BEL bell character \a 0x07
BS backspace \b 0x08
HT horizontal tab \t 0x09
NP formfeed \f 0x0C
NL newline \n 0x0A
CR carriage return \r 0x0D
VT vertical tab 0x0B
ESC escape 0x1B
SP space 0x14

Ví dụ:

Chương trình nhận ký tự trên console UART0 lưu vào mảng a tại phần tử là 0, hiển thị
ký tự này lên console DBGU, sau đó gửi ký tự này sang UART0. Chương trình kết thúc
khi nhận ký tự ‘e’ từ console UART0.
#include <stdio.h> /* Standard input/output definitions */
#include <string.h> /* String function definitions */
#include <unistd.h> /* UNIX standard function definitions */
#include <fcntl.h> /* File control definitions */
#include <errno.h> /* Error number definitions */
#include <termios.h> /* POSIX terminal control definitions */

int config (int fd)


{
struct termios config;
// is a tty device ?
if (!isatty (fd))
{
printf ("-E- not is a tty deive \r\n");
return -1;
}

// get the current port config


if (tcgetattr (fd, &config) < 0)
{
printf ("-E- cannot get current config \r\n");
return -1;
}

config.c_iflag &= ~(IGNBRK | BRKINT | ICRNL | INLCR |


PARMRK | INPCK | ISTRIP | IXON);
config.c_oflag = 0;
config.c_lflag &= ~(ECHO | ECHONL | ICANON | IEXTEN | ISIG);
config.c_cflag &= ~(CSIZE | PARENB);
config.c_cflag |= CS8;
config.c_cc[VMIN] = 1;
config.c_cc[VTIME] = 0;

if (cfsetispeed (&config, B115200) < 0 || cfsetospeed (&config, B115200) < 0)


{
printf ("-E- cannot set baudrate \r\n");
return -1;
}

if (tcsetattr (fd, TCSAFLUSH, &config) < 0)


{
printf ("-E- config failed \r\n");
return -1;
}

printf ("-I- config success \r\n");

return 0;
}

int main (int argc, char *argv[])


{
int fd; /* File descriptor */
char a[20];
const char *mes = "print input character and terminate by 'e' character\r\n";
const char *dev_name = "/dev/ttyS1";

char c = 'c';
ssize_t count = 0;

/* remove O_NDELAY if use blocking access */


fd = open (dev_name , O_RDWR | O_NOCTTY | O_NDELAY);
if (fd == -1)
{
printf ("-E- Cannot open %s \r\n", dev_name);
return -1;
}

printf ("-I- open %s success \r\n", dev_name);


if ( config (fd) != 0 )
{
printf ("-E- cannot configure %s", dev_name);
}

write (fd, mes , strlen(mes)); /* print message */

while (c != 'e')
{
count = read (fd, a, 10);
if (count > 0)
{
// printf ("a[0] = %c count = %d\r\n", a[0], (int)count);
printf ("key=%c ascii = %X\r\n", a[0], a[0]);
write (fd, a , 1); /* echo here */
}
c = a[0];
usleep (2);
}

printf ("-I- program terminated \r\n");

close (fd);

return 0;
}

ĐĂNG KÝ THIẾT BỊ UART VÀO HỆ THỐNG:

Như đã đề cập ở trên, làm thế nào ta có thể đăng ký thêm UART port vào KM9260. Mặc
định hệ thống chỉ có 3 thiết bị ttyS0~ttyS2. Giả sử ta muốn mở rộng thêm ttyS3~ttyS5 thì
phải làm như thế nào? Phần sau đây chỉ ra cách thực hiện:

Trước tiên ta cần phải giản nén và patch kernel source của linux:

$ tar –jxvf kernel-2.6.27.tar.bz2


$ cd linux-2.6.27
$ cat ../ linux-2.6.27-km9260-11102009.diff | patch –p1

Vào thư mục "linux-2.6.27/arch/arm/mach-at91" edit file board-km9260.c (thêm đoạn


code đăng ký UART vào hàm ek_map_io) như sau:

Static void int_ek_map_io (viod)


{
/* Initialize processor: 18.432 MHz crystal */
at91sam9260_initialize(18432000);

/* DGBU on ttyS0. (Rx & Tx only) */


at91_register_uart(0, 0, 0);

/* USART0 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */
at91_register_uart(AT91SAM9260_ID_US0, 1, ATMEL_UART_CTS | ATMEL_UART_RTS
| ATMEL_UART_DTR | ATMEL_UART_DSR | ATMEL_UART_DCD
| ATMEL_UART_RI);

/* USART1 on ttyS2. (Rx, Tx, RTS, CTS) */


at91_register_uart(AT91SAM9260_ID_US1, 2, ATMEL_UART_CTS | ATMEL_UART_RTS);

/* UART2 on ttyS3. (Rx & Tx only) */


at91_register_uart(AT91SAM9260_ID_US2, 3, 0);

/* UART3 on ttyS4. (Rx & Tx only) */


at91_register_uart(AT91SAM9260_ID_US3, 4, 0);

/* UART4 on ttyS5. (Rx & Tx only) */


at91_register_uart(AT91SAM9260_ID_US4, 5, 0);

/* set serial console to ttyS0 (ie, DBGU) */


at91_set_serial_console(0);
}

Sau khi edit xong ta có thể tiến hành các bước compile bình thường:

$ export PATH=$PATH:/home/km9260-project/tool/arm-2007q3/bin
$ cd linux-2.6.27
$ make ARCH=arm CROSS_COMPILE=arm-none-linux-gnueabi- km9260_defconfig
$ make ARCH=arm CROSS_COMPILE=arm-none-linux-gnueabi- uImage

Sau khi compile xong ta thu được file ảnh của kernel (uImage) nằm trong
thư mục "linux-2.6.27/arch/arm/boot".

Ta tiến hành cai đặt bình thường.

E. GIAO TIẾP VỚI VỚI MOUSE


USB mouse thuộc lớp HID, khi cắm USB mouse vào, Debian Linux sẽ
tự động tạo ra thiết bị "dev/input/mice". Thiết bị này thuộc lớp character
driver. Có thể dùng hàm open để mở thiết bị và truy xuất dữ liệu bởi các
hàm IO thông thường. Cấu trúc dữ liệu của sự kiện USB mouse như sau:

D7 D6 D5 D4 D3 D2 D1 D0
1 yv xv ys xs 1 0 R L
2 x7 x6 x5 x4 x3 x2 x1 x0
3 y7 y6 ỵ5 y4 y3 y2 y1 y0
Trong đó :
xs, ys :dx, dy
movement sign. R :
right button
L : left button
x7~x0 : dx
movement bits
y7~y0 : dy
movement bits

Ta có thể dump input event thông qua lệnh cat:

$ cat /dev/input/mice | hexdump -C

Ta có thể nhận thấy khi cắm chuột vào

Viết chương trình :

#include <stdio.h> /* Standard input/output definitions */

#include <string.h> /* String function definitions */

#include <unistd.h> /* UNIX standard function definitions */

#include <fcntl.h> /* File control definitions */

#include <errno.h> /* Error number definitions */

/******************************************************

USB mouse event data

d7 d6 d5 d4 d3 d2 d1 d0

1: yv xv ys xs 1 0 R L

2: x7 x6 x5 x4 x3 x2 x1 x0

3: y7 y6 y5 y4 y3 y2 y1 y0

xs,ys = dx,dy movement sign


R=right button; L=left button

x7-x0=dx movement bits

y7-y0=dy movement bits

*******************************************************/

int main (int argc, char *argv[])

int fd; /* File descriptor */

char a[20];

const char *dev_name = "/dev/input/mice";

char c = 'c';

ssize_t count = 0;

/* remove O_NDELAY if use blocking access */

fd = open (dev_name , O_RDWR | O_NOCTTY | O_NDELAY);

if (fd == -1)

printf ("-E- Cannot open %s \r\n", dev_name);

return -1;

printf ("-I- open %s success \r\n", dev_name);


while (c != 'e')

count = read (fd, a, 4);

if (count > 0)

printf ("event = %2X %2X %2X xs = %d ys = %d count = %d\r\n",

a[0], a[1], a[2], (a[0] >> 4) & 1, (a[0] >> 5) & 1, count);

printf ("-I- program terminated \r\n");

close (fd);

return 0;

Ta có kết quả như sau :

Vị trí bình thường


Click chuột phải

Click chuột trái

Lăn chuột giữa

CHƯƠNG IV
LẬP TRÌNH KERNEL MODULE
I . LẬP TRÌNH KERNEL MODULE:

Driver của Linux có thể tích hợp vào hệ thống theo hai kiểu bao gồm driver build sẵn
(tích hợp vào file ảnh của kernel) hặc theo kiểu module. Ở Linux 2.6 đuôi file của module
có tên là ".ko". Các lệnh shell thực hiện add và remove kernel module vào hệ thống bao
gồm "insmod, rmmod, lsmod ..."

a. Internal module và external module:

Internal module có source được tích hợp vào trong kernel source, để biên dịch module
này, chúng ta cần phải config lại kernel và check chữ [M] vào mục chọn trong kernel
menuconfig. Để biên dịch internal module ta dùng lệnh sau:

$ make ARCH=arm CROSS_COMPILE=arm-none-linux-gnueabi- modules

Chú ý: lệnh này chỉ được thực hiện khi ta đang ở thư mục gốc của kernel source, ví dụ
như thư mục "linux-2.6.27".

External module là có source code xây dựng nằm ngoài kernel source, khi đó người dùng
cần phải tạo ra Makefile cho phù hợp để có thể biên dịch. Cấu trúc của Makefile cho
external module như sau:

Biên dịch dùng native gcc: (cần phải có source kernel trong hệ thống rootfs, thích hợp
cho hệ thống Linux chạy trên PC), ta có Makefile như sau:

obj-m += module.o
all:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
clean:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean

Trong đó, source module có tên là module.c. Sau khi compile xong ta có được module.ko

Biên dịch dùng cross-compiler: (dùng máy tính Linux biên dịch cho hệ thống nhúng,
KM9260...) cấu trúc Makefile có dạng như sau:

export ARCH=arm
export CROSS_COMPILE=arm-none-linux-gnueabi-

obj-m += module.o

all:
make -C /home/AT91SAM9260/KERNEL/linux-2.6.27 M=$(PWD)
clean:
modules make -C /home/AT91SAM9260/KERNEL/linux-2.6.27 M=$
(

n
Ta cần phải export hai biến ARCH và CROSS_COMPILE, tham số -C của lệnh make
bao gồm đường dẫn đến source kernel cho hệ thống nhúng. Dùng lệnh sau để dịch
module:

$ make clean all

II. VIẾT DRIVER

1. SỬ DỤNG GPIO

Ở cấp độ software, hệ điều hành Linux phân chia thành 2 không gian hoạt động, gọi là
user space và kernel space. Chương trình ứng dụng (user program) thuộc về user space và
kernel module, driver thuộc về kernel space. Với sự phân chia trên, 1 chương trình ứng
dụng không thể truy xuất trực tiếp các gpio của MPU theo kiểu lập trình firmware truyền
thống, trong khi kernel module, driver có thể dễ dàng thực hiện điều này. Chương trình
ứng dụng truy xuất gpio thông qua driver. Về phía driver, các pin gpio_number của
AT91SAM9260 MPU được khai báo trong header file:
"arch/arm/mach-at91/include/mach/gpio.h"

AT91_PIN_PA0, AT91_PIN_PB0, AT91_PIN_PC0 ...

Ví dụ :

#defineAT91_PIN_PA0 (PIN_BASE + 0x00 + 0)


#defineAT91_PIN_PB0 (PIN_BASE + 0x20 + 0)
#defineAT91_PIN_PC0 (PIN_BASE + 0x40 + 0)
#defineAT91_PIN_PD0 (PIN_BASE + 0x60 + 0)
...

Và PIN_BASE được định nghĩa trong header file "irqs.h" và có giá trị là 32. Như vậy ta
có thể quy đổi ra gpio_number theo công thức như sau:

1. Pin name có dạng P<letter><number>


2. gpio_number = 32*letter + number : A = 1, B = 2, C = 3
3. Ví dụ : PC6 => gpio_number = 32*3+6 = 102

Sau đây là ví dụ cho kernel module có tên gọi là gpio_dev, driver cho phép chương trình
ứng dụng truy xuất gpio pin trên MPU, bao gồm các IO control set chiều input, ouput, set
bit, clear bit. Chương trình ứng dụng sử dụng driver này thông qua device file có tên là
"/dev/gpio". Sau đây là ví dụ cho kernel module với source file có tên là "gpio_dev.c".

#include <linux/module.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include <asm/gpio.h>
#include <asm/atomic.h>
#include <linux/init.h>
#include <linux/genhd.h>
#include <linux/miscdevice.h>

#define DRVNAME "gpiodev"


#define DEVNAME "gpio"

#define IOC_GPIODEV_MAGIC 'B'


#define GPIO_GET _IO(IOC_GPIODEV_MAGIC, 10)
#define GPIO_SET _IO(IOC_GPIODEV_MAGIC, 11)
#define GPIO_CLEAR _IO(IOC_GPIODEV_MAGIC, 12)
#define GPIO_DIR_IN _IO(IOC_GPIODEV_MAGIC, 13)
#define GPIO_DIR_OUT _IO(IOC_GPIODEV_MAGIC, 14)

static int dev_major;

/* Counter is 1, if the device is not opened and zero (or less) if opened. */
static atomic_t gpio_open_cnt = ATOMIC_INIT(1);

static int
gpio_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigned long arg)
{
int retval = 0;

switch (cmd)
{
case GPIO_GET:
retval = gpio_get_value(arg);
break;

case GPIO_SET: gpio_set_value(arg, 1); break;

case GPIO_CLEAR: gpio_set_value(arg, 0); break;

case GPIO_DIR_IN: gpio_direction_input(arg); break;

case GPIO_DIR_OUT: gpio_direction_output(arg, 0); break;

default:
retval = -EINVAL;
break;
}

return retval;
}

static int
gpio_open(struct inode *inode, struct file *file)
{
int result = 0;
unsigned int dev_minor = MINOR(inode->i_rdev);

/* FIXME: We should really allow multiple applications to open the device


* at the same time, as long as the apps access different IO pins.
* The generic gpio-registration functions can be used for that.
* Two new IOCTLs have to be introduced for that. Need to check userspace
* compatibility first. --mb */
if (!atomic_dec_and_test(&gpio_open_cnt)) {
atomic_inc(&gpio_open_cnt);
printk(KERN_ERR DRVNAME ": Device with minor ID %d already in use\n",
dev_minor);
result = -EBUSY;
goto out;
}

out:
return result;
}

static int
gpio_close(struct inode * inode, struct file * file)
{
smp_m before_atomic_inc();
b
atomic_inc(&gpio_open_cnt);

return 0;
}

struct file_operations gpio_fops = {


.ioctl = gpio_ioctl,
.open = gpio_open,
.release = gpio_close,
};

static struct miscdevice gpio_dev = {


.minor = MISC_DYNAMIC_MINOR,
.name = "gpio",
.fops = &gpio_fops,
};
static init
int
gpio_mod_init(void)
{
return misc_register(&gpio_dev);
}
static exit
void
gpio_mod_exit(void)
{
misc_deregister(&gpio_dev);
}
module_init (gpio_mod_init);
module_exit (gpio_mod_exit);

MODULE_LICENSE("GPL"); MODULE_AUTHOR("John Crispin / OpenWrt");


MODULE_DESCRIPTION("Character device for for generic gpio api");
Makefile của module này có thể xây dựng như sau:

export ARCH=arm
export CROSS_COMPILE=arm-none-linux-gnueabi-
obj-m += gpio_dev.o

all: make -C /home/AT91SAM9260/KERNEL/linux-2.6.27 M=$(PWD) modules


make -C

clean: /home/AT91SAM9260/KERNEL/linux-2.6.27 M=$(PWD) clean

Sau khi build thành công kernel module (trên máy PC Linux), ta được file gpio_dev.ko.
Để chạy được module, ta chép gpio_dev.ko vào thư mục trong KM9260 và thực hiện các
lệnh insert module vào hệ thống:

$ insmod gpio_dev.ko
$ lsmod
Module Size Used by
gpio_dev 2144 0

Về phía ứng dụng, ta có thể set pin gpio của AT91SAM9260 MPU ở chế độ input,
output, set bit, clear bit theo cú pháp như sau:

$ ./gpioctl dirin|dirout|get|set|clear gpio_num

Ví dụ: Cấu hình PC6 as output và set pin này lên 1 ta thực hiện lệnh sau:

$ ./gpioctl dirout 102


using gpio pin 102
$ ./gpioctl set 102
using gpio pin 102

Ví dụ: Cấu hình PC15 (nút nhấn S3) as input và get giá trị pin này ta thực hiện như sau:

$ ./gpioctl dirin 111


using gpio pin 111
$ ./gpioctl get 111
using gpio pin 111
Pin 111 is HIGH

Nếu ta nhấn S3 thì khi chạy chương trình trên ta có kết quả là LOW. Sau đây là source
code của chương trình ứng dụng trên có tên là "gpioctl.c"
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <linux/ioctl.h>

#define IOC_GPIODEV_MAGIC 'B'


#define GPIO_GET _IO(IOC_GPIODEV_MAGIC, 10)
#define GPIO_SET _IO(IOC_GPIODEV_MAGIC, 11)
#define GPIO_CLEAR _IO(IOC_GPIODEV_MAGIC, 12)
#define GPIO_DIR_IN _IO(IOC_GPIODEV_MAGIC, 13)
#define GPIO_DIR_OUT _IO(IOC_GPIODEV_MAGIC, 14)

void print_usage()
{
printf("gpioctl dirin|dirout|get|set|clear gpio\n");
exit(0);
}

int main (int argc, char **argv)


{
int gpio_pin;
int fd;
int result = 0;

if (argc != 3)
{
print_usage();
}

if ((fd = open("/dev/gpio", O_RDWR)) < 0)


{
printf("Error whilst opening /dev/gpio\n");
return -1;
}

gpio_pin = atoi(argv[2]);

printf("using gpio pin %d\n", gpio_pin);

if (!strcmp(argv[1], "dirin"))
{
ioctl(fd, GPIO_DIR_IN, gpio_pin);
} else if (!strcmp(argv[1], "dirout"))
{
ioctl(fd, GPIO_DIR_OUT, gpio_pin);
} else if (!strcmp(argv[1], "get"))
{
result = ioctl(fd, GPIO_GET, gpio_pin);
printf("Pin %d is %s\n", gpio_pin, (result ? "HIGH" : "LOW"));
} else if (!strcmp(argv[1], "set"))
{
ioctl(fd, GPIO_SET,
gpio_pin);
} else if (!strcmp(argv[1], "clear"))
{
ioctl(fd, GPIO_CLEAR, gpio_pin);
} else print_usage();

return result;
}

2. SỬ DỤNG GPIO IRQ:

Đôi khi ta muốn giao tiếp KM9260 với thiết bị bên ngoài ví dụ như các thiết bị chuyển
đổi, thiết bị đọc thẻ smart card... Thông thường các thiết bị này có chân interrupt dùng
cho việc giao tiếp với host và tạo ra một xung tín hiệu điện nhằm thông báo cho host
trạng thái thiết bị đã chuyển đổi hoàn tất.

Các MPU trong các thệ thống VĐK thông thường có số lượng pin (có thể cấu hình thành
external interrupt source) hạn chế. Đối với hệ thống Linux, ta có thể sử dụng 1 pin GPIO
thông thường như một external interrupt source. Điều này có thể thực hiện bên kernel
space. Đối với user space, ta có thể gửi tính hiệu từ kernel space (soft interrupt) thông
qua cơ chế SIGNAL (sẽ được đề cập sau). Việc sử dụng các GPIO như các nguồn ngắt
ngoài tạo nên sự linh hoạt và tiện lợi cho các hệ thống vận hành với Linux OS.

Chương trình sau (gpio_irq.c) minh họa cách khai báo và sử dụng pin
"AT91_PIN_PB16" (pin 5 trên Externtion J17), khi có xung cạnh lên hoặc cạnh xuống
thì chương trình phục vụ ngắt được gọi và in ra thông báo "gpio isr handler in irq XX".
Sau đây là source của chương trình:

#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/sched.h>
#include <linux/errno.h>
#include <linux/delay.h>
#include <linux/wait.h>

/* For GPIO and interrupt */


#include <linux/gpio.h>
#include <linux/irq.h>
#include <linux/interrupt.h>

#define PIN AT91_PIN_PB16 static int irq;

static irqreturn_t gpio_irq_handler (int irq, void *dev_id)


{
printk (KERN_ALERT "gpio isr handler in irq %d\n", irq);
/* ack the irq here so it stops generating */
return IRQ_HANDLED;
}

static int gpio_irq_init(void)


{
int ret;

ret = gpio_request (PIN, "IRQ"); /* GPIO request*/

if (ret) {
printk (KERN_ALERT "Unable to request PC6\n");
}

at91_set_GPIO_periph (PIN, 1); // PIN as GPIO and Pull Up at91_set_gpio_input


(PIN, 1); // PIN as input and Pull Up at91_set_deglitch (PIN, 1); // PIN
deglitch

irq = gpio_to_irq (PIN); /* Get IRQ number */

printk (KERN_ALERT "IRQ = %d\n", irq);

ret = request_irq (irq, gpio_irq_handler,


IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, "MyIRQ",
NULL);

if (ret) {
printk (KERN_ALERT "IRQ %d is not free\n", irq);
return ret;
}

return 0;
}

static void gpio_irq_exit(void)


{
printk (KERN_ALERT "exit gpio_irq module\n");
free_irq (irq, NULL);
gpio_free (PIN);

module_init(gpio_irq_init);
module_exit(gpio_irq_exit);

MODULE_LICENSE("GPL"); MODULE_AUTHOR("kamejoko80");
MODULE_DESCRIPTION("gpio irq example");

Makefile như sau:

export ARCH=armexport CROSS_COMPILE=arm-none-linux-gnueabi-


obj-m += gpio_irq.o

all:
make -C /home/AT91SAM9260/KERNEL/linux-2.6.27 M=$(PWD)
clean:
modules make -C /home/AT91SAM9260/KERNEL/linux-2.6.27 M=$

(PWD) clean

$ insmod gpio_irq.ko
IRQ = 80
gpio isr handler in irq 80
gpio isr handler in irq 80
gpio isr handler in irq 80

You might also like