1. Trang chủ
  2. » Luận Văn - Báo Cáo

Thiết kế và xây dựng ứng dụng với ARM CotexM3 trên nền CoOSRTOS (BÁO CÁO ĐỒ ÁN KỸ THUẬT MÁY TÍNH)

92 1,4K 0

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Định dạng
Số trang 92
Dung lượng 10,78 MB

Nội dung

Giới Thiệu Đề Tài Với mục tiêu làm quen với cách sử dụng HĐH thời gian thực (Real Time Operating System), Nhóm đã tự xây dựng cho mình hoàn chỉnh phần cứng cũng như ứng dụng chạy trên nền CooCox CoOS – một RTOS miễn phí được xây dựng cho dòng ARMCotexM3 Các module mà nhóm đã hoàn thành • Board phần cứng chạy với chip LPC1766 với các chức năng ngoại vi như ADC, DAC, USB, UART, JTAG, GPIO, TFT LCD • Toàn bộ Driver điều khiển LCD TFT 240x320 điểm ảnh • Phát triển library FAT để truy xuất file theo định dạng FAT từ thẻ nhớ • Xây dựng chương trình chơi nhạc WAV player, với wave file được đọc từ thẻ nhớ • Xây dựng chương trình BMP Viewer, với BMP file được đọc từ thẻ nhớ MicroSDCard • Toàn bộ giao diện được hiển thị trên LCD Graphic 2.4 inch và tương tác với người dùng bằng module Touching Mục Lục 1 Phần 1. Tìm hiểu CooCox CoOS RTOS 6 1.1 Mục tiêu 6 1.2 Kernel CoOS 6 1.2.1 Vấn đề Task Management 6 1.2.1.1 Các trạng thái của task 6 1.2.1.2 Task Control Block – Nơi lưu giữ thông tin một task 6 1.2.1.3 Ready Task List – Hàng đợi của các task ở trạng thái ready 8 1.2.1.4 Task Scheduling Định thời cho các task 8 1.2.1.5 Cách thức xử lí Critical Section của CoOS 9 1.2.1.6 Các interrupt trong CoOS 9 1.2.2 Vấn đề quản lí thời gian 10 1.2.2.1 System Tick 10 1.2.2.2 Delay Management 11 1.2.2.3 Software Timer 12 1.2.3 Memory Management – Quản lí bộ nhớ 12 1.2.3.1 Static Memory Allocation – Cấp phát bộ nhớ tĩnh 12 1.2.3.2 Dynamic Memory Management – Quản lí bộ nhớ động 13 1.2.3.3 Kiểm tra Stack Overfloaw 16 1.2.4 Intertask Synchronization – Vấn đề đồng bộ các task 17 1.2.4.1 Semaphore 17 1.2.4.2 Mutex 18 1.2.4.3 Flag 20 1.2.5 Intertask Communication – Vấn đề giao tiếp giữa các task 22 1.2.5.1 Mailbox 22 1.2.5.2 Message queue 23 1.3 Ứng dụng các API của CoOS 24 1.3.1 Các API liên quan đến OS. 24 1.3.1.1 CoInitOS() 24 1.3.1.2 CoStartOS() 25 1.3.2 Các API liên quan đến Task. 25 1.3.2.1 CoCreateTask() 25 1.3.2.2 CoExitTask() 26 1.3.2.3 CoDelTask() 26 1.3.3 Các API liên quan đến Software Timer. 27 1.3.3.1 CoCreateTmr () 27 1.3.3.2 CoStartTmr () 27 1.3.4 Các API liên quan đến Flag. 28 1.3.4.1 CoCreateFlag () 28 1.3.4.2 CoSetFlag () 28 1.3.4.3 CoWaitForSingFlag () 29 2 Phần 2. Các module hộ trợ cho việc phát triển ứng dụng trên CooCox CoOS 30 2.1 SDCard và giao tiếp SPI trên LPC1766 30 2.1.1 SDCard 30 2.1.1.1 Giới thiệu 30 2.1.1.2 Giao thức truyền dữ liệu 30 2.1.1.3 Sơ đồ chân 30 2.1.1.4 Thanh ghi 31 2.1.2 Module SPI trong LPC1766 33 2.1.2.1 Giới thiệu 33 2.1.2.2 Cấu hình căn bản khi sử dụng module SPI trong LPC1766 33 2.1.2.3 Hệ thống thanh ghi trong SPI: 33 2.1.2.4 Hoạt động của module SPI ở chế độ Master 36 2.1.3 Giao tiếp SPI giữa SD Card và LPC1766 36 2.1.3.1 Cấu hình kênh giao tiếp SPI 36 2.1.3.2 Cách thức trao đổi dữ liệu trên kênh SPI 36 2.1.3.3 Định dạng thông tin 37 2.1.3.4 Một số hoạt động diễn ra trên kênh SPI 39 2.2 Cấu trúc dữ liệu và hệ thống tập tin FAT 39 2.2.1 Cấu trúc vùng dữ liệu của thẻ nhớ 39 2.2.1.1 Partition Area 39 2.2.1.2 Regular Area 40 2.2.2 Hệ thống tập tin FAT 40 2.2.2.1 Cấu trúc tổng quan 40 2.2.2.2 Boot Sector 41 2.2.2.3 Bảng FAT (File Allocation Table) và cơ chế lưu trữ, cấp phát file 42 2.2.2.4 Thư mục (directory) 43 2.3 Thư viện EFSL 43 2.3.1 Tổng quan 43 2.3.2 Cấu hình và sử dụng EFSL 44 2.3.2.1 Cấu hình các thông số: 44 2.3.2.2 Hiện thực Hardware endpoint 44 2.3.2.3 Các hàm giao diện người dùng: 45 2.3.3 Cấu trúc EFSL 45 2.4 Xây dựng thư viện cho TFT LCD 2.4’ sự dụng chip điều khiên ILI9320 47 1.1. Giới thiệu 47 2.4.1 Xây dựng thư viện cho TFT LCD 47 2.4.1.1 Các hàm cấp thấp giao tiếp với phần cứng của LCD 47 2.4.1.2 Các hàm cấp cao phục vụ người dùng. 49 2.5 Module Touching 55 2.5.1 Cơ chế hoạt động 55 2.5.2 Hiện thực 56 2.6 Mô tả về Board hỗ trợ 57 3 Phần 3. Xây dựng ứng dụng 58 3.1 Task GUIMain 58 3.2 Task WAVPlayer 60 3.2.1 Định dạng của file WAVE 60 3.2.2 Hiện thực Task WAVPlayer 62 3.3 Task BMPViewer 64 3.3.1 Định dạng ảnh BMP 64 3.3.1.1 Giới thiệu: 64 3.3.1.2 Thuộc tính của BMP 64 3.3.1.3 Cấu trúc của BMP: Một tập tin BMP thường chứa những khối dữ liệu sau: 65 3.3.1.4 Sự dụng định dạng BMP 66 3.3.2 Hiện thực module BMP 67 3.3.2.1 Vai trò của module BMP 67 3.3.2.2 Các cấu trúc dữ liệu được sử dụng trong module BMP 67 3.3.2.3 Mô tả các hàm được cung cấp bởi module BMP 67 3.3.3 Hiện thực task BMPViewer 67 3.3.3.1 Giới thiệu 67 3.3.3.2 Hiện thực 67 4 Phần 4. Tổng Kết 68 Tài liệu tham khảo 70 Phục Lục 71 1 Phần 1. Tìm hiểu CooCox CoOS RTOS 1.1 Mục tiêu Tìm hiểu kernel CooCox CoOS (open source): cách quản lí các task, quản lí thời gian, quản lí bộ nhớ và điểu khiển việc đồng bộ, giao tiếp giữa các task.

Trang 2

Giới Thiệu Đề Tài

Với mục tiêu làm quen với cách sử dụng HĐH thời gian thực (Real Time Operating System), Nhóm đã tự xây dựng cho mình hoàn chỉnh phần cứng cũng như ứng dụng chạy trên nền CooCox CoOS – một RTOS miễn phí được xây dựng cho dòng ARM-Cotex-M3

