Faça o download da configuração para FPGA via USB ou desmonte o FTDI MPSSE
Nós escrevemos o carregador FPGA no LabVIEW. Parte 1

No primeiro artigo, testamos o algoritmo de carregamento no bom e velho C, no segundo artigo, descobrimos como organizar um programa no LabVIEW e implementar uma interface de usuário simples. Desta vez, vamos nos familiarizar com os novos métodos de trabalho no LabVIEW, analisar os recursos de tratamento de erros e concluir o projeto: implementamos o protocolo para carregar o arquivo de configuração no FPGA.
Tratamento de erros
Abra o código fonte, analise a função MPSSE_open. Apesar da simplicidade algorítmica (as funções são chamadas uma após a outra), é necessário importar alguns elementos da API do FT_OpenEx
: FT_ResetDevice
, FT_Purge
, FT_SetUSBParameters
, FT_SetChars
, FT_SetTimeouts
, FT_SetLatencyTimer
, FT_SetFlowControl
, FT_SetBitMode
Como foi mostrado no artigo anterior , a importação de funções é realizada usando o nó Call library Function
. Este nó possui terminais dedicados para controle de erros. O LabVIEW possui uma regra simples: todos os VIs devem rastrear erros e reportar erros retornados pelos terminais de erro. A maioria dos VIs embutidos segue-o estritamente. Espero que todos compreendam como é importante controlar e manipular erros, especialmente no estágio de depuração, mas há outra razão pela qual isso é tão importante que não é óbvio para programadores "clássicos". O LabVIEW não possui uma sequência estrita de dispositivos no diagrama de blocos: o dispositivo é executado quando os dados estão prontos em suas entradas. Se os dados da saída de um VI são transferidos para a entrada de outro VI, fica claro que no início o primeiro VI funcionará, somente depois do segundo. Mas e se não houver transferência de dados e os VIs executarem ações independentes? Obviamente, você pode usar a complexa "Estrutura de sequência plana", mas é muito mais conveniente conectar os dispositivos entre si por um fluxo de erros.
Ao importar funções do D2XX, encontramos dois tipos de erros. O primeiro - este é um erro de importação direta - retorna o próprio bloco de Call library Function
. O segundo é um erro da própria biblioteca; é retornado por quase todas as funções via FT_STATUS
. Todos os valores possíveis são descritos como enumeração no arquivo de cabeçalho ftd2xx.h. Embora seja suficiente saber que o valor FT_OK
é a ausência de um erro e todos os outros valores são códigos de erro, gostaria de acompanhar não apenas o fato do erro em si, mas também o erro que ocorreu e onde exatamente ocorreu.
No LabVIEW, os dados de erro são propagados através de agrupamentos de error
. Este é um tipo de dados dedicado tão especial; o LabVIEW possui muitos VIs e funções para trabalhar com ele. O cluster de erros consiste em três elementos: uma variável lógica - exibe o status, um número inteiro assinado - um código de erro, uma string - a origem do erro. O status indica se ocorreu um erro, o código de erro determina seu tipo e é usado por VIs especiais para gerar um relatório. A linha fornece uma idéia mais detalhada de exatamente onde o erro ocorreu. No LabVIEW, é aceito que, se o status for TRUE
, isso é um erro, se o status for FALSE
, mas o código não é zero e a linha de descrição não está vazia, isso é um aviso , se o status for FALSE
, o código é zero e a linha está vazia, não há erro.

