Chave de seleção de inicialização de hardware usando Pico
Pré-escolha o sistema operacional para inicializar, mesmo antes de ligar o computador, alternando um botão. Agora você não precisa esperar para selecionar o sistema operacional.
História
Vagando Hackaday.io por projetos, me deparei com este projeto (clique) de Stephen Holdaway. Neste projeto, ele resolveu uma tarefa frustrante enfrentada por todo usuário de dual boot, que está sentado e esperando para escolher os (Windows) do menu GRUB a qualquer momento quando quisermos mudar para o Windows. Ele foi capaz de adicionar uma chave de hardware para determinar o sistema operacional a ser inicializado cada vez que o computador fosse ligado.
Ele conseguiu isso configurando o microcontrolador STM32 como um dispositivo de armazenamento em massa USB. Ele documentou toda a sua jornada pela pesquisa e implementação do projeto na postagem hackaday (clique). Por favor, leia sua postagem para obter uma melhor compreensão das implementações.
Neste projeto, vou mostrar como consegui portar as alterações para o Raspberry Pi Pico. Você pode encontrar minha versão neste repositório GitHub (clique).
Conceito
GNU GRUB é um programa executado antes de qualquer sistema operacional ser carregado. Através deste menu, podemos selecionar qual SO carregar. GRUB oferece módulos muito limitados para trabalhar. Isso significa que ele não pode ler dados de um microcontrolador conectado via USB. Mas ele pode ler dados de discos de armazenamento.
Portanto, podemos enganar o GRUB para ler os dados do microcontrolador, enumerando nosso micro como um dispositivo de armazenamento em massa.
Portanto, enumeramos nosso raspberry pi pico como um dispositivo de armazenamento em massa, por meio da biblioteca tinyUSB, que terá um arquivo switch.cfg arquivo, no qual o pico gravará a posição da chave, ou seja, 1 para LIGADO 0 para DESLIGADO .
Temos que adicionar um script no GRUB, que funciona para ler o arquivo switch.cfg e definir o padrão para 0 (Ubuntu) / 2 (Windows).
GRUB quando carrega, executa nossos scripts personalizados, que por sua vez procura nosso dispositivo por seus identificadores UUID, e se sai lê o arquivo switch.cfg. Depois de obter a posição do interruptor, ele define a seleção do sistema operacional padrão, respectivamente.
Resumindo,
- pico irá se configurar como um dispositivo de armazenamento em massa.
- o menu grub chama nosso script e pede o arquivo específico.
- O Pico responde à solicitação de leitura adicionando a posição do switch no arquivo switch.cfg.
- o script em grub extrai as informações do arquivo e define a opção padrão dos dados extraídos.
Configurando o Pico como um dispositivo de armazenamento em massa
Eu usei o cdc_msc exemplo por tinyUSB para conseguir isso. O exemplo configura o pico como um dispositivo de armazenamento em massa, cria um sistema de arquivos FAT12 e enumera um arquivo README.txt.
Mudei o README.txt para switch.cfg e adicionei a linha “set os_hw_switch =0 \ n” ao arquivo.
# define SWITCH_CFG_CONTENTS \
"set os_hw_switch =0 \ n"
...
// ----- -------- Bloco3:Conteúdo Leiame ------------- //
SWITCH_CFG_CONTENTS
Agora configuramos o pico como um dispositivo de armazenamento em massa. Depois de copiar o arquivo uf2 para o pico, ele é enumerado como um dispositivo de armazenamento. Precisaremos do ID UUID do dispositivo para o script GRUB, que é UUID =”0000-1234 ″.
$ sudo blkid
...
/ dev / sda:SEC_TYPE ="msdos" LABEL_FATBOOT ="TinyUSB MSC" LABEL ="TinyUSB MSC" UUID ="0000-1234" BLOCK_SIZE ="512" TYPE ="vfat"
Circuito
Leitura da posição do switch e gravação no arquivo
Agora precisamos ler a posição do switch e alterar o conteúdo do arquivo switch.cfg de acordo, ou seja,
- se o interruptor estiver LIGADO: definir os_hw_switch =1 \ n
- se a chave estiver DESLIGADA: defina os_hw_switch =0 \ n
Usei o GPIO_PIN 28 como o pino da chave, que está definido para puxar para baixo.
read_switch_value retorne a posição da chave, ou seja, '1' está ligado (puxado para cima) e '0' está desligado (puxado para baixo).
// ------------------------- main.c -------- -------------
#define SWITCH_PIN 28
// ler o valor do switch
uint8_t read_switch_value ()
{
retornar gpio_get (SWITCH_PIN)? '1':'0';
}
int main (vazio)
{
gpio_init (SWITCH_PIN);
// configurar pin como INPUT
gpio_set_dir (SWITCH_PIN, false);
// configurar o pino como PULL_DOWN
gpio_set_pulls (SWITCH_PIN, falso, verdadeiro);
Para escrever a posição da chave para switch.cfg, usei readGRUBConfig () que chama o read_switch_value função e definir o buffer de saída com a posição do interruptor.
Eu descobri que ao ler o terceiro bloco 3 lba é definido como 3, portanto, interceptando a chamada e chamando readGrubConfig e passando o buffer onde o conteúdo do arquivo será copiado.
// ------------------------- msc_disk.c -------- -------------
static char grubConfigStr [] ="set os_hw_switch =0 \ n";
static void readGrubConfig (uint8_t * output)
{
// Modifica a string de configuração com o valor da chave atual
grubConfigStr [sizeof (grubConfigStr) -3] =read_switch_value ();
memcpy (saída, &grubConfigStr, sizeof (grubConfigStr));
}
// Retorno de chamada invocado quando recebido o comando READ10.
// Copia os dados do disco para o buffer (até o tamanho bufs) e retorna o número de bytes copiados.
int32_t tud_msc_read10_cb (uint8_t lun, uint32_t lba, uint32_t offset, void * buffer, uint32_t bufsize)
{
(void) lun;
// ao ler o arquivo
if (lba ==3) {
readGrubConfig (buffer);
return bufsize;
}
...
...
}
Compile o código do Pico
Precisamos adicionar pico stdlib ao nosso código para obter o gpio acesso por pin.
// ------------------------- main.c -------- ---------------------------
#include
#include
#incluir
#incluir "bsp / board.h"
#incluir "tusb.h"
...
#incluir "pico / stdlib.h "
Para fazer o projeto:
$ mkdir build
$ cd build
$ cmake ..
$ make
Configurando o GRUB para ler o conteúdo do arquivo
Eu adicionei essas mudanças no meu Ubuntu 20.10.
$ sudo vim /etc/grub.d/40_custom
....
# Procure o dispositivo de troca de hardware por seu hard-coded ID do sistema de arquivos
search --no-floppy --fs-uuid --set hdswitch 0000-1234
# Se encontrado, leia o arquivo de configuração dinâmica e selecione a entrada apropriada para cada posição
if ["$ {hdswitch}"]; então
fonte ($ hdswitch) /switch.cfg
if ["$ {os_hw_switch}" ==0]; então
# Boot Linux
set default ="0"
elif ["$ {os_hw_switch}" ==1]; então
# Boot Windows
set default ="2"
else
# Retorno ao padrão
set default ="$ {GRUB_DEFAULT}"
fi
else
definir padrão ="$ {GRUB_DEFAULT}"
fi
Primeiro, procuramos nosso sistema de arquivos. GRUB tem um subcomando search apenas para isso.
- -no-disquete opção impede a pesquisa de dispositivos de disquete
- -fs – uuid 0000-1234 pesquisa um sistema de arquivos com UUID de 0000-1234.
Se algum dispositivo for encontrado, o primeiro dispositivo encontrado é definido como o valor da variável de ambiente.
–set hdswitch hdswitch é a nossa variável de ambiente e é definida com o nome do disco, se encontrado.
Em seguida, fornecemos o arquivo switch.cfg se o hdswitch variável é definida, o que cria outra variável de ambiente
os_hw_switch
com a posição do interruptor, ou seja, 0/1. Lemos o valor do
os_hw_switch
e defina o padrão para 0 ou 2, respectivamente. 0 porque o Ubuntu está na 0ª posição e as janelas na 2ª posição no menu GRUB. Por último, se hdswitch não foi definido, definimos o padrão para GRUB_DEFAULT.
Agora precisamos atualizar nosso grub:
$ sudo update-grub
Fonte: Hardware Boot Select Switch usando Pico
Processo de manufatura
- Instrução C# switch
- C# usando
- Estação meteorológica Raspberry Pi 2
- Sistema de controle de dispositivo baseado em temperatura usando LM35
- Monitoramento remoto do clima usando Raspberry Pi
- SensorTag para Blynk usando Node-RED
- Sensor de movimento usando Raspberry Pi
- Robô usando Raspberry Pi e Bridge Shield
- Robô controlado por Wi-Fi usando Raspberry Pi
- Uma introdução ao hackeamento de hardware embarcado de dispositivo IoT