Các module mà nhóm đã hoàn thành

 Board phần cứng chạy với chip LPC1766 với các chức năng ngoại vi như ADC, DAC, USB, UART, JTAG, GPIO, TFT LCD

 Toàn bộ Driver điều khiển LCD TFT 240x320 điểm ảnh

 Phát triển library FAT để truy xuất file theo định dạng FAT từ thẻ nhớ

 Xây dựng chương trình chơi nhạc WAV player, với wave file được đọc từ thẻ nhớ

 Xây dựng chương trình BMP Viewer, với BMP file được đọc từ thẻ nhớ MicroSDCard

 Toàn bộ giao diện được hiển thị trên LCD Graphic 2.4 inch và tương tác với người dùng bằng module Touching

Trang 3

Mục Lục

1 Phần 1 Tìm hiểu CooCox CoOS RTOS 6

1.1 Mục tiêu 6

1.2 Kernel CoOS 6

1.2.1 Vấn đề Task Management 6

1.2.1.1 Các trạng thái của task 6

1.2.1.2 Task Control Block – Nơi lưu giữ thông tin một task 6

1.2.1.3 Ready Task List – Hàng đợi của các task ở trạng thái ready 8

1.2.1.4 Task Scheduling - Định thời cho các task 8

1.2.1.5 Cách thức xử lí Critical Section của CoOS 9

1.2.1.6 Các interrupt trong CoOS 9

1.2.2 Vấn đề quản lí thời gian 10

1.2.2.1 System Tick 10

1.2.2.2 Delay Management 11

1.2.2.3 Software Timer 12

1.2.3 Memory Management – Quản lí bộ nhớ 12

1.2.3.1 Static Memory Allocation – Cấp phát bộ nhớ tĩnh 12

1.2.3.2 Dynamic Memory Management – Quản lí bộ nhớ động 13

1.2.3.3 Kiểm tra Stack Overfloaw 16

1.2.4 Intertask Synchronization – Vấn đề đồng bộ các task 17

1.2.4.1 Semaphore 17

1.2.4.2 Mutex 18

1.2.4.3 Flag 20

1.2.5 Intertask Communication – Vấn đề giao tiếp giữa các task 22

1.2.5.1 Mailbox 22

1.2.5.2 Message queue 23

1.3 Ứng dụng các API của CoOS 24

1.3.1 Các API liên quan đến OS 24

1.3.1.1 CoInitOS() 24

1.3.1.2 CoStartOS() 25

1.3.2 Các API liên quan đến Task 25

1.3.2.1 CoCreateTask() 25

1.3.2.2 CoExitTask() 26

1.3.2.3 CoDelTask() 26

1.3.3 Các API liên quan đến Software Timer 27

1.3.3.1 CoCreateTmr () 27

1.3.3.2 CoStartTmr () 27

1.3.4 Các API liên quan đến Flag 28

1.3.4.1 CoCreateFlag () 28

Trang 4

1.3.4.2 CoSetFlag () 28

1.3.4.3 CoWaitForSingFlag () 29

2 Phần 2 Các module hộ trợ cho việc phát triển ứng dụng trên CooCox CoOS 30

2.1 SDCard và giao tiếp SPI trên LPC1766 30

2.1.1 SDCard 30

2.1.1.1 Giới thiệu 30

2.1.1.2 Giao thức truyền dữ liệu 30

2.1.1.3 Sơ đồ chân 30

2.1.1.4 Thanh ghi 31

2.1.2 Module SPI trong LPC1766 33

2.1.2.1 Giới thiệu 33

2.1.2.2 Cấu hình căn bản khi sử dụng module SPI trong LPC1766 33

2.1.2.3 Hệ thống thanh ghi trong SPI: 33

2.1.2.4 Hoạt động của module SPI ở chế độ Master 36

2.1.3 Giao tiếp SPI giữa SD Card và LPC1766 36

2.1.3.1 Cấu hình kênh giao tiếp SPI 36

2.1.3.2 Cách thức trao đổi dữ liệu trên kênh SPI 36

2.1.3.3 Định dạng thông tin 37

2.1.3.4 Một số hoạt động diễn ra trên kênh SPI 39

2.2 Cấu trúc dữ liệu và hệ thống tập tin FAT 39

2.2.1 Cấu trúc vùng dữ liệu của thẻ nhớ 39

2.2.1.1 Partition Area 39

2.2.1.2 Regular Area 40

2.2.2 Hệ thống tập tin FAT 40

2.2.2.1 Cấu trúc tổng quan 40

2.2.2.2 Boot Sector 41

2.2.2.3 Bảng FAT (File Allocation Table) và cơ chế lưu trữ, cấp phát file 42

2.2.2.4 Thư mục (directory) 43

2.3 Thư viện EFSL 43

2.3.1 Tổng quan 43

2.3.2 Cấu hình và sử dụng EFSL 44

2.3.2.1 Cấu hình các thông số: 44

2.3.2.2 Hiện thực Hardware endpoint 44

2.3.2.3 Các hàm giao diện người dùng: 45

2.3.3 Cấu trúc EFSL 45

2.4 Xây dựng thư viện cho TFT LCD 2.4’ sự dụng chip điều khiên ILI9320 47

1.1 Giới thiệu 47

2.4.1 Xây dựng thư viện cho TFT LCD 47

2.4.1.1 Các hàm cấp thấp giao tiếp với phần cứng của LCD 47

2.4.1.2 Các hàm cấp cao phục vụ người dùng 49

2.5 Module Touching 55

2.5.1 Cơ chế hoạt động 55

Trang 5

2.5.2 Hiện thực 56

2.6 Mô tả về Board hỗ trợ 57

3 Phần 3 Xây dựng ứng dụng 58

3.1 Task GUIMain 58

3.2 Task WAVPlayer 60

3.2.1 Định dạng của file WAVE 60

3.2.2 Hiện thực Task WAVPlayer 62

3.3 Task BMPViewer 64

3.3.1 Định dạng ảnh BMP 64

3.3.1.1 Giới thiệu: 64

3.3.1.2 Thuộc tính của BMP 64

3.3.1.3 Cấu trúc của BMP: Một tập tin BMP thường chứa những khối dữ liệu sau: 65

3.3.1.4 Sự dụng định dạng BMP 66

3.3.2 Hiện thực module BMP 67

3.3.2.1 Vai trò của module BMP 67

3.3.2.2 Các cấu trúc dữ liệu được sử dụng trong module BMP 67

3.3.2.3 Mô tả các hàm được cung cấp bởi module BMP 67

3.3.3 Hiện thực task BMPViewer 67

3.3.3.1 Giới thiệu 67

3.3.3.2 Hiện thực 67

4 Phần 4 Tổng Kết 68

Tài liệu tham khảo 70

Phục Lục 71

Trang 6

1 Phần 1 Tìm hiểu CooCox CoOS RTOS1.1 Mục tiêu

Tìm hiểu kernel CooCox CoOS (open source): cách quản lí các task, quản lí thời gian, quản lí bộ nhớ và điểu khiển việc đồng bộ, giao tiếp giữa các task

1.2 Kernel CoOS

Đây là một nhân hệ điều hành thời gian thực, đa nhiệm, nguồn mở, tương thích với họ LPC1700 dùng chip vi xử lí ARM Cotex-M3

1.2.1 Vấn đề Task Management

CoOS dùng cơ chế scheduling preemptive và round robin Một task là một công việc cụ

thể mà CPU phải làm, một application có thể gồm nhiều task Đối với hệ điều hành đa nhiệm, vào một thời điểm, có nhiều công việc cần được CPU thực hiện Vấn đề quản lí các task như thứ

tự thực hiện, thời gian thực hiện từng task, …sao cho đạt được hiệu suất cao là vấn đề cốt lõi củamọi hệ điều hành đa nhiệm

1.2.1.1 Các trạng thái của task

Running: Khi một task đang được CPU thực hiện thì nó ở trạng thái running.

Ready : Khi một task đang chờ CPU thì nó ở trạng thái ready Một task khi được tạo

ra sẽ ở vào trạng thái ready