O LabVIEW contém um banco de dados interno no qual cada código de erro está associado à sua descrição. Para cada tipo de erro, um intervalo especial de valores de código é alocado. Por exemplo, para os erros associados à operação da rede, vários intervalos são alocados: de –2147467263 a –1967390460, de 61 a 65, de 116 a 118 e 122, 1101, 1114, 1115, 1132 a 1134, de 1139 a 1143 e de 1178 a 1185 Para erros definidos pelo usuário, dois intervalos são reservados de –8999 a –8000 e de 5000 a 9999. Nesses intervalos, podemos escolher valores para os códigos de erro da biblioteca D2XX.
Vamos criar um VI que receba o status da função D2XX como entrada e converta esse status em um cluster de erros do LabVIEW. A maioria das funções e VIs no LabVIEW, tendo recebido o status TRUE
na entrada Error In
, não executa seu código, mas transmite informações de erro para o terminal Error Out
. Isso permite que você efetivamente transfira informações sobre a fonte através de toda a cadeia para o manipulador de erros, eliminando a execução do código no modo de emergência. É desejável que nossos VIs se comportem de maneira semelhante.
Vamos organizar a lista de status do D2XX na forma de enum
e colocá-la em um tipo separado (no artigo anterior, fizemos isso com os tipos de FTDI).
Nós salvamos o novo VI com o nome FT_error.vi. Adicionamos dois clusters Error In
e Error Out
painel frontal. Você pode encontrá-los no painel "Matriz, matriz e cluster". Nós os conectamos aos terminais no painel de conexão nos cantos inferior esquerdo e direito, respectivamente, como já mencionado no artigo anterior, este é o local dos terminais de fluxo de erro adotados pelo LabVIEW. Adicionamos a estrutura Case
ao diagrama de blocos, fornecemos o cluster Error In
à entrada Case selector
, após o qual a estrutura Case
muda de cor e divide dois sub-diagramas: "No Error" - cor verde e "Error" - cor vermelha. Dentro do caso Error, transferimos o cluster de erros do terminal seletor diretamente para o túnel de saída na borda direita. E no caso verde, adicionamos outro Case
, dependendo do status, ele determinará se deve ser criado um erro (o status não é igual a FT_OK) ou o deixa como está: pule o cluster de erros de entrada para sair sem alterar.
Para converter tecnicamente o código de erro em um cluster, você pode usar o VI Error Cluster From Error Code VI
. Este SubVI adiciona uma cadeia de chamadas à descrição do erro, para que possamos determinar não apenas o que aconteceu, mas também onde aconteceu.
Para selecionar o texto correspondente ao status de entrada (FT_Status), use o bloco de propriedades: selecione "RingText.Text". O texto do erro é enviado para a entrada da error message
de Error Cluster From Error Code VI
.
Não se esqueça de desenhar um ícone "falante".
FT_error.vi
Painel frontal do sub-instrumento

Diagrama de blocos. Erro de entrada

Diagrama de blocos. Não há erro na entrada e o status é FT_OK

Diagrama de blocos. Não há erro na entrada, mas o status é diferente de FT_OK
Para testar o FT_error, você pode criar um VI vazio, adicionar o VI criado lá e ver como o valor será alterado na inicialização se vários status forem aplicados.
Teste FT_error.vi
Painel frontal (frontal) do dispositivo

Diagrama de blocos
Agora, após qualquer chamada de função da API do D2XX, usaremos o SubVI FT_error.vi. Um cluster de erros passará por todos os VIs na hierarquia de chamadas.
Nos VIs de nível superior, devemos decidir o que fazer com o erro detectado: você pode exibir uma mensagem na caixa de diálogo, gravá-la no arquivo de relatório, ignorá-la ou simplesmente "silenciosamente" finalizar o aplicativo. A caixa de diálogo é a maneira mais fácil e popular de relatar erros. Também é conveniente para um programador iniciante, pois não há nada a fazer. Em cada VI, o modo automático de tratamento de erros é ativado por padrão ( Ative o tratamento automático de erros , localizado na categoria Execução do menu Propriedades do VI). Funciona assim: se o terminal Error Out
não estiver conectado em nenhum lugar de algum nó e ocorrer um erro nesse nó, o LabVIEW interrompe o aplicativo e exibe uma caixa de diálogo. Se o terminal Error Out
do nó estiver conectado, o fluxo de erros será propagado conforme programado e nenhuma ação adicional ocorrerá. No entanto, a janela de mensagem pode ser acessada de forma programática, para isso, é necessário usar os VIs Simple Error Handler
General Error Handler
e Simple Error Handler
(localizados no painel Diálogo e interface do usuário). Nesse caso, podemos usar as informações de erro para concluir o programa. Em um diagrama de blocos, é algo como isto:

Imagem clicável
Quando ocorrer um erro, o programa será suspenso, uma janela de relatório será exibida. Após fechar a janela, o programa será encerrado corretamente.
Abrir e fechar FTDI
Então, de volta à função MPSSE_open
. Crie um novo VI . Primeiro de tudo, adicione os terminais para o fluxo de erros. Adicione uma estrutura de seleção e selecione Entrada de Error In
no seletor. No caso verde, importamos as funções na ordem e com os parâmetros como no protótipo de Sishny. Todos os nós do nó da Call Library Function Node
conectados em uma cadeia por um fluxo de erros. No estojo vermelho através do túnel, conectamos o Error In
ao terminal de saída do erro.

Imagem clicável

