Prática no trabalho com pneus personalizados do complexo Redd

No último artigo, examinamos a teoria de gerenciar mil pequenas coisas no complexo Redd, mas, para não aumentar o volume, adiamos a prática da próxima vez. Chegou a hora de realizar experimentos práticos. Aqueles que não usam o complexo Redd também poderão encontrar conhecimento útil neste artigo, a saber, a metodologia para enviar comandos do Fornecedor para drives USB a partir do Linux, porque, como já mencionado, o controlador STM32 no complexo desempenha a função de um leitor SD, ou seja, dirigir.




Classificação da unidade por sistemas de comando


Ao trabalhar com unidades, você deve distinguir entre uma interface física e um sistema de comando. Em particular, unidades de CD / DVD / BD e outras ópticas. Tradicionalmente, eles se conectam a um cabo SATA (anteriormente IDE). Porém, especificamente nesse fio, apenas os comandos PACKET são executados durante a operação, no bloco de dados em que os comandos codificados de acordo com um princípio completamente diferente são colocados (em breve descobriremos qual). Portanto, agora falaremos não tanto sobre fios, mas sobre as equipes que os rodeiam. Conheço três sistemas de comando comuns para trabalhar com unidades.

  • MMC É entendido por cartões SD. Honestamente, para mim este é o sistema de comando mais misterioso. Como enviá-los, ao que parece, é claro, mas como gerenciar a unidade sem ler atentamente o documento que contém muitos gráficos de transição - estou sempre confuso. Felizmente, isso não nos incomoda atualmente, pois, embora trabalhemos com um cartão SD, o controlador STM32 no modo "caixa preta" trabalha com ele.
  • ATA Inicialmente, esses comandos eram executados no barramento IDE e depois no SATA. Um sistema de comando maravilhoso, mas hoje também mencionamos que ele existe.
  • SCSI Este sistema de comando é usado em uma ampla variedade de dispositivos. Considere seu uso em unidades. Hoje, as equipes de SCSI executam, antes de tudo, os fios do barramento SAS (a propósito, até SSDs com interface SAS estão na moda). Curiosamente, as unidades ópticas conectadas fisicamente ao barramento SATA também funcionam através de comandos SCSI. No barramento USB ao trabalhar de acordo com o padrão do dispositivo de armazenamento em massa, os comandos também vão no formato SCSI. O microcontrolador STM32 é conectado ao complexo Redd através do barramento USB, ou seja, no nosso caso, os comandos seguem o seguinte caminho:



Do PC ao controlador, via USB, os comandos estão no formato SCSI. O controlador transcodifica os comandos de acordo com a regra do MMC e os envia pelo barramento SDIO. Mas temos que escrever um programa para o PC, para que as equipes nos deixem no formato SCSI. Eles são preparados pelo driver de dispositivo do dispositivo de armazenamento em massa, com o qual nos comunicamos através do driver do sistema de arquivos. É possível misturar solicitações com outros dispositivos para essas solicitações? Vamos acertar.

Detalhes do sistema de comando SCSI


Se você abordar o assunto formalmente, a descrição do padrão SCSI estará disponível no t10.org, mas seremos realistas. Ninguém o lerá voluntariamente. Mais precisamente, não o dele, mas o deles: existe uma pilha inteira de documentos abertos e uma montanha de documentos fechados. Somente uma necessidade extrema fará com que você mergulhe na linguagem complexa em que o padrão está escrito (isso, a propósito, se aplica ao padrão ATA em t13.org). É muito mais fácil ler a documentação para unidades reais. Está escrito em uma linguagem mais animada, e partes hipotéticas, mas não realmente usadas, são cortadas. Ao preparar o artigo, me deparei com um documento bastante novo (2016) do Manual de referência de comandos SCSI da Seagate (link direto www.seagate.com/files/staticfiles/support/docs/manual/Interface%20manuals/100293068j.pdf , mas, como sempre, Não sei quanto tempo ela vai viver). Eu acho que se alguém quiser dominar esse sistema de comandos, ele deve começar com este documento. Lembramos apenas que os leitores SD implementam um subconjunto ainda menor dos comandos dessa descrição.