Waiting : Một task đang chờ một sự kiện nào đó xảy ra (chẳng hạn IO) sẽ ở vào trạng

thái waiting

Dormant: Một task bị xóa khỏi bộ nhớ, không bao giờ được thực hiện nữa sẽ ở vào

trạng thái dormant (terminated)

1.2.1.2 Task Control Block – Nơi lưu giữ thông tin một task

Khi hệ điều hành đa nhiệm chuyển CPU từ task này qua cho task khác (vì thời gian dành cho task cũ đã hết), cần có một khối dữ liệu để lưu các thông tin về task cũ (chẳng hạn câu lệnh đang thực hiện) để nó có thể được thực hiện tiếp sau này Khối dữ liệu này là gọi là một Task Control Block (TCB) có kiểu là struct

typedef struct TCB{

OS_STK *stkPtr;

/*CoOS tạo cho mỗi task một stack để lưu trạng thái của CPU Điều này đồng nghĩa với việc lưu 16 thanh ghi đa dụng 32 bit của CPU (trong đó có thanh ghi

Trang 7

Progam Counter cho biết đang thực hiện lệnh nào của task) Do cần thêm 4 byte

để phát hiện stack bị over flow, tối thiểu mỗi stack phải có sức chứa 68 byte*/

/*ID của task, dùng để xác định một task*/

#if CFG_MUTEX_EN > 0 OS_MutexID mutexID;

#endif/*Nếu như có sử dụng cơ chế Mutex thì định nghĩa mutexID là ID xác định Mutex Cách viết #if … #endif này giúp tiết kiệm bộ nhớ */

#if CFG_EVENT_EN > 0 OS_EventID eventID; /*!< Event ID.*/

#endif

#if CFG_ROBIN_EN >0 U16 timeSlice; /*!< Task time slice */

#endif

#if CFG_EVENT_EN > 0 struct TCB *waitNext; /*!<Next TCB in the Event waiting list */ struct TCB *waitPrev; /*!<PrevTCB in the Event waiting list.*/

#endif

#if CFG_FLAG_EN > 0 void* pnode; /*!< Pointer to node of event flag.*/

#endif U32 delayTick; /*!< The number of ticks which delay */ struct TCB *TCBnext; /*!< The pointer to next TCB.*/

struct TCB *TCBprev; /*!< The pointer to prev TCB */

}OSTCB,*P_OSTCB;

Các TCB được tổ chức thành một danh sách liên kết một chiều, các TCB đã cấp phát cho các task nằm ở đầu danh sách, TCB cấp phát cuối cùng trỏ vào TCB trống đầu tiên Nếu TCB cấp phát cuối cùng trỏ vào NULL, thì có nghĩa là đã hết TCB trống và task sẽ không được tạo ra nữa

Lúc mới khởi động hệ thống, các TCB đều trống, và được tổ chức như sau:

Trang 8

1.2.1.3 Ready Task List – Hàng đợi của các task ở trạng thái ready

Hàng đợi này được tổ chức theo một danh sách liên kết 2 chiều, mỗi mắt xích là một TCB của một task Khi một task được tạo ra, TCB nó sẽ được xếp vào danh sách liên kết theo nguyên tắc FIFO có tính đến priority, tức là xếp vào cuối cụm các mắt xích TCB có cùng priorityvới nó

Task có TCB ở đầu hàng đợi sẽ là task được ưu tiên cao nhất, TCB đó gọi là RdyTCB

1.2.1.4 Task Scheduling - Định thời cho các task

Đối với các task khác priority, CoOS sử dụng cơ chế định thời Preemptive, tức là một

task ready có thể giành quyền thực thi từ một task running nếu nó priority cao hơn Đối với các

task cùng priority, CoOS dùng cơ chế định thời Round robin, tức là luân chuyển CPU giữa các

task, mỗi task được cấp CPU một khoảng thời gian nhất định gọi là time slice Các time slice chocác task có thể khác nhau, như trong hình sau minh họa 3 task A, B, C có time slice lần lượt là 1,

2, 3

CoOS làm công việc định thời khi một trong các điều kiện sau xảy ra:

a Một task có priority cao hơn task running được chuyển vào trạng thái ready Ở trường hợp này, hệ điều hành sẽ thực hiện cơ chế preemptive (tranh giành)

b Task running chuyển sang trạng thái waiting hay dormant Ở trường hợp này, hệ điều hành chỉđơn giản lấy task ready đầu hàng đợi ra, đưa nó vào trạng thái running

Trang 9

c Task running đã dùng hết time slice của nó và có task khác trong ready list có cùng priority với task running Ở trường hợp này, hệ điều hành sẽ thực hiện cơ chế round robin.

Cụ thể là hàm định thời Schedule sẽ được gọi khi có một tick interrupt (hết time slice) hay có một sự chuyển trạng thái xảy ra

/*a Is higher PRI task coming in? */

if(RdyPrio < RunPrio ) //priority number bé hơn nghĩa là priority cao hơn 

{

TCBNext = pRdyTCB; //chuyển ngữ cảnh, đưa RdyTCB vào trạng thái running

pCurTcb->state = STATE_READY; //chuyển trạng thái

pRdyTcb->state = STATE_RUNNING;

InsertToTCBRdyList (pCurTCB);

RemoveFromTCBRdyList (pRdyTCB);

}

/*b Does Running task status change */

else if(pCurTcb->state != TASK_RUNNING)

/* c Is it the time for robinning */

else if((RunPrio == RdyPrio) && (OSCheckTime == OSTickCnt))

{

TCBNext = pRdyTCB; //chuyển ngữ cảnh, đưa RdyTCB vào trạng thái running

pCurTcb->state = STATE_READY; //chuyển trạng thái

pRdyTcb->state = STATE_RUNNING;

InsertToTCBRdyList (pCurTCB);

RemoveFromTCBRdyList (pRdyTCB);

}

1.2.1.5 Cách thức xử lí Critical Section của CoOS

Critical Section là đoạn code có câu lệnh làm thay đổi các tài nguyên dùng chung giữa các task và do đó không được chuyển ngữ cảnh khi đang thực thi trong Critical Section Các cách xử lí Critical Section là: cấm các interrupt hoặc cấm các system call có thể gây chuyển ngữ cảnh trong Critical Section CoOS chọn cách disable bộ định thời thay vì disable các interrupt để đảm bảo tính đáp ứng của hệ thống, vốn rất quan trọng trong các hệ thống thời gian thực

void Task1(void* pdata)

1.2.1.6 Các interrupt trong CoOS

CoOS phân loại 2 kiểu interrupt, dựa vào tiêu chí nó có gọi các hàm API của CoOS hay không Các interrupt không gọi API không ảnh hưởng gì đến hệ điều hành, do đó CoOS không

Trang 10

đặt đòi hỏi gì các interrupt này Đối với các interrupt có gọi API, CoOS yêu cầu bạn phải gọi các API thích hợp bên trong interrupt Ví dụ:

void WWDG_IRQHandler(void)

{

CoEnterISR ( ); // Enter the interrupt

isr_SetFlag(flagID); // API function

; // Interrupt service routine

CoExitISR ( ); // Exit the interrupt

}

Mọi API có thể được gọi trong ISR bắt đầu bởi isr_, như isr_PostSem ( ), isr_PostMail ( ), isr_PostQueueMail ( ) và isr_SetFlag ( ) Việc gọi một API khác bên trong ISR sẽ dẫn đến tình trạng system chaos

Khi gọi một API tương ứng trong ISR, hệ thống cần xác định xem bộ định thời đang bị khóa hay không Nếu như không khóa, hệ thống có thể gọi nó một cách bình thường Ngược lại,

hệ thống sẽ gửi một service request phù hợp đến list các service request và đợi đến khi bộ định thời được mở khóa mới đáp ứng nó

1.2.2 Vấn đề quản lí thời gian

1.2.2.1 System Tick

CoOS sử dụng interrupt systick để hiện thực system tick (tick: một khoảng thời gian rất ngắn) Bạn cần thiết lập tần số của system tick trong file config.h CFG_CPU_FREQ là tần số của CPU clock CFG_SYSTICK_FREQ là tần số của system tick bạn muốn CoOS hỗ trợ tần số