VI MPSSE_open.vi
Uma linha com a descrição de FTDI ( Description
) é fornecida à entrada do SubVI, na saída é Handle
e um chip FTDI inicializado no modo MPSSE.
Vamos criar um vice-presidente que termine de trabalhar com o FTDI e você já poderá verificar o desempenho no hardware.
FT_Close.vi
Diagrama de blocos

Painel frontal
No artigo anterior, para depurar a interface, criamos o stub VI SP_FT_MPSSE_FPGA.vi, agora é hora de preenchê-lo. Adicione MPSSE_open.vi e FT_Close.vi ao seu diagrama de blocos. Nesse estágio, é bastante difícil avaliar se a inicialização estava correta; no entanto, o valor diferente de zero de Handle
na saída do MPSSE_open.vi e a ausência de um erro nos dizem muito.

Fluxograma SP_FT_MPSSE_FPGA.vi
Para ver o valor de Handle
você pode usar a "Janela de inspeção do probe". Esta é uma ferramenta de depuração conveniente que permite exibir o valor dos dados em qualquer fio (quase qualquer) durante a execução do dispositivo. Para definir a amostra na linha, você precisa selecionar "Sonda" no menu de contexto desta linha. A janela "Probe Watch Window" será aberta e um número com o número da amostra aparecerá na linha. Na imagem acima, é "3".
Janela de inspeção do probe
Na linha Alça, o valor 698389336
Ótimo! Iniciamos os VIs de nível superior, conectamos a placa de depuração ao computador. Uma descrição do chip FTDI conectado aparece na lista "Selecionar um dispositivo", clique no botão "Programa" e ... nada acontece. Somente na janela "Probe Watch" o valor Handle
exibido. E isso é bom.
Desligamos o painel, a lista de dispositivos é limpa. Clique em "Programa". É aqui que a janela do relatório de erros é exibida.
Depois de clicar no botão "Continuar", o VI conclui seu trabalho.
É proibido pressionar o botão se nenhum dispositivo for encontrado. Modificamos o manipulador de eventos "Timeout" do caso. Deixe-me lembrá-lo de que os chips FTDI conectados a um PC são verificados duas vezes por segundo, se forem detectados e puderem ser usados para programar FPGAs, seus descritores serão adicionados à Devices list
através da propriedade Strings[]
. Criamos a propriedade Disabled
para "Programming" e, se nenhum dispositivo adequado for encontrado, desligue e escureça o botão.
Tempo limite do caso
Imagem clicável
Dominando o GPIO
Depois que o MPSSE é ativado, o trabalho é realizado através do chamado "código operacional", e somente FT_Write
, FT_Read
e FT_Queue
são usados nas funções da API do FT_Write
(para descobrir o status do buffer do receptor). Criamos o VI correspondente ao longo da trilha que criamos: FT_Write.vi, FT_Read.vi, FT_Queue.vi.
Um pouco de rotina
FT_Write.vi

Diagrama de blocos. FT_Write.vi

FT_Read.vi

Diagrama de blocos. FT_Read.vi

FT_Queue.vi

Diagrama de blocos. FT_Queue.vi
Agora, a partir desses três tijolos, apresentamos os VIs para ler a porta paralela e escrever nela. O valor é convenientemente representado como uma matriz de variáveis booleanas.
MPSSE_Set_LByte.vi e MPSSE_Get_LByte.vi
MPSSE_Set_LByte.vi

Diagrama de blocos. MPSSE_Set_LByte.vi

MPSSE_Get_LByte.vi

Diagrama de blocos. MPSSE_Get_LByte.vi
Confesso que tive preguiça de criar uma lista nomeada para todos os códigos operacionais, então os deixei na forma de Números Mágicos.
Conforme declarado no primeiro artigo , o protocolo de inicialização Passive Serial FPGA nada mais é do que um SPI com manipulação adicional de sinalizador. Um total de cinco partes é usado: as linhas DCLK , DATA [0] , nCONFIG devem ser configuradas como saídas, as linhas nSTATUS , CONF_DONE como entradas.
Pinagem do layout da tabelaPino FPGA | Nome do PIN | Pin | MPSSE | Direção | padrão |
---|
DCLK | BDBUS0 | 38. | TCK / SK | Fora | 0 0 |
DADOS [0] | BDBUS1 | 39. | TDI / DO | Fora | 1 |
nCONFIG | BDBUS2 | 40. | TDO / DI | Fora | 1 |
nSTATUS | BDBUS3 | 41. | TMS / CS | Em | 1 |
CONF_DONE | BDBUS4 | 43 | GPIOL0 | Em | 1 |
Precisamos de um vice-presidente que possa alterar o valor da perna selecionada sem afetar todas as outras. Primeiro, crie Enum
com números de série das pernas na porta, salve-o como "Strict Type Def" no arquivo SP_LBYTE_BITS.ctl. Criamos um novo VI, adicionamos os terminais de fluxo de erro conhecidos. Lemos o valor atual da porta paralela usando MPSSE_Get_LByte.vi, usamos a função Replace Array Subset
para modificar o bit desejado e gravamos o valor de volta na porta (MPSSE_Set_LByte.vi).
SP_Set_Flag.vi
SP_Set_Flag.vi