Falando muito brevemente, uma unidade de comando com um comprimento de 6 a 16 bytes é enviada para a unidade. Um bloco de dados pode ser anexado ao bloco de comando do PC para a unidade ou da unidade para o PC (o padrão SCSI também permite trocas bidirecionais, mas para o Dispositivo de armazenamento em massa via USB apenas um bloco é permitido, o que significa que a direção é apenas uma). No bloco de instruções, o primeiro byte é sempre o código de comando. Os bytes restantes são seus argumentos. As regras para preenchimento dos argumentos são descritas exclusivamente pelos detalhes da implementação do comando.



No começo, inseri muitos exemplos no artigo, mas depois percebi que eles dificultam a leitura. Portanto, sugiro que todos comparem os campos do comando READ CAPACITY (10) da tabela 119 do documento Seigate e os campos do comando READ (10) da tabela 97 do mesmo documento (consulte o link acima). Quem não encontrou nenhuma conexão - não se assuste. Era isso que eu queria mostrar. Além do campo "comando" no byte zero, o objetivo de todos os campos depende exclusivamente das especificidades de um comando específico. Você sempre precisa abrir o documento e estudar a finalidade dos campos restantes nele.

Então:

  • Para se comunicar com a unidade, você deve formar um bloco de comando com um comprimento de 6 a 16 bytes (dependendo do formato do comando, o número exato é indicado na documentação para ele).
  • O mais importante é o byte zero do bloco: é ele quem define o código de comando.
  • Os bytes restantes do bloco não têm um objetivo claro. Para entender como preenchê-los, você deve abrir a documentação para uma equipe específica.
  • Um bloco de dados que pode ser transferido para ou de uma unidade pode ser anexado a um comando.

Na verdade, é tudo. Aprendemos as regras para emitir comandos SCSI. Agora podemos enviá-los, haveria documentação sobre eles. Mas como fazer isso no nível do sistema operacional?

Comandos Linux SCSI


Pesquisar dispositivo de destino


Para emitir comandos, abra o dispositivo de disco. Vamos encontrar o nome dele. Para fazer isso, seguiremos exatamente da mesma maneira que no artigo sobre portas seriais . Vamos ver a lista de “arquivos” no diretório / dev (lembre-se de que nos dispositivos Linux também são mostrados como arquivos e sua lista é exibida com o mesmo comando ls ).

Hoje prestamos atenção ao disco do diretório virtual:



Analisamos seu conteúdo:



Um conjunto familiar de diretórios aninhados! Estamos tentando considerar o diretório by-id , usando a opção –l do comando ls, que já sabíamos no artigo sobre portas seriais:



Palavras destacadas falam por si. Esta é uma unidade que contém o cartão SD interno do complexo Redd. Ótimo! Agora sabemos que o dispositivo MIR_Redd_Internal_SD corresponde ao dispositivo / dev / sdb e / dev / sdb1 . Aquele que sem o número é a própria unidade, trabalharemos com ela e, com o número, é o sistema de arquivos localizado na mídia inserida nela. Em termos de trabalho com um cartão SD, / dev / sdb é o leitor e / dev / sdb1 é o sistema de arquivos no cartão inserido nele.

Função do sistema operacional para emitir comandos


Normalmente, em qualquer sistema operacional, todas as coisas não padronizadas dos dispositivos são feitas através de solicitações diretas ao driver. No Linux, a função ioctl () está disponível para enviar esses pedidos. Nosso caso não é exceção. Como argumento, passamos a solicitação SG_IO descrita no arquivo de cabeçalho sg.h. A estrutura sg_io_hdr_t que contém os parâmetros de solicitação também é descrita lá. Não darei a estrutura completa, pois nem todos os seus campos devem ser preenchidos. Vou dar apenas o mais importante deles:

typedef struct sg_io_hdr { int interface_id; /* [i] 'S' for SCSI generic (required) */ int dxfer_direction; /* [i] data transfer direction */ unsigned char cmd_len; /* [i] SCSI command length ( <= 16 bytes) */ unsigned char mx_sb_len; /* [i] max length to write to sbp */ unsigned short int iovec_count; /* [i] 0 implies no scatter gather */ unsigned int dxfer_len; /* [i] byte count of data transfer */ void * dxferp; /* [i], [*io] points to data transfer memory or scatter gather list */ unsigned char * cmdp; /* [i], [*i] points to command to perform */ unsigned char * sbp; /* [i], [*o] points to sense_buffer memory */ unsigned int timeout; /* [i] MAX_UINT->no timeout (unit: millisec) */ 

Não faz sentido descrever os campos que estão bem documentados nos comentários ( interface_id, dxfer_direction, timeout ). O artigo já está crescendo.

O campo cmd_len contém o número de bytes no bloco de comando e o cmdp contém um ponteiro para esse bloco. Você não pode ficar sem um comando, portanto, o número de bytes deve ser diferente de zero (de 6 a 16).

Os dados são opcionais. Se estiverem, o comprimento do buffer selecionado é especificado no campo dxfer_len e um ponteiro para ele é especificado no campo dxferp . Uma unidade pode transferir fisicamente menos dados que o tamanho do buffer especificado. A direção da transmissão é especificada no campo dxfer_direction . Os valores válidos do dispositivo de armazenamento em massa USB são: SG_DXFER_NONE, SG_DXFER_TO_DEV, SG_DXFER_FROM_DEV . Há mais uma coisa no arquivo de cabeçalho, mas o padrão do dispositivo de armazenamento em massa não permite implementá-lo fisicamente.

Você também pode solicitar o retorno de um código de erro estendido ( SENSE ). O que é encontrado pode ser encontrado no documento Segate, seção 2.4. O comprimento do buffer alocado é indicado no campo mx_sb_len , e o ponteiro para o buffer em si é indicado no campo sbp .

Como você pode ver, tudo o que eu falei acima está preenchido nesta estrutura (além disso, você pode obter informações estendidas sobre o erro). Leia mais sobre como trabalhar com a solicitação SG_IO aqui: sg.danny.cz/sg/sg_io.html

Enviamos um comando padrão para a unidade


Bem, descobrimos o formato do comando, descobrimos para qual dispositivo enviá-lo, descobrimos qual função chamar. Vamos tentar enviar algum comando padrão para o nosso dispositivo. Seja este o comando para obter o nome da unidade. É assim que é descrito no documento Sigeyt:



Observe que, de acordo com a ideologia SCSI, todos os campos nos comandos padrão são preenchidos na notação Big Endian, ou seja, o maior byte a frente. Portanto, preenchemos o campo com o tamanho do buffer não no formato "0x80, 0x00", mas, pelo contrário - "0x00, 0x80". Mas isso está em comandos padrão. No não padrão, tudo é possível, você deve sempre consultar a descrição. Na verdade, apenas o código de comando ( 12h ) e o comprimento que precisamos preencher. Solicitaremos uma página zero e os campos restantes serão reservados ou desatualizados ou o padrão será zero. Então, preencha todos com zeros.

Nós criamos um programa que fornece este comando:
 #include <cstdio> #include <stdint.h> #include <string.h> #include <fcntl.h> // open #include <unistd.h> // close #include <sys/ioctl.h> #include <scsi/scsi.h> #include <scsi/sg.h> int main() { printf("hello from SdAccessTest!\n"); int s_fd = open("/dev/sdb", O_NONBLOCK | O_RDWR); if (s_fd < 0) { printf("Cannot open file\n"); return -1; } sg_io_hdr_t header; memset(&header;, 0, sizeof(header)); uint8_t cmd12h[] = { 0x12,0x00,0x00,0x00,0x80,0x00}; uint8_t data[0x80]; uint8_t sense[0x80]; header.interface_id = 'S'; //  'S' //  header.cmd_len = sizeof(cmd12h); header.cmdp = cmd12h; //  header.dxfer_len = sizeof(data); header.dxferp = data; header.dxfer_direction = SG_DXFER_TO_FROM_DEV; //     header.mx_sb_len = sizeof(sense); header.sbp = sense; // header.timeout = 100; // 100  int res = ioctl(s_fd, SG_IO, &header;); close(s_fd); return 0; } 



Como executar esses programas em um dispositivo Redd remoto, já discutimos em um dos artigos anteriores . É verdade que, iniciando-o pela primeira vez, recebi imediatamente um erro ao chamar a função open () . Descobriu-se que o usuário por padrão não tem direitos suficientes para abrir dispositivos de disco. Qual de mim é especialista em Linux, escrevi várias vezes, mas na rede consegui descobrir que, para resolver esse problema, você pode alterar os direitos de acesso ao dispositivo emitindo o comando:

sudo chmod 666 / dev / sdb

No entanto, meu chefe (e ele é um grande especialista neste sistema operacional) mais tarde observou que a solução é válida até que o sistema operacional seja reiniciado. Para obter os direitos com certeza, você precisa adicionar o usuário ao grupo de discos .

Qualquer que seja o caminho, mas depois que tudo tiver funcionado, coloque um ponto de interrupção na linha close (s_fd); e inspecione os resultados até o momento em que é alcançado no ambiente de desenvolvimento (já que o programa nem sequer é de um dia, o que significa que não temos tempo para gastar tempo e esforço na inserção de mapeadores, se o ambiente de desenvolvimento puder nos mostrar tudo). O valor de res é zero. Então a equipe trabalhou sem erros.



O que veio para o buffer? Quando inseri a palavra dados no endereço do despejo, eles me disseram que não podiam calcular o valor, tive que inserir o & data; . É estranho, porque os dados são um ponteiro, ao depurar no Windows tudo funciona, mas apenas observe esse fato, funciona assim: veja o resultado obtido assim:



É isso mesmo, eles retornaram o nome e a revisão da unidade para nós. Mais informações sobre o formato da estrutura resultante podem ser encontradas no documento Segate (seção 3.6.2, tabela 59). O buffer de detecção não foi preenchido, mas a descrição IOCTL da solicitação diz que é preenchida apenas quando ocorre um erro que retorna algo nesse buffer. Literalmente: dados de detecção (usados ​​apenas quando 'status' é CHECK CONDITION ou (driver_status & DRIVER_SENSE) são verdadeiros) .

Formato de comando personalizado para a unidade SD interna Redd


Agora que não apenas estudamos a descrição seca do padrão, mas também tentamos tudo na prática, tendo experimentado o que é um bloco de comando, já podemos mostrar o formato de comando com o qual você pode chamar funções fora do padrão que são "piscadas" para o controlador STM32 na placa complexa. O código de comando que selecionei desde o início do intervalo de comandos específicos do fornecedor É igual a 0xC0. Tradicionalmente, nas descrições dos comandos SCSI, escreva C0h . O comprimento do comando é sempre 10 bytes. O formato da equipe é unificado e apresentado na tabela abaixo.

ByteNomeação
0 0Código de comando C0h
1Código de subcomando
2Argumento arg1. Situado na notação Little Endian (avanço de bytes baixos)
3
4
5
6Argumento arg2. Situado na notação Little Endian (avanço de bytes baixos)
7
8
9

Como você pode ver, os argumentos são dados na notação Little Endian. Isso permitirá que você descreva o comando na forma de uma estrutura e acesse seus campos diretamente, sem recorrer à função de permutação de bytes. Problemas de alinhamento (palavras duplas na estrutura têm compensações que não são múltiplas de quatro) nas arquiteturas x86 e x64 não valem a pena.

Os códigos de subcomando são descritos pela seguinte enumeração:
 enum vendorSubCommands { subCmdSdEnable = 0, // 00 Switch SD card to PC or Outside subCmdSdPower, // 01 Switch Power of SD card On/Off subCmdSdReinit, // 02 Reinitialize SD card (for example, after Power Cycle) subCmdSpiFlashEnable, // 03 Switch SPI Flash to PC or Outside subCmdSpiFlashWritePage, // 04 Write Page to SPI Flash subCmdSpiFlashReadPage, // 05 Read Page from SPI Flash subCmdSpiFlashErasePage,// 06 Erase Pages on SPI Flash (4K block) subCmdRelaysOn, // 07 Switch relays On by mask subCmdRelaysOff, // 08 Switch relays off by mask subCmdRelaysSet, // 09 Set state of all relays by data subCmdFT4222_1_Reset, // 0A Activate Reset State or switch chip to normal mode subCmdFT4222_2_Reset, // 0B Activate Reset State or switch chip to normal mode subCmdFT4222_3_Reset, // 0C Activate Reset State or switch chip to normal mode subCmdFT4232_Reset, // 0D Activate Reset State or switch chip to normal mode subCmdFT2232_Reset, // 0E Activate Reset State or switch chip to normal mode subCmdMAX3421_Reset, // 0F Activate Reset State or switch chip to normal mode subCmdFT4222_1_Cfg, // 10 Write to CFG pins of FT4222_1 subCmdFT4222_2_Cfg, // 11 Write to CFG pins of FT4222_2 subCmdFT4222_3_Cfg, // 12 Write to CFG pins of FT4222_3 }; 

Eles podem ser divididos em grupos.

Alternando dispositivos para modos interno e externo


Os comandos subCmdSdEnable e subCmdSpiFlashEnable alternam o cartão SD e o SPI, respectivamente. O parâmetro arg1 passa um dos seguintes valores:

 enum enableMode { enableModeToPC = 0, enableModeOutside }; 

Por padrão, os dois dispositivos estão conectados a um PC.

Comutação de energia


O protocolo SDIO requer muita manipulação durante a inicialização. Às vezes, é útil redefinir o cartão SD para seu estado inicial (por exemplo, ao mudar suas linhas para um conector externo). Para fazer isso, desligue e ligue a energia. Isso pode ser feito usando o comando subCmdSdPower . No argumento arg1, um dos seguintes valores é passado: 0 - desligado, 1 - ligado. Lembre-se de reservar um tempo para descarregar os capacitores na linha de energia.

Depois de ligar a alimentação, o cartão, se estiver conectado ao PC, deve ser reinicializado. Para fazer isso, use o comando subCmdSdReinit (ele não possui argumentos).

Trabalhar com a unidade flash SPI


Se o cartão SD estiver conectado ao sistema como uma unidade completa, o chip de acesso na versão atual é bastante limitado. Você pode acessar apenas suas páginas individuais (256 bytes) e apenas uma de cada vez. A quantidade de memória no microcircuito é tal que, mesmo quando se trabalha na página, o processo não leva muito tempo, mas essa abordagem simplifica bastante o "firmware" do microcontrolador.

O comando subCmdSpiFlashReadPage lê a página. O endereço é especificado no parâmetro arg1, o número de páginas a serem transmitidas no parâmetro arg2. Mas na versão atual, o número de páginas deve ser igual a uma. O comando retornará 256 bytes de dados.

Espelhado para ela está o comando subCmdSpiFlashWritePage . Os argumentos para ela são preenchidos pelo mesmo princípio. A direção da transferência de dados é para o dispositivo.

A peculiaridade da memória flash é que apenas bits únicos podem ser substituídos por zero durante a gravação. Para devolvê-los a um único valor, as páginas devem ser apagadas. Existe um comando subCmdSpiFlashErasePage para isso . É verdade que, devido aos recursos do microcircuito usado, não é uma única página configurada no parâmetro arg1 que é apagada, mas um bloco de 4 kilobytes que o contém.

Gerenciamento de relés de estado sólido


O complexo possui seis relés de estado sólido. Existem três equipes para gerenciá-los.

subCmdRelaysSet - define o valor de todos os seis relés simultaneamente. No parâmetro arg1, um valor é passado, cada bit correspondendo ao seu próprio relé (zero bit - relé com índice 0, primeiro bit com índice 1, etc.). Um valor de bit único fecha o relé, um valor zero faz com que ele seja aberto.

Este método de operação é bom quando todos os relés funcionam como um único grupo. Se eles funcionarem independentemente um do outro, com essa abordagem, você precisará iniciar uma variável de buffer que armazene o valor do estado de todos os relés. Se diferentes relés são controlados por diferentes programas, o problema de armazenar o valor agregado se torna extremamente agudo. Nesse caso, você pode usar outros dois comandos:

subCmdRelaysOn - ativa relés selecionados por máscara. Os relés que correspondem aos bits da unidade no argumento arg1 serão ativados. Os relés que correspondem a zeros na máscara manterão seu estado atual.

O comando subCmdRelaysOff, espelhando-o , desativará os relés selecionados por máscara. Os relés que correspondem aos bits únicos no argumento arg1 serão desativados. Os relés que correspondem a zeros na máscara manterão seu estado atual.

Redefinir controladores FTDI e Maxim


Para enviar sinais de redefinição para os microcircuitos FTDI e Maxim, o grupo de comandos subCmdFT4222_1_Reset , subCmdFT4222_2_Reset , subCmdFT4222_3_Reset , subCmdFT4232_Reset , subCmdFT2232_Reset e subCmdMAX3421_ é usado . A partir de seus nomes, você pode ver quais chips eles controlam através de sinais de reset. As pontes FT4222, como consideramos anteriormente, são duas no circuito (seus índices são 1 e 2), outra ponte FT4222 transfere dados para o chip MAX3421, que consideraremos no próximo artigo.

O parâmetro arg1 passa um dos seguintes valores:

 enum ResetState { resetStateActive =0, resetStateNormalOperation }; 

Por padrão, todas as pontes estão em condições normais de trabalho. Como já observado em um artigo anterior , nós mesmos não temos certeza se essa funcionalidade é necessária, mas quando não há acesso direto ao dispositivo, é melhor poder redefinir remotamente tudo e tudo.

Alternando linhas de configuração de chips FT4222


Os chips FT4222 têm quatro modos. É improvável que alguém precise de um modo diferente de "00", mas se você precisar de repente, poderá usar os comandos subCmdFT4222_1_Cfg , subCmdFT4222_2_Cfg e subCmdFT4222_3_Cfg para alternar para o primeiro, segundo e terceiro chips. O valor das linhas CFG0 e CFG1 é definido nos dois bits inferiores do parâmetro arg1 .

Experiência prática na emissão de comandos para o controlador STM32


Para testar o material teórico obtido na prática, tentaremos trocar o cartão SD. Para fazer isso, emita o comando subCmdSdEnable com o código 0x00 com o argumento enableModeOutside com o código 0x01. Ótimo. Reescrevemos o programa a partir de experiências passadas da seguinte forma.

Programa reescrito:
 #include <cstdio> #include <stdint.h> #include <string.h> #include <fcntl.h> // open #include <unistd.h> // close #include <sys/ioctl.h> #include <scsi/scsi.h> #include <scsi/sg.h> int main() { printf("hello from SdAccessTest!\n"); int s_fd = open("/dev/sdb", O_NONBLOCK | O_RDWR); if (s_fd < 0) { printf("Cannot open file\n"); return -1; } sg_io_hdr_t header; memset(&header;, 0, sizeof(header)); uint8_t cmdSdToOutside[] = { 0xC0,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }; uint8_t cmdSdToPC[] = { 0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }; uint8_t sense[32]; memset(sense, 0, sizeof(sense)); header.interface_id = 'S'; //  'S' //  header.cmd_len = sizeof(cmdSdToOutside); header.cmdp = cmdSdToOutside; //  ( ) header.dxfer_len = 0; header.dxferp = 0; header.dxfer_direction = SG_DXFER_NONE; //     header.mx_sb_len = sizeof(sense); header.sbp = sense; // header.timeout = 100; // 100  int res = ioctl(s_fd, SG_IO, &header;); //   header.cmdp = cmdSdToPC; res = ioctl(s_fd, SG_IO, &header;); close(s_fd); return 0; } 


Alteramos o comprimento do comando para dez bytes e removemos o bloco de dados. Bem, eles escreveram o código de comando com argumentos, conforme necessário. Caso contrário, tudo permanece o mesmo. Começamos ... E ... Nada funciona. A função ioctl () retorna um erro. O motivo está descrito no documento de comando SG_IO . O fato é que damos o comando específico do fornecedor C0h , e o seguinte é dito sobre eles literalmente:
Qualquer outro comando SCSI (opcode) não mencionado para o driver sg precisa de O_RDWR. Qualquer outro comando SCSI (opcode) não mencionado para a camada de bloco SG_IO ioctl precisa de um usuário com o recurso CAP_SYS_RAWIO.

Como o chefe me explicou (estou apenas recontando suas palavras), os valores das capacidades são atribuídos a um arquivo executável. Por esse motivo, tive que rastrear a partir do ambiente de desenvolvimento efetuando login como raiz . Não é a melhor solução, mas pelo menos alguma coisa. De fato, no Windows, a solicitação IOCTL_SCSI_PASS_THROUGH_DIRECT também requer direitos de administrador. Talvez nos comentários alguém dê conselhos sobre como resolver o problema de rastreamento sem essas etapas drásticas, mas você pode executar o programa já escrito sem raiz , se registrar os recursos corretos para ele . Enquanto isso, altere o nome de usuário no ambiente de desenvolvimento e defina um ponto de interrupção na linha:

 int res = ioctl(s_fd, SG_IO, &header;); 

e antes de chamar a função ioctl () , examinamos a lista de dispositivos de armazenamento:



Ligue para ioctl () e veja a lista novamente:



O dispositivo / dev / sdb permaneceu (grosso modo, este é o próprio leitor de cartão SD) e / dev / sdb1 desapareceu. Este dispositivo corresponde ao sistema de arquivos na mídia. A operadora desconectou do computador - não estava mais visível. Continuamos rastreando. Depois de chamar a segunda função ioctl () , examinamos novamente a lista de dispositivos:



O cartão SD é reconectado ao sistema, então / dev / sdb1 está de volta no lugar. Na verdade, aprendemos como emitir comandos específicos do fornecedor e gerenciar um dispositivo baseado no microcontrolador STM32 no complexo Redd. Outros comandos serão deixados para os leitores para estudo independente. Você pode controlar a operação de alguns deles de maneira semelhante. Se algum chip ftdi entrar em um estado de redefinição, o dispositivo correspondente desaparecerá do sistema. A operação do relé e o controle das pernas da configuração terão que ser controlados por instrumentos de medição. Bem, você pode verificar o trabalho com uma unidade flash escrevendo páginas com o controle de leitura subsequente.

Conclusão


Examinamos dois grandes tópicos que não estão relacionados aos FPGAs no complexo Redd. O terceiro permaneceu - trabalhando com o chip MAX3421, que permite a implementação de dispositivos USB 2.0 FS. De fato, também existem hosts, mas existem muitos hosts e a placa-mãe. A funcionalidade do dispositivo permitirá ao complexo fingir ser uma unidade flash USB (para enviar atualizações de "firmware"), um teclado USB (para controlar unidades externas) etc. Vamos considerar este tópico no próximo artigo.

Source: https://habr.com/ru/post/pt484706/


All Articles