từ 1 đến 1000Hz, mặc định là 100Hz

SYSTICK là gì?

SYSTICK là một Timer được tích hợp vào NVIC và được sử dụng để phát sinh một SYSTICK exception (exception kiểu #15) Exception là một điều kiện đặc biệt có thể làm thay đổi dòng chảy bình thường của chương trình NVIC là một bộ phận được tích hợp với vi xử lí Cotex M3, có khả năng hỗ trợ đến 240 ngắt ngoài với số mức ưu tiên lên tới 256 và có thể quy định lại mức ưu tiên

SYSTICK là một hardware timer, nên không phụ thuộc vào các task đang chạy và do đó

hệ thống không bị task đó chiếm quyền Để làm được điều này, timer cần có khả năng tạo ra interrupt và được bảo vệ khỏi những user task để không có một user application nào có thể thay đổi timer

CoOS tăng giờ hệ thống lên 1 trong mỗi system tick ISR Bạn có thể xem giờ hệ thống bằng cách gọi hàm CoGetOSTime() CoOS cũng kiểm tra xem delayed list và timer list có rỗng hay không trong system tick ISR mà không tăng system time lên 1 Nếu list không trống, giảm delayed time của của phần tử đầu trong list đi 1 đơn vị, và kiểm tra xem có phải là waiting time của phần tử đầu trong list đã hết hay không Nếu hết rồi, gọi hàm xử lí tương ứng, nếu không, chuyển qua bước tiếp theo

CoOS gọi hàm định thời để xác định xem hệ thống có cần phải chạy bộ định thời hay không khi thoát từ system tick ISR

Đoạn mã sau xử lí một system tick interrupt

void SysTick_Handler(void)

{

OSSchedLock++; /* Lock the scheduler */

OSTickCnt++; /* Increment system time */

if(DlyList != NULL) /* Have task in delayed list? */

Trang 11

DlyList->delayTick ; /* Decrease delay time of the list head */

if(DlyList->delayTick == 0) /* Delay time == 0? */

{

isr_TimeDispose(); /* Call hander for delay time list */

}}

#if CFG_TMR_EN > 0

if(TmrList != NULL) /* Have timer be in working? */

{

TmrList->tmrCnt ; /* Decrease timer time of the list head */

if(TmrList->tmrCnt == 0) /* Timer time == 0? */

{

isr_TmrDispose(); /* Call hander for timer list */

}}

delayed list Biến delayTick trong TCB lưu lại sự khác biệt giá trị của thời gian delay giữa task hiện thời và task trước Phần tử đầu của list là giá trị thời gian delay hay thời gian timeout, trong khi những phần tử tiếp theo là sự sai biệt giá trị với phần tử trước nó Để dễ hiểu, hình dung task

A, B, C có thời gian delay lần lượt là 10, 18, 5, khi đó chúng được sắp vào delayed list như sau:

Hệ thống sẽ giảm giá trị đầu list đi 1 mỗi system tick interrupt, và chuyển nó vào ready list nếu nó đã đạt giá trị 0 Khi chuyển các task có giá trị delayTick (xem hình) đạt 0, hệ thống phải xác định xem cần phải xử lí theo delay hay theo timeout Đối với delay, CoOS, đưa nó vào

Trang 12

ready list sau khi nó đã đưa ra khỏi delayed list Đối với timeout, CoOS sẽ kiểm tra xem sự kiện nào dẫn tới overtime trước rồi mới chuyển task từ waiting list sang ready list.

CoOS không bảo đảm độ chính xác dưới những điều kiện sau:

i Có một task có độ ưu tiên cao hơn task Achiếm CPU khi task A đang bị delayed, thời

gian delay sẽ được xác định bằng thời gian chạy của task có độ ưu tiên cao hơn

ii Có một task có độ ưu tiên bằng task A chiếm CPU khi task A đang bị delayed, thời

gian delay được tính bằng số task có độ ưu tiên bằng task A ở trong ready list và chiều dài của time slice cũng như thời điểm kết thúc delay time

1.2.2.3 Software Timer

Software Timer (ST) là một timer chính xác cao, lấy nguồn là system tick CoOS hỗ trợ

32 ST, mỗi ST có thể ở mode periodic (tuần hoàn) hay mode one-shot (một lần)

Khi bạn tạo ra một ST bằng hàm CoCreateTmr(), ST được tạo ra ở trạng thái stopping, bạn phải gọi hàm CoStartTmr() để bật nó chạy Khi một ST được tạo ra, CoOS gán cho nó một Timer Control Block để lưu lại trạng thái của ST CoOS quản lí các ST bằng một danh sách liên kết 2 chiều, với cách tổ chức tương tự delayed list Ví dụ 3 timer A, B, C được thiết lập giá trị

10, 18, 5 sẽ được tổ chức như sau:

Khi một ST bắt đầu chạy, nó sẽ hoàn toàn không phụ thuộc vào các module khác ngoại trừ system tick interrupt CoOS giảm giả trị của ST đầu list đi 1 mỗi system tick interrupt

Khi giá trị trong ST đạt 0, ST kiểu periodic sẽ thiết lập lại timer dựa vào giá trị tmrReload

mà bạn quy định và đưa trở lại vào timer list Ngược lại, ST kiểu one-shot sẽ bị đưa ra khỏi list

và trạng thái của nó được đưa vào stop

1.2.3 Memory Management – Quản lí bộ nhớ

1.2.3.1 Static Memory Allocation – Cấp phát bộ nhớ tĩnh

Việc cấp phát bộ nhớ tĩnh được áp dụng khi bạn không biết chắc bạn cần bao nhiêu dung lượng bộ nhớ khi biên dịch, và bộ nhớ tĩnh cũng không thể được giải phóng hay phân phối lại trong lúc hệ thống đang chạy Ưu điểm của bộ nhớ tĩnh so với bộ nhớ động là nó không chiếm tài nguyên CPU, và luôn luôn được cấp phát thành công (vì nếu không đã bị lỗi biên dịch) Vì thế, nó nhanh và an toàn hơn

CoOS cấp bộ nhớ tĩnh cho các module sau: TCB, ECB (event CB), FCB (flag CB), flag node (FLAG_NODE), … Sau đây là ví dụ về cấp bộ nhớ tĩnh cho TCB

Trang 13

1.2.3.2 Dynamic Memory Management – Quản lí bộ nhớ động

Việc cấp bộ nhớ động là cần thiết khi dung lượng bộ nhớ cần thiết không thể được xác định trong khi biên dịch mà phụ thuộc vào môi trường runtime khi hệ thống đang chạy Việc cấp

bộ nhớ tĩnh là dựa trên kế hoạch; trong khi việc cấp bộ nhớ động là dựa trên yêu cầu tức thời

Bộ nhớ động linh hoạt hơn và sử dụng hiệu quả bộ nhớ Tuy nhiên nó chiếm CPU và có thể làm phân mảnh bộ nhớ, và không phải lúc nào cũng cấp phát được

Hai hàm cơ bản liên quan đến bộ nhớ động là malloc() và free() Khi bạn gọi malloc(), hệthống sẽ thực hiện những bước sau:

i Tìm khối bộ nhớ thỏa mãn yêu cầu Thuật toán thường dùng nhất là first matching,

tức là gán ngay khối nhớ đầu tiên thỏa mãn yêu cầu Thuật toán này tối thiểu thời gian tìm kiếm, song lại làm phân mảnh bộ nhớ

ii Chia khối nhớ ra làm hai, phần đúng bằng dung lượng được yêu cầu và phần còn lại.iii Chuyển phần thứ nhất cho người dùng, trả khối thứ hai về cho free list

Hệ thống đưa khối nhớ bạn trả lại vào free list và làm thao tác kết khối nếu nó nằm kề vớimột khối nhớ free khác Sau đây là sơ đồ

Từ sơ đồ trên, task thấy rằng free list sẽ được chia thành nhiều mảnh nhỏ sau nhiều lần cấp phát và giải phóng bộ nhớ, dẫn đến tình trạng phân mảnh bộ nhớ Hệ thống lúc này phải dò tìm đến cuối free list mà vẫn không tìm được khối bộ nhớ phù hợp để gán cho ứng dụng

Để khắc phục tình trạng trên, CoOS đưa ra hai cơ chế phân vùng bộ nhớ: cơ chế chiều dài

cố định và cơ chế chiều dài thay đổi

1.2.3.2.1 Phân vùng chiều dài cố định

Trang 14

Hệ thống chia khối nhớ lớn ra làm nhiều block có chiều dài cố định và bằng nhau, sau đó liên kết chúng lại thành một list Bạn có thể cấp hay giải phóng phân vùng nhớ có chiều dài cố định, một phân vùng gồm nhiều block nhớ có độ dài bằng nhau Cách này đảm bảo thời gian cấp phát hay giải phóng cố định và tránh được phân mảnh Sau đây là sơ đồ một phân vùng nhớ có chiều dài cố định.

CoOS có thể quản lí 32 phân vùng như thế, các vùng có thể khác nhau về kích thước (tùy yêu cầu của người dùng) Bạn tạo phân vùng bằng hàm hệ thống CoCreateMemPartition() Sau khi đã tạo thành công phân vùng, bạn cấp phát hay giải phóng bộ nhớ bằng cách gọi hàm

CoGetMemoryBuffer() và CoFreeMemoryBuffer() Để lấy số thứ tự của khối nhớ trống, bạn gọihàm CoGetFreeBlockNum() Trong ví dụ sau, một phân vùng gồm 20 khối nhớ 128 byte được tạo ra, sau đó một khối nhớ trống được cấp cho ứng dụng, và cuối cùng khối nhớ đó được giải phóng

1.2.3.2.2 Phân vùng chiều dài thay đổi

Cách tổ chức trên đòi hỏi phải thao tác trên cả hai list Cũng có thể tổ chức phân vùng nhớ thành một list để giảm bớt các thao tác mà CPU phải thực hiện CoOS gọi cách tổ chức này

là một KHEAP (kernel heap)

Trang 15

Cách tổ chức như trên có điểm lợi là khi giải phóng vùng nhớ, hệ điều hành không phải tìm kiếm chỗ chèn từ đầu list Nó chỉ cần tìm block trống ở đằng trước và chèn vào list, tăng tínhhiệu quả của bộ nhớ Trong hình vẽ trên, block 1 và block 2 đã có sẵn thông tin về block trống đằng trước nó, do đó rất dễ để đưa nó vào free list Đối với block 3 và 4, cần thêm một thao tác

dò ngược để tìm block trống đằng trước Ví dụ:

Bộ nhớ được quản lí theo từng khối 4 byte, nếu như số byte yêu cầu cấp phát không chia hết cho 4 thì làm tròn lên rồi mới cấp phát Do đó 2 bit cuối của địa chỉ bộ nhớ không có ý nghĩa.CoOS tận dụng bit cuối cùng làm bit thông tin về block nhớ: 0 là free block và 1 là block đã được cấp phát

Sau đây là các thông tin liên quan đến KHEAP:

Trang 16

Sau khi đã enable KHEAP, bạn có thể sử dụng các hàm CoKCreate() (tạo heap),

CoKMalloc(U32 size) (cấp phát size byte), CoKFree() (giải phóng heap)

1.2.3.3 Kiểm tra Stack Overfloaw

Như đã nói trong phần task control block, mỗi task sở hữu 1 stack Nếu stack bị tràn, thông tin được lưu ra ngoài stack, và có thể trùng lắp lên thông tin của task khác Do đó để hệ thống chạy đúng, cần kiểm tra stack của task trong quá trình scheduling CoOS lưu địa chỉ của stack bottom trong TCB (biến stack) và ghi vào stack bottom một giá trị đặc biệt

(MAGIC_WORD) để kiểm tra stack overflow

Khi xảy ra overflow, hàm CoStkOverFlowHook sẽ được gọi, bạn cần hiện thực hàm này:

Trang 17

1.2.4 Intertask Synchronization – Vấn đề đồng bộ các task

Intertask Synchronization có nghĩa là một task chỉ có thể thực thi tiếp sau khi nó nhận được tín hiệu đồng bộ từ một task khác hay là từ một ISR Cách hiện thực Intertask

Synchronization có thể là semaphore, mutex hay flag

1.2.4.1 Semaphore

Semaphore là một phương pháp phổ biến trong việc đồng bộ các task Semaphore là một biến số s, đại diện cho một loại tài nguyên nào đó Giá trị lớn nhất của s là số tài nguyên cùng

loại có thể cấp cho các task Có hai phương thức cơ bản tác động lên một semaphore s là P ( viết

tắt của từ probeer te verlagen trong tiếng Hà Lan, quê hương của Dijkstra, nghĩa là kiểm tra để giảm) và V( verhogen, nghĩa là tăng).

Các API liên quan:

CoCreateSem (): tạo semaphore

CoPendSem (): thực hiện thao tác P nói trên, nó sẽ phải đợi cho đến khi s > 0.

CoAcceptSem(): tương tự như CoPendSem nhưng thay vì phải đợi, nó sẽ trả về giá trị báo error

ngay lập tức

CoPostSem (): thực hiện thao tác V.

Isr_CoPostSem (): như CoPostSem nhưng áp dụng cho hàm interrupt.

Đoạn code sau minh họa việc tạo semaphore:

Đoạn code sau minh họa việc sử dụng semaphore:

Trang 18

1.2.4.2 Mutex

Mutex là một semaphore chỉ nhận hai giá trị là 0 và 1 Vì vậy, Mutex được dùng để cho phép chỉ một task có thể nhận tài nguyên vào một thời điểm, chẳng hạn một biến chung chia sẻ giữa các task Đoạn code chứa các câu lệnh truy cập vào tài nguyên đó gọi là Critical Section

Điểm đặc thù của khái niệm Mutex so với semaphore hai trạng thái là Mutex thường

được thêm vào tính năng chống priority inversion.

Priority intersion là một hiện tượng xảy ra trong quá trình định thời Đó là khi một

high-priority task phải chờ tài nguyên từ một low-high-priority task, trong khi low-high-priority task lại phải chờmột medium-priority task Low-priority task bị medium-priority task chiếm quyền, trong khi high-priority task không thể chiếm quyền low-priority task vì low-priority task đang ở trong Critical Section Điều này dẫn tới việc high-priority task phải chờ rất lâu mới được thực hiện Hiện tượng này đặc biệt nghiêm trọng trong hệ thống realtime bởi vì high-priority task thường là những task đòi hỏi tính đáp ứng cao, thời gian đáp ứng nhỏ hơn nhiều so với medium hay low-priority task

Để giải quyết priority inversion, thường người ta nâng priority của low-priority task lên

để nó không bị medium-priority task chiếm quyền Có hai phương pháp cơ bản sau:

i Ceilling priority: Đặt cho tài nguyên một priority (ceilling priority) Priority này là priority cao

nhất trong số priority của các task có thể chiếm tài nguyên Khi một task chiếm tài nguyên, priority của nó được tạm thời gán bằng ceilling priority Sau khi trả tài nguyên, priority của nó trở về giá trị ban đầu

ii.Priority inheritance: Khi một task chiếm tài nguyên, nó thừa kế priority (nhận priority) của

task có priority cao nhất trong số các task yêu cầu tài nguyên Sau khi trả tài nguyên, priority của

Trang 19

nó trở về giá trị ban đầu Phương pháp này linh động hơn ở chỗ nếu không có high-priority task nào đang yêu cầu tài nguyên thì low-priority task vẫn giữ priority cũ của nó.

Hình vẽ sau minh họa phương pháp priority inheritance với 3 task A, B, C có priority tương ứng là high, medium và low

Các API liên quan:

CoCreateMutex (): Tạo một mutex.

CoEnterMutex (), CoLeaveMutex (): vào, ra mutex section.

Đoạn code sau minh họa cách sử dụng các API trên:

Trang 20

1.2.4.3 Flag

Flag được sử dụng khi một task phải đồng bộ với nhiều sự kiện Mỗi sự kiện tương ứng với một flag Task đó có thể chờ một trong các sự kiện (OR các flag) hay chờ tất cả các sự kiện (AND các flag) Khi một/các sự kiện chưa xảy ra (flag ở trạng thái not ready) thì task vẫn chưa được định thời

CoOS hiện thực hai loại flag: reset tự động và reset bằng tay Để phân biệt hai loại flag này, xét 3 task A, B, C cùng chờ một flag I Nếu I reset tự động, khi I ready, task A được đưa vào ready list, sau đó hệ thống tự động đưa I về trạng thái not-ready và B, C vẫn ở trạng thái waiting

Nếu I reset bằng tay, khi I ready, các task A, B, C sẽ được đưa vào ready list Bạn gọi CoClearFlag để đưa I về not-ready

Các API liên quan:

CoCreateFlag (): tạo flag.

CoWaitForSingleFlag (), CoWaitForMultipleFlag (): đợi 1 hay nhiều flag Hai đoạn code sau

minh họa các API nói trên:

Trang 22

1.2.5 Intertask Communication – Vấn đề giao tiếp giữa các task

1.2.5.1 Mailbox

Một mail message là một pointer trỏ tới thông tin cần giao tiếp, nhờ các service của hệ điều hành, được đặt vào một mailbox Các task khác có thể nhận mail này cũng nhờ core service.Mailbox do một task tạo ra, và do đó là sở hữu của một task Mailbox chỉ lưu được một mail tại một thời điểm Sơ đồ một mailbox:

Mailbox trong CoOS gồm hai phần: phần thông tin cần trao đổi được biểu thị bởi con trỏ void và phần waiting list gồm các task đang chờ mailbox List này có thể là FIFO hay

preemptive priority, được user quy định khi tạo mailbox

Các API liên quan: CoCreateMBox: tạo Mailbox, CoPostMail, isr_PostMail: dùng để gửi mail, CoPendMail, CoAcceptMai: dùng để nhận mail Đoạn code sau minh họa các API trên:

Trang 23

1.2.5.2 Message queue

Một Message queue là một mảng các mailbox, khác với mailbox chỉ lưu 1 mail, nó có thểlưu được nhiều mail, được xác định bởi user khi tạo queue Các tính chất và API của Message queue hoàn toàn tương tự Mailbox Đoạn code sau minh họa cách sử dụng Message queue:

Trang 24

1.3 Ứng dụng các API của CoOS

1.3.1 Các API liên quan đến OS

Trang 25

task: con trỏ hàm trỏ đến hàm tương ứng với task cần tạo.

argv: danh sách các tham số của hàm

prio: mức ưu tiên của task, prio càng nhỏ càng được ưu tiên

stk: địa chỉ bắt đầu của stack của task, mỗi phần tử của stack là 1 word (4 bytes)

stkSz: kích thước của stack của task, tính theo word (4 bytes)

Giá trị trả về:

Trang 26

Task ID nếu thành công, -1 nếu không tạo được task.

Trang 27

E_OK, Xóa thành công.

Ví dụ:

OS_TID TaskB_ID ;//khai báo biến để nhận ID của TaskB

void TaskB (void *pdata)

Chức năng:

Tạo một software timer

Tham số:

tmrType : Kiểu time, có thể là periodic hay one_shot (chỉ chạy một lần)

tmrCnt : giá trị khởi tạo cho biến đếm của timer

tmrReload: giá trị nạp trở lại cho biến đếm khi nó giảm xuống 0

func: con trỏ hàm, hàm được trỏ đến được gọi khi biến đếm bằng 0

Trang 28

OS_TCID tmrID);