Diagrama de blocos. SP_Set_Flag.vi

Enum SP_LBYTE_BITS.ctl
Para iniciar a configuração, o MPSSE deve gerar uma transição de baixa para alta na linha nCONFIG . Assim que o FPGA estiver pronto para receber dados, ele formará um alto nível na linha nSTATUS . Nesta fase, tudo está pronto para o experimento em ferro. No diagrama de blocos SP_FT_MPSSE_FPGA.v, adicionamos a linha de controle nCONFIG - após a inicialização do MPSSE, fornecemos um nível baixo e depois alto. Após cada operação (para depuração), lemos o status dos trechos da porta.
SP_FT_MPSSE_FPGA.vi
Durante a inicialização

Diagrama de blocos
Em geral, durante o lançamento do VI, é claro que o FPGA responde à transição na linha nCONFIG - zero é definido na perna nSTATUS e depois uma. Mas não será supérfluo monitorar isso com um osciloscópio. Quase todos os osciloscópios de dois canais com acionamento por disparo (espera) são adequados. Canal A (faixa azul) Coloquei no ponto de controle do circuito nCONFIG , canal B (faixa vermelha) - cadeia nSTATUS . O gatilho está definido para a extremidade descendente do canal A.

A imagem é clicável. Com os detalhes!
Trabalhar com arquivo
O FPGA está pronto para aceitar o arquivo de configuração. Estamos prontos para transferir o arquivo para o FPGA?
O LabVIEW contém um extenso conjunto de ferramentas para trabalhar com arquivos. Não posso dizer que a funcionalidade seja suficiente para absolutamente toda a gama de tarefas; no entanto, operações básicas como leitura e escrita são realizadas de maneira fácil e agradável. O conjunto básico de VIs para trabalhar com arquivos pode ser encontrado no painel "File I / O". Para resolver o problema, você precisa abrir o arquivo de configuração, avaliar seu tamanho (precisamos saber quantos bytes enviar o FPGA), lê-lo e fechá-lo. Tudo é simples e um após o outro. Usamos os refnum
Open/Create/Replace File
, Get File Size
, Read from Binary File
, Close File
, combiná-los com a cadeia de fluxo de erro e refnum
- um número, como um descritor de arquivo, é criado quando o arquivo é aberto e deve ser transferido para a entrada de outros VIs que trabalham com esse arquivo.
Até o momento, não temos nenhum lugar para descartar os dados lidos, mas se você realmente deseja verificar a operacionalidade da cadeia, pode criar um indicador do tipo String
e configurá-lo um pouco. No menu de contexto, ative a opção "Hex Display", ative a barra de rolagem vertical (Itens Visíveis -> Barra de Rolagem Vertical) e, após o lançamento, observamos o conteúdo do arquivo de configuração binária.
SP_FT_MPSSE_FPGA.vi
Painel frontal Examinamos o conteúdo do arquivo

Diagrama de blocos. Karinka clicável
Duas linhas paralelas independentes de código formadas no diagrama de blocos do VI, portanto, cadeias de erro separadas são usadas para elas. Para reduzir os fluxos paralelos em um terminal Error Out
, a função Merge Errors
Error Out
é usada. Esta função procura erros de entrada de cima para baixo (sim, pode haver mais de dois terminais de entrada, é esticada pelo mouse) e retorna o primeiro que encontrar. Se não houver erros, ele retornará a primeira mensagem de aviso. Se não houver avisos, não haverá erro na saída. É importante observar que a ordem de conexão das entradas Merge Errors
determina a prioridade dos erros e, se ocorrer um erro imediato em duas cadeias, o erro mais baixo será ignorado. Isso deve ser tratado com cuidado.
Se tentarmos pressionar o botão "Programa" no VI de nível superior sem selecionar um arquivo, a entrada SP_FT_MPSSE_FPGA.vi receberá um caminho vazio, o que causará o erro "Erro 1430. LabVIEW: (Hex 0x596) O caminho está vazio ou relativo. Você deve usar um caminho absoluto ". Como meu amigo de infância diz: "Ninharia, isso é algo mundano!" E esse erro não é um erro, mas a falta de atenção do usuário. Não interromperemos o programa e juraremos com uma janela com uma cruz vermelha; simplesmente removemos o erro com esse código do fluxo e, na caixa de diálogo, recomendamos que o usuário decida o arquivo. Para filtrar o erro, use o VI "Limpar erros" na paleta "Caixa de diálogo e interface do usuário". Para exibir a mensagem - "Caixa de diálogo com um botão".

