Como funciona o endereçamento de E / S mapeado pela memória?
Estou tentando entender um exemplo fornecido I2S: Alguém conseguiu rodar? .
Configurando relógios:
#define BCM2708_PERI_BASE 0x20000000
#define CLOCK_BASE (BCM2708_PERI_BASE + 0x101000) /* Clocks */
Primeiro mapeia o código da seguinte maneira ...
clk_map = (unsigned char *)mmap(
(caddr_t)clk_mem,
MAP_BLOCK_SIZE,
PROT_READ|PROT_WRITE,
MAP_SHARED|MAP_FIXED,
mem_fd,
CLOCK_BASE
);
Então faz alguma coisa ...
// Always use volatile pointer!
clk = (volatile unsigned *)clk_map;
E quando é referenciada, existem esses acréscimos ímpares de 0x26 e 0x27, o que é isso?
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;
Olhando para a folha de dados, posso ver onde eles obtiveram alguns desses valores, como o endereço base, mas estou lutando para entender os outros. Onde isso é CLOCK_BASE
determinado e o que está acontecendo?
Respostas:
Em um computador, você grava em um 'endereço de memória' especificado. Este endereço é reconhecido pelo sistema como um endereço de hardware e o hardware apropriado recebe ou envia o valor apropriado.
A maioria dos sistemas de hardware possui muitos registros diferentes que podem ser configurados ou lidos. Alguns podem ter alguns, alguns podem ter muitos. Esses registros serão agrupados em uma faixa contínua. Um ponteiro base aponta para o primeiro no intervalo e você grava, por exemplo, a segunda porta com base_pointer + 1. Você não precisa, pode escrever diretamente para um ponteiro, mas usar um deslocamento facilita o trabalho das coisas.
O Raspberry Pi reconhece uma enorme variedade de registros de hardware no endereço 0x20000000. Uma variedade de registradores que controlam sistemas de relógio são acessados a partir de BCM2708_PERI_BASE + 0x101000. Os registradores que controlam o relógio I2S são os registradores 38 e 39 desse bloco, gravados usando BCM2708_PERI_BASE + 0x101000 + 0x26 e 0x27
Você não pode simplesmente alterar os valores do relógio, porém, você deve desativar o relógio, alterar os valores e reiniciá-lo.
Se esta resposta é muito básica, minhas desculpas. Nesse caso, sua pergunta é realmente grave, boa sorte. Você pode achar este link útil
Atualização: Por que usar o mmap e não gravar diretamente na memória?
Quando um programa está executando os endereços de memória que acha que não são endereços reais, eles são mapeados para endereços reais pelo gerenciador de memória. Isso impede que um programa possa afetar outro. Dois processos podem ler e gravar em seu próprio endereço 1234 perfeitamente felizes, e o gerenciador de memória manterá os dois locais completamente separados.
As portas de hardware, no entanto, estão em endereços físicos absolutos. Mas você não pode escrever diretamente para eles, porque o gerenciador de memória pega seu endereço e o mapeia para sua área de memória pessoal.
No Linux / dev / mem, há um ' arquivo de dispositivo de caractere que é uma imagem da memória principal do computador '
Se você abrir isso como um arquivo, poderá ler e gravar nele como um arquivo. No exemplo fornecido, mem_fd é um identificador de arquivo resultante da abertura de / dev / mem
Outro sistema que pode facilitar muito a vida é a capacidade de mapear um arquivo na memória e gravá-lo como memória. Portanto, se você possui um arquivo no qual deseja ler ou gravar diferentes bits específicos, em vez de mover o ponteiro do arquivo para trás e para frente, é possível mapeá-lo para um local na memória e gravá-lo diretamente como se fosse memória.
Portanto, neste exemplo, o código está criando um identificador para a memória física, como se fosse um arquivo em disco, e depois pedindo ao sistema para tratá-lo como se fosse memória. Um pouco complicado, mas necessário para contornar o gerenciador de memória virtual e gravar em um endereço físico real. O valor 0x20000000, ao que parece, é um pouco de um arenque vermelho. O código está propondo esse endereço como uma dica, o sistema não precisa mapear / dev / mem aqui, embora provavelmente o faça. Normalmente, o valor nulo seria passado e o sistema mapearia o identificador do arquivo para qualquer endereço que considerasse melhor.
Agora a memória física é mapeada para a memória virtual dos processos, e as leituras e gravações vão para onde você espera.
Referências:
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
fonte
@AlexChamberlain, isso se deve à estrutura do sistema operacional. Você pode ficar sem,
mmap
mas a paginação é declarada, portanto, nenhum acesso direto. No modo kernel, você pode ficar semmmap
, por exemplo, inserir seu driver como módulo do kernel sem necessidademmap
. Além disso, no caso mais simples do sistema operacional, em que nenhuma memória da tabela de páginas é usada, você pode acessar semmmap
, por exemplo. acesso direto ao endereço físico.fonte