E_INVALID_ID, nếu ID không hợp lệ

E_OK, nếu thành công

Ví dụ:

OS_TCID timer1;

void taskBMP (void* pdata) {

timer1 = CoCreateTmr (TMR_TYPE_PERIODIC, 10, 10, timer1Handler);

if (timer1 != E_CREATE_FAIL) LedOn (4);

if (CoStartTmr (timer1) == E_OK) LedOn (5);

… }

1.3.4 Các API liên quan đến Flag.

1.3.4.1 CoCreateFlag ()

Prototype:

OS_FlagID CoCreateFlag

( BOOL bAutoReset,BOOL bInitialState);

ID của flag nếu thành công

-1, nếu không thành công

Trang 29

E_INVALID_ID, nếu ID không hợp lệ.

E_OK, nếu thành công

U32 timeout);

Chức năng:

Chờ một flag

Tham số:

id: ID của flag cần chờ

timeout: thời gian timer, tính bằng tick Nếu timeout = 0 thì có nghĩa là chờ đến khi nào nhận được flag mới thôi

Giá trị trả về:

E_CALL, lỗi do gọi hàm trong ISR

E_INVALID_ID, nếu ID của flag không hợp lệ

E_TIMEOUT, nếu timeout

E_OK, nếu thành công

//chờ flag_1, timeout = 20 tick

