Salvando dados do módulo do kernel no userspace

4

então eu tenho jogado em torno da programação do kernel por um tempo e quero criar essa simples interface de aquisição de dados com algum hardware customizado. Para portabilidade e reutilização, faço a coisa toda no meu Raspberry Pi.

A parte desafiadora do projeto é ter um ADC de alta velocidade (paralelo) conectado a GPIOs e ter um módulo de kernel que usa interrupção de hardware do ADC para adquirir cada amostra e armazená-la dentro de um buffer que é acessível via chardevice.

Minha configuração atual (que funciona) é a seguinte:

  • Eu tenho um programa C do userspace que está controlando meu hardware por meio do SPI. Se eu enviar um comando necessário, ele começará a adquirir dados analógicos e os enviará ao ADC.
  • Sempre que o ADC termina a conversão, ele envia um sinal correspondente para 'baixo' em um GPIO e eu recebo uma interrupção dentro do módulo do kernel (ligado a esse GPIO). O ISR coleta o valor de 12 outros GPIOs (é um ADC de 12 bits) e os coloca em um buffer que é acessado por meio do / dev / mydevice.
  • Eu tenho outro programa userspace separado que executa um loop while sem fim, lendo de / dev / mydevice e, por sua vez, grava em 'out_data.dat' (um arquivo userspace).
  • Com essa configuração crua (2 programas de espaço de usuário e módulo do kernel carregados), posso gravar mais de 130.000 amostras em meu arquivo por segundo (sem perder nada).

Agora quero ver quanto mais rápido posso conseguir, há duas coisas a serem consideradas:

  1. Eu sou um iniciante em programação do kernel, a configuração que descrevi acima do modo "usual" é como algo assim seria feito? Eu li em todos os lugares que a entrada / saída direta de arquivos não é aconselhada a partir do kernel, portanto, não estou fazendo isso. Certamente, porém, deve ser possível escrevê-lo em algum local "permanente" durante o ISR. Isso me parece um problema comum, tentando obter dados de algum hardware para o computador usando interrupções.

  2. Sem alterar minha configuração acima, existe alguma maneira de desativar outras interrupções para torná-la o mais suave possível? Durante a aquisição de dados, eu realmente não preciso de nada, apenas uma maneira de pará-lo. Quaisquer outras interrupções (sem fio, atualização de monitor, etc ...) podem ser desativadas, pois a aquisição de dados deve ser executada apenas por alguns minutos. Depois disso, tudo será retomado e o código Python, mais exigente, poderá ser executado para analisar e visualizar os dados (pelo menos, essa é minha visão simples disso).

por Amudsen 11.05.2018 / 20:44

1 resposta

2

Para o programa de coleta de dados do espaço do usuário, o que há de errado com um loop infinito? Contanto que você esteja usando a chamada de sistema poll , ela deve ser eficiente: link ?

Armazenamento permanente de dados

Não sei qual é a melhor maneira de fazer isso, por que você não escreve apenas em um arquivo da userland na enquete? Eu suponho que sua preocupação é que, se muitos dados chegarem, os dados serão perdidos, é isso?

Mas duvido que o fator limitante seja o kernel da comunicação do usuário no caso, mas a lentidão do dispositivo de armazenamento permanente, portanto, fazê-lo na userland não fará nenhuma diferença, eu acho. Em qualquer caso, a única solução do kernel tem uma questão de alto nível em: link e não acho que você terá uma solução melhor aqui.

Desativar interrupções

Você tem certeza de que isso faria alguma diferença, especialmente considerando que o gargalo provavelmente será? Eu esperaria que se o seu dispositivo estivesse realmente produzindo um grande número de interrupções, então elas dominariam qualquer outra interrupção em qualquer caso. Vale a pena arriscar bagunçar o estado de outro hardware? As especificações do seu dispositivo de hardware sugerem que ele poderia fornecer fisicamente uma largura de banda de dados muito maior do que a que você tem atualmente?

Eu não sei como fazer isso sozinho, mas se você quiser uma resposta, sua melhor aposta é fazer uma pergunta separada com o título "Como desabilitar todas as interrupções de um módulo do kernel do Linux?". O LDD2 menciona a função cli() link , mas parece que foi preterido: link Esse texto sugere local_irq_disable e local_irq_save .

Eu também tentaria hack-lo com qualquer método que você encontrasse para desabilitar as interrupções, e ver se fica mais eficiente antes de procurar mais se um método legal existir.

Em um emulador, um rápido:

static int myinit(void)
{
    pr_info("hello init\n");
    unsigned long flags;
    local_irq_save(flags);
    return 0;
}

falha com:

returned with disabled interrupts

aparentemente vindo de v4.16 do_one_initcall , então há um erro especializado para lidar com isso!

Eu então tentei ingenuamente fazer isso a partir de um thread de trabalho:

static int work_func(void *data)
{
    unsigned long flags;
    local_irq_save(flags);
    return 0;
}

static int myinit(void)
{
    kthread = kthread_create(work_func, NULL, "mykthread");
    wake_up_process(kthread);
    return 0;
}

mas ainda assim não consigo observar nenhum efeito, então as interrupções devem estar sendo ativadas por alguma outra coisa, como pode ser inferido de:

watch -n 1 grep i8042 /proc/interrupts

que continua atualizando tty ou muse / interrupções de teclado.

O mesmo de outros pontos de entrada, como fops, ou se eu tentar um asm("cli") bruto. Vamos precisar de uma abordagem mais educada.

    
por 12.05.2018 / 02:47