Diagrama de blocos
Imagem clicável
Download da configuração
Para transferência serial de dados, o processador MPSSE precisa enviar o código operacional 0x18, os argumentos do comando serão o comprimento da sequência transmitida (dois bytes, começando pelo mais baixo) e a própria sequência de dados. O comprimento é codificado menos um. Vamos enviar o bloco de dados como o VI MPSSE_send.
MPSSE_Send.vi
MPSSE_Send.vi

Diagrama de blocos
O tamanho do buffer de entrada ( Array Size
) é convertido em um tipo de byte duplo U16
, subtraímos um, trocamos os bytes alto e baixo (bytes de Swap Bytes
) - você precisa enviar o comprimento começando pelo mais baixo e converter o número de byte duplo em um array de byte único (conversão de Type Cast
).
A função Type Cast
merece atenção especial. Esse é um conversor de tipo universal, cuja engenhosidade às vezes é muito surpreendente. Em suma, então:

Visualmente para o programador
No entanto, isso não é apenas converter dados para um tipo diferente, é também uma interpretação heurística. Esta função permite realizar a conversão entre tipos de dados incompatíveis, enquanto a função não hesita em alinhar os dados de entrada e até remover as partes "extras". Se o tipo de dados solicitado exigir mais memória que os dados de entrada, a função alocará a quantidade que falta. Para um desenvolvedor iniciante, o LabVIEW Type Cast
pode se tornar um salva-vidas, mas com o crescimento, é melhor recusar esse conversor - ele fica muito escondido da vista e pode se tornar uma fonte de erros inesperados. É melhor usar métodos de conversão mais explícitos, como Coerce To Type
.
Ao inicializar o processador MPSSE, configuramos o tamanho máximo permitido do buffer para transferência de dados para 65536 bytes; portanto, devemos dividir o arquivo de configuração em fragmentos cujo tamanho não exceda o tamanho especificado. Usaremos a função Array Subset
, essa função seleciona uma subarray da matriz, começando com o elemento index
e um length
longo. Nós o dividiremos em um loop While
, aumentaremos cada iteração do índice em 65536. Entre as iterações, passaremos o valor pelo registro de deslocamento. Assim que não é possível extrair 65536 bytes da matriz principal, pegamos tudo o que resta, enviamos e paramos o ciclo.
De acordo com o protocolo de download, após a transferência de todos os dados, mais dois pulsos de clock devem ser aplicados para iniciar a inicialização do FPGA. Para fazer isso, após o loop, enviamos outro byte "vazio".
SP_FT_MPSSE_FPGA.vi
Imagem clicável
Para entender o sucesso do firmware, consideramos os sinalizadores e, se CONF_DONE estiver definido como um, relatamos o nível superior VI de que tudo está OK.
O programa está completo. Resta garantir que o FPGA esteja piscando com sucesso e a placa pisque alegremente com os LEDs.
Sobre a nomeação de vice-presidente
, , LabVIEW, , SubVI. . :
- — , FTDI, API D2XX. "FT", FT_Close.vi FT_Read.vi.
- — MPSSE. "MPSSE". : MPSSE_open.vi, MPSSE_Set_LByte.vi, MPSSE_Get_LByte.vi.
- — "Passive Serial" MPSSE. "S". , SP_FT_MPSSE_FPGA.vi ( , ) SP_LBYTE_BITS.ctl.
- . . , .
( ), . subVI .
, , .
, LabVIEW, . , , , ( ). .
Materiais relacionados
- . LabVIEW: . Per. . . .– .:
, 2008 – 400 .: . - labview_mpsse . .
- .
- Software Application Development D2XX Programmer's Guide . API D2XX.