//xử lý công việc ở đây sau khi đã nhận được flag_1

//do taskM bật lên

Trang 30

2 Phần 2 Các module hộ trợ cho việc phát triển ứng dụng trên CooCox

có 3 chuẩn dung lượng là: Standard-Capacity (SD - dung lượng lên tới 2GB), High-Capacity (SDHC - dung lượng từ 4-32GB) và Extended-Capacity (SDXC - dung lượng từ >32GB lên tới2TB) Trong đồ án này, thẻ nhớ microSD với dung lượng 1GB được sử dụng làm bộ nhớ thứ cấp cho VĐK LPC1766 Sau đây là một số điểm cần lưu ý về chuẩn SD, hỗ trợ cho việc thực hiện đồ án

2.1.1.2 Giao thức truyền dữ liệu

 Thẻ nhớ SD giao tiếp với bên ngoài theo mô hình master-slave, trong đó thẻ nhớ luôn đóng vai trò slave, nhận tín hiệu điều khiển, xung clock từ chip bên ngoài đóng vai tròhost Một host có thể giao tiếp với nhiều thẻ nhớ cùng lúc

 Các chuỗi bit nối tiếp được trao đổi qua lại giữa thẻ nhớ và host được định dạng thành một trong ba kiểu gói: command (từ host đến card), responde (từ card vào host) và data (theo cả hai hướng)

 Có 2 kiểu giao diện bus giữa host và card: SD Card Bus và SPI Bus SD CardBus dùng tới 4 chân Data, 1 chân Command và Responde để giao tiếp host, còn SPI Bus thì giao tiếp theo chuãn SPI, chỉ gồm 2 chân trao đổi tín hiệu Giao diện SPI Bus được sử dụng trong đồ án này và sẽ được nói rõ hơn trong phần sau

7 DAT0 I/O/PP Data bit 0

8 DAT1 I/O/PP Data bit 1

 SPI Bus:

Trang 31

Pin Name Type Description

1 CS I Chip Select (Neg True)

 Thanh ghi OCR (Operation Condition Register): chứa thông tin về các cấu hình điện áp của thẻ nhớ

 Thanh ghi CID (Card IDentification): chứa thông tin định danh thẻ

 Thanh ghi CSD (Card-Specific Data): cung cấp những thông tin liên quan đến việc truy xuất nội dung thẻ nhớ như: định dạng dữ liệu, kiểu sửa lỗi, thời gian truy xuất dữ liệu tối đa… Những thông tin về kích thước thẻ, kích thước sector, định dạng hệ thống file… cũng được rút ra từ việc truy xuất thanh ghi này, do đó đây là thanh ghi nên được tìm hiểu kỹ

Có 2 phiên bản về cấu trúc thanh ghi CSD ứng với 2 chuẩn dung lượng Standard- và Capacity Dưới đây là cấu trúc CSD theo phiên bản thứ nhất

Trang 32

High-Lưu ý: ta có thể tính được dung lượng của thẻ nhớ từ các trường C_SIZE, C_SIZE_MULT

và READ_BL_LEN theo công thức sau:

Dung lượng = BLOCKNR * BLOCK_LEN

