메모리 매핑 된 I / O 주소 지정은 어떻게 작동합니까?


29

메모리 매핑 된 I / O 주소 지정은 어떻게 작동합니까?

샘플로 제공되는 I2S 를 이해하려고합니다 . 누구나 실행 중입니까? .

시계 구성 :

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

먼저 코드를 이렇게 매핑합니다 ...

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

그런 다음 뭔가를합니다 ...

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

그리고 그것을 참조 할 때 0x26 & 0x27의 이상한 추가가 있습니다.

 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;

데이터 시트를 보면 기본 주소와 같이 이러한 값 중 일부가 어디에 있는지 확인할 수 있지만 다른 값을 이해하기 위해 고심하고 있습니다. 그것이 어디에서 CLOCK_BASE결정되고 무엇이 진행되고 있습니까?


1
이것은 아마도 StackOverflow에 가장 적합합니다. RPi와 관련이 있지만 프로그래밍 질문에 대한 답변을 얻을 수 있습니다.
Jivings

4
어쩌면 데이터 시트와 Pi 하드웨어의 해석을 결합한 일반적인 Pi 프로그래밍 관련 질문이라고 생각합니다. 좋은 정보가 있는지 확인하십시오.
강아지 귀

괜찮아. 어떻게되는지 보자 :)
Jivings

1
나는 이것이 스택 오버플로에서 너무 잘 될 것이라고 생각하지 않습니다. 그것은 꽤 전문가이며 여기에서 더 많은 전문가의 관심을 끌 것입니다.
Flexo

답변:


18

컴퓨터에서는 지정된 '메모리 주소'에 씁니다. 이 주소는 시스템에서 하드웨어 주소로 인식하고 적절한 하드웨어가 적절한 값을 받거나 보냅니다.

대부분의 하드웨어 시스템에는 설정하거나 읽을 수있는 다양한 레지스터가 있습니다. 일부는 몇 개가 있고, 일부는 몇 개가있을 수 있습니다. 이 레지스터는 연속 범위로 그룹화됩니다. 기본 포인터는 범위의 첫 번째 포인터를 가리키고 예를 들어 base_pointer + 1이있는 두 번째 포트에 씁니다. 포인터에 직접 쓸 수는 있지만 오프셋을 사용하면 작업하기가 더 쉬워집니다.

Raspberry Pi는 주소 0x20000000에서 광범위한 하드웨어 레지스터를 인식합니다. 클록 시스템을 제어하는 ​​레지스터 범위는 BCM2708_PERI_BASE + 0x101000에서 액세스합니다. I2S 클록을 제어하는 ​​레지스터는 해당 블록의 38 번째 및 39 번째 레지스터이며 BCM2708_PERI_BASE + 0x101000 + 0x26 및 0x27을 사용하여 기록됩니다.

시계 값만 변경할 수는 없습니다. 시계를 비활성화하고 값을 변경 한 후 다시 시작해야합니다.

이 답변이 너무 기본적이라면 사과드립니다. 어떤 경우에 귀하의 질문은 정말 하드, 행운입니다. 이 링크가 도움 될 수 있습니다

업데이트 : mmap을 사용하고 메모리에 직접 쓰지 않는 이유는 무엇입니까?

프로그램이 메모리 주소를 실행할 때 프로그램이 실제 주소가 아니라고 생각하면 메모리 관리자에 의해 실제 주소에 매핑됩니다. 한 프로그램이 다른 프로그램에 영향을 줄 수 없습니다. 두 개의 프로세스가 자신의 주소 1234를 완벽하게 읽고 쓸 수 있으며 메모리 관리자는 두 위치를 완전히 분리하여 유지합니다.

그러나 하드웨어 포트는 절대 물리적 주소에 있습니다. 그러나 메모리 관리자가 주소를 가져와 개인 메모리 영역에 매핑하기 때문에 직접 쓸 수는 없습니다.

Linux에서 / dev / mem은 ' 컴퓨터의 주 메모리 이미지 인 문자 장치 파일 '입니다.

이것을 파일처럼 열면 파일처럼 읽고 쓸 수 있습니다. 제공된 샘플에서 mem_fd는 / dev / mem을 연 결과로 생성 된 파일 핸들입니다.

인생을 훨씬 쉽게 할 수있는 또 다른 시스템은 파일을 메모리에 매핑하고 메모리처럼 쓸 수있는 기능입니다. 따라서 다른 특정 비트를 읽거나 쓰려는 파일이있는 경우 파일 포인터를 앞뒤로 이동하는 대신 메모리의 위치에 매핑 한 다음 메모리 인 것처럼 직접 쓸 수 있습니다.

따라서이 샘플에서는 코드가 마치 디스크의 파일 인 것처럼 실제 메모리에 대한 핸들을 만든 다음 시스템을 메모리 인 것처럼 처리하도록 요청합니다. 약간 복잡하지만 가상 메모리 관리자를 처리하고 실제 물리적 주소에 쓰려면 필요합니다. 0x20000000 값은 약간의 청어입니다. 코드는이 주소를 힌트로 제안하고 있지만 시스템은 / dev / mem을 여기에 매핑 할 필요는 없지만 아마도 그렇게합니다. 일반적으로 null 값이 전달되고 시스템은 파일 핸들을 가장 적합한 주소로 매핑합니다.

이제 실제 메모리가 프로세스 가상 메모리에 매핑되고 원하는 위치에서 읽고 쓸 수 있습니다.

참고 문헌 :

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


여전히 몇 가지 질문이 있습니다. 왜 그런가요? 왜 메모리에 직접 액세스하지 않습니까?
Alex Chamberlain

@AlexChamberlain 코드는 Linux에서 실행되므로 각 프로세스가 자체 가상 메모리 공간을 확보하면 메모리에 직접 액세스 할 수 없습니다. 그러나 물리적 메모리에 직접 액세스하기 위해 mmap / dev / mem을 열고 열 수 있습니다.
Nos

1

@AlexChamberlain 이것은 OS 구조 때문입니다. 당신은없이 갈 수 mmap있지만 페이징이 선언되므로 직접 액세스 할 수 없습니다. 커널 모드에서는 mmap예를 들어 드라이버를 커널 모듈로 삽입하지 않아도됩니다 mmap. 또한, 페이지 테이블 메모리가 사용되지 않는 가장 간단한 OS의 경우, mmap예 를 들어 어느 쪽도 없이 액세스 할 수 있습니다 . 직접적인 물리적 주소 접근.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.