Làm thế nào để địa chỉ I / O ánh xạ bộ nhớ hoạt động?


29

Làm thế nào để địa chỉ I / O ánh xạ bộ nhớ hoạt động?

Tôi đang cố gắng để hiểu một mẫu được cung cấp I2S: Bất cứ ai cũng có nó chạy? .

Cấu hình Đồng hồ:

#define BCM2708_PERI_BASE        0x20000000
#define CLOCK_BASE               (BCM2708_PERI_BASE + 0x101000) /* Clocks */

Đầu tiên, nó ánh xạ mã như vậy ...

clk_map = (unsigned char *)mmap(
      (caddr_t)clk_mem,
      MAP_BLOCK_SIZE,
      PROT_READ|PROT_WRITE,
      MAP_SHARED|MAP_FIXED,
      mem_fd,
      CLOCK_BASE
   );

Sau đó, nó làm một cái gì đó ...

 // Always use volatile pointer!
   clk = (volatile unsigned *)clk_map;

Và khi nó được tham chiếu có những phần bổ sung kỳ lạ 0x26 & 0x27, thì sao?

 printf("Disabling I2S clock\n");
 *(clk+0x26) = 0x5A000000;
 *(clk+0x27) = 0x5A000000;

 usleep(10);

 printf("Confiure I2S clock\n");
 *(clk+0x26) = 0x5A000001;
 *(clk+0x27) = 0x5A000000 | 3<<12 | 1<<9; // divider: 3.125==0b11.001

 usleep(10);
 printf("Enabling I2S clock\n");
 *(clk+0x26) = 0x5A000011;

Nhìn vào biểu dữ liệu, tôi có thể thấy nơi họ đã nhận được một số giá trị này, như địa chỉ cơ sở, nhưng tôi đang đấu tranh để hiểu những cái khác. Điều đó được CLOCK_BASExác định ở đâu và những gì đang xảy ra?


1
Điều này có lẽ phù hợp nhất với StackOverflow. Mặc dù nó liên quan đến RPi Bạn sẽ có nhiều khả năng nhận được câu trả lời cho các câu hỏi lập trình ở đó.
Jivings

4
Có thể, nhưng tôi cảm thấy đó là một câu hỏi liên quan đến lập trình Pi chung hơn kết hợp việc giải thích biểu dữ liệu và phần cứng Pi. để xem nếu nó nhận được một số thông tin tốt.
Tai chó

Đuợc. Chúng ta hãy xem mọi thứ diễn ra như thế nào :)
Jivings

1
Tôi không nghĩ rằng điều này sẽ làm quá tốt trên Stack Overflow - nó khá chuyên nghiệp và có thể sẽ được nhiều chuyên gia chú ý hơn ở đây.
Flexo

Câu trả lời:


18

Trên máy tính, bạn ghi vào một 'địa chỉ bộ nhớ' được chỉ định. Địa chỉ này được hệ thống nhận ra là địa chỉ phần cứng và phần cứng phù hợp nhận hoặc gửi giá trị phù hợp.

Hầu hết các hệ thống phần cứng có nhiều thanh ghi khác nhau có thể được đặt hoặc đọc. Một số có thể có một vài, một số có thể có nhiều. Những thanh ghi này sẽ được nhóm thành một phạm vi liên tục. Một con trỏ cơ sở trỏ đến cái đầu tiên trong phạm vi và bạn viết vào, ví dụ, cổng thứ hai có base_pulum + 1. Bạn không cần phải có, bạn có thể viết trực tiếp vào một con trỏ, nhưng sử dụng phần bù giúp mọi thứ dễ dàng hơn để làm việc.

Raspberry Pi nhận ra một loạt các thanh ghi phần cứng khổng lồ tại địa chỉ 0x20000000. Một loạt các thanh ghi điều khiển các hệ thống đồng hồ được truy cập từ BCM2708_PERI_BASE + 0x101000. Các thanh ghi điều khiển đồng hồ I2S là thanh ghi thứ 38 và 39 trong khối đó, được viết bằng BCM2708_PERI_BASE + 0x101000 + 0x26 và 0x27

Bạn không thể thay đổi các giá trị đồng hồ, bạn phải vô hiệu hóa đồng hồ, thay đổi các giá trị và khởi động lại nó.

Nếu câu trả lời này quá cơ bản, tôi xin lỗi. Trong trường hợp câu hỏi của bạn là thực sự khó khăn, chúc may mắn. Bạn có thể thấy liên kết này hữu ích