Trong đó: BLOCKNR = (C_SIZE + 1) * MULT

MULT = 2C_SIZE_MULT + 2 (C_SIZE_MULT < 8)

BLOCK_LEN = 2READ_BL_LEN (READ_BL_LEN < 12)

 Thanh ghi RCA (Relative Card Address): mang địa chỉ thẻ nhớ khi ở chế độ SD Card Bus (thanh ghi này không sử dụng trong chế độ SPI Bus)

 Thanh ghi DSR (Driver Stage Register): đây là thanh ghi tùy chọn, dùng để nâng hiệu suất bus

Trang 33

 Thanh ghi SCR (SD Card Configuration Register): cung cấp thông tin về những tính năngđặc biệt của thẻ nhớ.

2.1.2 Module SPI trong LPC1766

2.1.2.1 Giới thiệu

Module SPI được sử dụng trong đồ án, đóng vai trò trao đổi dữ liệu cấp thấp (theo từng byte) giữa VĐK và thẻ nhớ SD Vì vậy, module SPI trong VĐK phải được cấu hình ở chế độ Master theo phương thức truyền 8 bit

2.1.2.2 Cấu hình căn bản khi sử dụng module SPI trong LPC1766

o Cấp nguồn: ghi bit PCSPI của thanh ghi PCONP (Chú ý: khi reset, bit PCSPI = 1)

o Cấp xung clock: ghi bit PCLK_SPI của thanh ghi PCLKSEL0 để cấp xung clock cho SPI

o Cấu hình chân chức năng: các chân SCK, SS, MISO và MOSI của SPI lần lượt trùng với các chân 15, 16, 17 và 18 của Port 0, do đó cần ghi các bit tương ứng trong các thanh ghi PINSEL0, PINSEL1 và FIO0DIR để thiết lập hướng và chức năng cho các chân trên

o Cấu hình ngắt: ngắt SPI được kích hoạt khi kích hoạt cờ ngắt SPI trong NVIC, đồng thời bit SPIF của thanh ghi S0SPINT được ghi lên 1

2.1.2.3 Hệ thống thanh ghi trong SPI:

Gồm 5 thanh ghi điều khiển và 1 thanh ghi trạng thái

o Thanh ghi S0SPCR (SPI Control Register): điều khiển chức năng của khối SPI

Trang 35

o Thanh ghi S0SPSR (SPI Status Register): giám sát trạng thái hoạt động của SPI, bao gồmchức năng thông thường và các điều kiện ngoại lệ.

o Thanh ghi S0SPDR (SPI Data Register): chứa các byte dữ liệu truyền đi và nhận về

o Thanh ghi S0SPCCR (SPI Clock Counter Register): điều khiển tốc độ xung clock khi ở chế độ master

Có thể tính tần số xung clock của SPI Master theo công thức sau:

SPI Clock Rate = SPI Peripheral Clock / S0SPCCR

 S0SPCCR là giá trị 8 bit Counter của thanh ghi S0SPCCR, giá trị này phải là số chẵn và lớn hơn 8 để bảo đảm hoạt động chính xác của SPI

Trang 36

 SPI Peripheral Clock được xác định theo giá trị PCLK_SPI của thanh ghi PCLKSEL0 (các bit 17:16), đó là: bằng CCLK/4 nếu PCLK_SPI = 00, bằng CCLK nếu PCLK_SPI = 01, bằng CCLK/2 nếu PCLK_SPI = 10 và bằng CCLK/8 nếu PCLK_SPI = 11 (CCLK là tần số xung clock của CPU)

o Thanh ghi S0SPINT (SPI Interrupt): chứa cờ ngắt của SPI

2.1.2.4 Hoạt động của module SPI ở chế độ Master

Khởi tạo: gồm các bước sau

 Các bước cấu hình cơ bản (xem phần trước)

 Thiết lập giá trị thanh ghi S0SPCCR để đạt được tần số xung clock mong muốn

 Thiết lập giá trị thanh ghi S0SPCR theo chế độ Master

Trao đổi dữ liệu: gồm các bước sau

 Ghi dữ liệu cần truyền đi vào thanh ghi dữ liệu S0SPDR (nếu không có dữliệu cần truyền thì có thể ghi 0xff), hành động này sẽ bắt đầu việc truyền dữ liệu ra bus

 Chờ đến khi bit SPIF của thanh ghi S0SPSR được tích cực

 Đọc thanh ghi trạng thái S0SPSR

 Đọc dữ liệu cần nhận từ thanh ghi S0SPDR (nếu không cần dữ liệu nhận thì phải xóa bit SPIF của thanh ghi S0SPSR để kết thúc việc trao đổi dữ liệu)

Trong thời gian trao đổi dữ liệu, chân CS của SPI phải luôn được tích cực

2.1.3 Giao tiếp SPI giữa SD Card và LPC1766

2.1.3.1 Cấu hình kênh giao tiếp SPI

o Đối với LPC1766: kích hoạt module SPI theo chế độ Master, truyền 8 bit

o Đối với thẻ nhớ SD: thẻ nhớ phải được chuyển sang chế độ giao diện SPI Bus

2.1.3.2 Cách thức trao đổi dữ liệu trên kênh SPI

o Kênh SPI là "byte-oriented", nghĩa là tất cả các thông tin được trao đổi trên kênh đều phải có độ dài là một số nguyên byte (trong khi đó, thông tin ở chế độ SD Card là tính theo từng bit), như vậy sẽ phù hợp với chế độ giao tiếp SPI 8 bit của VĐK Thông tin được truyền lên kênh SPI theo thứ tự từ MSB

o Tất cả hoạt động trao đỗi thông tin trên kênh SPI đều được điều khiển bởi Host (trong trường hợp này là LPC1766) Host bắt đầu mỗi giao dịch bus bằng việc tích cực tín hiệu

CS (Chip Select)

Trang 37

o Thẻ nhớ (đóng vai trò Slave) sẽ lấy mẫu thông tin trên kênh SPI khi tín hiệu CS được tích cực, do đó thời gian tích cực của CS phải là bội số của 8 xung clock SPI để đảm bảo thông tin được lấy mẫu chính xác.

o Thông tin trên kênh SPI được chia thành 4 loại:

 Command Token: được gửi bởi Host tới thẻ nhớ, mỗi Command là một yêu cầu tới thẻ nhớ, yêu cầu đó có thể là: ghi thẻ, đọc thẻ, đọc thanh ghi …

 Responde Token: luôn được gửi bởi thẻ nhớ ngay sau khi nhận Command

từ Host Có các loại định dạng Responde khác nhau tùy theo Command nhận được

 Data Block: khối dữ liệu cần được trao đổi, có thể là dữ liệu đọc từ thẻ nhớ, dữ liệu ghi vào thẻ nhớ hay nội dung một thanh ghi trong thẻ nhớ…

 Control Token: điều khiển việc trao đổi Data Block

o Quá trình giao tiếp giữa Host và thẻ nhớ luôn luôn diễn ra và lặp lại theo các bướcsau:

 Host gửi một Command Token tới thẻ nhớ

 Thẻ nhớ phản hồi Command trên bằng cách gửi lại một Responde Token tương ứng

 Trong trường hợp Command có yêu cầu đọc hay ghi dữ liệu, các Data Block và Control Token sẽ được gửi đi, từ thẻ nhớ hay từ Host tuy theo yêu cầu Lưu ý làData Block chỉ được di chuyển trên kênh SPI theo một hướng: từ Host tới thẻ nhớ nếu có yêu cầu ghi dữ liệu và hướng ngược lại nếu có yêu cầu đọc dữ liệu

 Trường argument: các tham số cần thiết của yêu cầu

 Trường CRC7: kiểm tra lỗi theo công thức x7+x3+1

Một số Command nên biết:

 CMD0: reset thẻ nhớ, đưa thẻ nhớ về trạng thái Idle

 CMD1: kích hoạt quá trình khởi tạo của thẻ nhớ

 CMD9: đọc thanh ghi CSD

 CMD10: đọc thanh ghi CID

 CMD12: dừng hoạt động đọc nhiều Data Block

 CMD17/CMD18: đọc một/nhiều Data Block, trường argument chứa địa chỉ Data Block

 CMD24/CMD25: ghi một/nhiều Data Block, trường argument chứa địa chỉ Data Block

 CMD55: đây là Command đặc biệt, khi gặp Command này, thẻ nhớ sẽ phải chờ để nhận thêm một Command Token nữa (cùng định dạng nhưng khác loại với các Command trên, gọi là

"Application Specific Command" - ký hiệu ACMDx) mới biết được yêu cầu của Host là gì

b) Responde Token:

Trang 38

Tùy theo Command Token, có các loại định dạng Responde Token tương ứng, đó là: R1, R2, R3, R4, R5 và R7 Định dạng R1 được sử dụng nhiều nhất, các Command được liệt kê ở trên đều được phản hồi bằng Responde R1 Định dạng R1 như sau (MSB được gửi đi đầu tiên)

MSB luôn bằng 0, các bit khác dùng để báo lỗi, bằng 0 nghĩa là không có lỗi Ý nghĩa các lỗi là:

 In idle state: thẻ nhớ đang ở trạng thái idle và đang khởi tạo

 Erase reset: chuỗi lệnh xóa không đúng thứ tự

 Illegal command: mã lệnh không hợp lệ

 Com CRC error: CRC không khớp

 Erase sequence error: lỗi xảy ra trong chuỗi lệnh xóa

 Address error: địa chỉ Data Block không trùng khớp với độ dài của nó

 Parameter error: tham số không hợp lệ

c) Data Block:

Một Data Block luôn có 16 bit CRC (tính theo công thức x16+x12+x5+1) đi kèm theo sau Chiều dài mỗi Data Block (không kể 2 byte CRC) biến thiên từ 1 đến 512 byte, mặc định là 512 byte

là 0xFE trong các trường hợp khác

 Stop Tran Token: trong trường hợp ghi nhiều Data Block (bằng CMD25), thẻ nhớ được quyền yêu cầu dừng ghi bằng cách gửi Stop Tran Token đến Host Token này luôn có giá trị là 0xFD

 Data Error Token: nếu hoạt động đọc bị lỗi và thẻ nhớ không thể cung cấp dữ liệu cần đọc, thay vào đó nó sẽ gửi đi một Data Error Token, có định dạng là:

Trang 39

4 bit cuối chỉ ra lỗi gặp phải trong hoạt đông đọc: Error - lỗi tổng quát hoặc lỗi lạ; CC Error

- lỗi bộ điều khiển trong của thẻ nhớ; Card ECC Failed - không sữa lỗi được; Out of range - địachỉ không hợp lệ

2.1.3.4 Một số hoạt động diễn ra trên kênh SPI

Quá trình khởi tạo chế độ SPI Bus cho thẻ nhớ

 Host gửi CMD0 trong khi tín hiệu CS được tích cực, đây là điều kiện để thẻ nhớ chuyển sang chế độ SPI Bus, đồng thời cũng chính là yêu cầu reset thẻ nhớ

 Sau khi gửi CMD0, host nhận R1 Nếu R1 khác 0x01 (bit In Idle State chưa tích cực), tức là thẻ nhớ vẫn chưa trở về trạng thái Idle, Host sẽ gửi lại CMD0 (và nhận R1) nhiều lần cho đến khi trạng thái Idle xuất hiện (R1 = 0x01)

 Host gửi CMD1 để kích hoạt quá trình khởi tạo thẻ nhớ, gửi CMD1 và nhận R1 nhiều lần cho đến khi R1 khác 0x01 thì dừng (vì lúc này bit In Idle State của R1 khôngtích cực, chứng tỏ thẻ nhớ đã khởi tạo xong)

Đọc dữ liệu từ thẻ nhớ

Trường hợp đọc một Data Block

 Host gửi CMD17 với argument là địa chỉ của dữ liệu cần đọc, sau đó nhận R1 = 0

 Thẻ nhớ gửi Start Block Token (0xFE)

 Thẻ nhớ gửi Data Block được yêu cầu (thường là 512 byte cùng với 2 byte CRC16)Trường hợp đọc nhiều Data Block

 Host gửi CMD18 với argument là đỉa chỉ dữ liệu, sau đó nhận R1 = 0

 Thẻ nhớ gửi Start Block Token cùng với Data Block nhiều lần Các Data Block này nằm

ở những vị trí liên tiếp nhau trên thẻ nhớ mà bắt đầu là vị trí được chỉ định bởi argument của CMD18

 Host chủ động dừng việc nhận Data Block từ thẻ nhớ bằng cách gửi CMD12 và nhận R1

Đọc các thanh ghi: Trình tự giống với trường hợp đọc một Data Block ngoại trừ: thay

CMD17 bằng CMD9 (đọc CSD) hoặc CMD10 (đọc CID) và Data Block là nội dung của thanh ghi tương ứng.

2.2 Cấu trúc dữ liệu và hệ thống tập tin FAT

2.2.1 Cấu trúc vùng dữ liệu của thẻ nhớ

Vùng dữ liệu của thẻ nhớ là vùng có thể được đọc hoặc ghi bởi Host Dữ liệu trong vùng nàyđược đánh địa chỉ theo byte (bắt đầu từ 0) nhưng thường được truy xuất theo từng khối byte gọi

là sector Kích thước mỗi sector là 512 byte

Có thể chia vùng dữ liệu thành 2 khu vực: Partition Area và Regular Area

0 446 Master Boot Record Not Restricted

446 16 Partition Table (partition 1) Xem bảng dưới

462 16 Partition Table (partition 2) All 0x00

478 16 Partition Table (partition 3) All 0x00

494 16 Partition Table (partition 4) All 0x00

Trang 40

Signature Word: gồm 2 byte 0x55 và 0xaa, dùng để xác định tính hợp lệ của Partiton AreaBốn Partition Table tương ứng với (tối đa) 4 phân vùng, tuy nhiên, mỗi thẻ nhớ thường chỉ gồm một phân vùng duy nhất nên chỉ cần thông tin của Partition Table đầu tiên, 3 Partiton Table còn lại có thể gán giá trị bằng 0x00 cho tất cả các byte.

Cấu trúc của Parttion Table như sau:

2 2 Starting Sector/ Starting Cylinder Numeric Value

6 2 Ending Sector/ Ending Cylinder Numeric Value

 Boot Indicator (byte 0): bằng 0x80 nếu thẻ nhớ được sử dụng để khởi động máy, hoặc bằng 0x00 nếu ngược lại

 Relative Sector (byte 8, 9, 10 và 11): số lượng sector nằm trước sector đầutiên của phân vùng, dựa vào thông số này để xác định địa chỉ sector đầu tiên của phân vùng

 Total Sector (byte 12, 13, 14, 15): tổng số lượng sector của phân vùng

 System ID (byte 4): kiểu hệ thống file trong phân vùng

Ngoài Sector 0, các sector còn lại (nếu có) của Partition Area không có ý nghĩa nên không cần xem xét

2.2.1.2 Regular Area

Là phân vùng duy nhất của thẻ nhớ, vị trí của Regular Area hoàn toàn có thể xác định nhờ vào thông số Relative Sector của Partition Table ở phần trên Hệ thống file thường được sử dụng trong phân vùng thẻ nhớ là FAT (chủ yếu là FAT16), chi tiết về FAT sẽ được trình bày rõ ở phầnsau

2.2.2 Hệ thống tập tin FAT

2.2.2.1 Cấu trúc tổng quan

Một hệ thống tập tin FAT được cấu tạo bởi các miền sau

o Miền Reserved Sectors: phần đầu tiên của phân vùng Sector 0 của miền này - gọi là BootSector - là một sector quan trọng của hệ thống, nó chứa những thông số về phân vùng FAT, cònsector 1 (nếu có) chứa những thông tin của phân vùng FAT32

Ngày đăng: 19/12/2014, 13:29

TỪ KHÓA LIÊN QUAN

TRÍCH ĐOẠN

TÀI LIỆU CÙNG NGƯỜI DÙNG

TÀI LIỆU LIÊN QUAN

w