Cập nhật: Tại sao sử dụng mmap và không ghi trực tiếp vào bộ nhớ?

Khi một chương trình đang chạy các địa chỉ bộ nhớ, nó nghĩ rằng nó không có địa chỉ thực, chúng được ánh xạ tới các địa chỉ thực bởi trình quản lý bộ nhớ. Điều này ngăn một chương trình có thể ảnh hưởng đến chương trình khác. Hai quá trình có thể đọc và ghi vào địa chỉ riêng 1234 của họ một cách hoàn toàn hạnh phúc và trình quản lý bộ nhớ sẽ giữ hai vị trí hoàn toàn tách biệt.

Cổng phần cứng, tuy nhiên, là tại địa chỉ vật lý tuyệt đối. Nhưng bạn không thể viết thư cho họ trực tiếp vì trình quản lý bộ nhớ sẽ lấy địa chỉ của bạn và ánh xạ nó tới vùng nhớ cá nhân của bạn.

Trên Linux / dev / mem là ' tệp thiết bị ký tự là hình ảnh của bộ nhớ chính của máy tính '

Nếu bạn mở nó như một tập tin thì bạn có thể đọc và ghi vào nó như một tập tin. Trong mẫu được cung cấp mem_fd là một tệp xử lý kết quả từ việc mở / dev / mem

Một hệ thống khác có thể làm cho cuộc sống dễ dàng hơn nhiều là khả năng ánh xạ một tệp vào bộ nhớ và ghi vào nó như bộ nhớ. Vì vậy, nếu bạn có một tệp mà bạn muốn đọc hoặc ghi các bit cụ thể khác nhau thì thay vì di chuyển con trỏ tệp về phía trước và về phía trước, bạn có thể ánh xạ nó đến một vị trí trong bộ nhớ, sau đó ghi trực tiếp vào đó như là bộ nhớ.

Vì vậy, trong mẫu này, mã đang tạo một tay cầm cho bộ nhớ vật lý, như thể nó là một tệp trên đĩa, và sau đó yêu cầu hệ thống xử lý nó như thể nó là bộ nhớ. Một chút phức tạp, nhưng cần thiết để có được trình quản lý bộ nhớ ảo và ghi vào một địa chỉ vật lý thực tế. Giá trị 0x20000000, dường như, là một chút cá trích đỏ. Mã đang đề xuất địa chỉ này như một gợi ý, hệ thống không phải ánh xạ / dev / mem ở đây, mặc dù có lẽ nó có. Thông thường giá trị null sẽ được thông qua và hệ thống sẽ ánh xạ xử lý tệp tới bất kỳ địa chỉ nào nó nghĩ tốt nhất.

Bây giờ bộ nhớ vật lý được ánh xạ tới bộ nhớ ảo xử lý, và đọc và ghi đi đến nơi bạn mong đợi.

Tài liệu tham khảo:

http://www.kernel.org/doc/man-pages/online/pages/man2/mmap.2.html

http://www.raspberrypi.org/phpBB3/viewtopic.php?f=44&t=8496&p=104359

https://superuser.com/questions/71389/what-is-dev-mem


Tôi vẫn còn một vài câu hỏi: Tại sao họ mmap? Tại sao không chỉ truy cập bộ nhớ trực tiếp?
Alex Chamberlain

@AlexChamberlain Vì mã chạy trên linux, vì vậy bạn không thể truy cập bộ nhớ trực tiếp vì mỗi tiến trình có không gian bộ nhớ ảo của riêng chúng. Tuy nhiên, người ta có thể mở và mmap / dev / mem để có quyền truy cập trực tiếp vào bộ nhớ vật lý
số

1

@AlexChamberlain điều này là do cấu trúc hệ điều hành. Bạn có thể đi mà không có mmapnhưng phân trang được khai báo, do đó không có quyền truy cập trực tiếp. Trong chế độ kernel, bạn có thể đi mà không cần mmap, ví dụ, chèn trình điều khiển của bạn làm mô-đun kernel mà không cần mmap. Ngoài ra, trong trường hợp hệ điều hành đơn giản nhất, trong đó không có bộ nhớ bảng trang nào được sử dụng, bạn có thể truy cập mà không cần mmap, tức là. truy cập địa chỉ vật lý trực tiếp.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.