martes, 20 de mayo de 2008

CONTROLADOR DEL TECLADO

Na primeira parte do diagrama de bloques podemos atopar a parte correspondente coa interface humana do sistema: o controlador do teclado. Este está deseñado para cumprir coa tarefa de xerar os sinais de entrada ao sistema cando o usuario pulsa algunha das teclas do teclado matricial.


Na páxina web do departamento puidemos atopar uns ficheiros que xa resolvían o noso problema, pero decidimos adaptalos á nosa aplicación para facer un deseño máis óptimo desde o punto de vista da FPGA (terminales, liñas, reloxos, ...)


Os cambios máis importantes atópanse no ficheiro ucf (fixemos un que realiza unha pequena proba do mesmo na placa), no controlador do teclado, na unidade de control (máquina de estados) e na interface, que é o ficheiro principal do proxecto, xa cos reloxos integrados e coas entradas e saídas correctas.


De calquera maneira, seguimos en liñas xerais os pasos da aplicación que se atopa na web. A nosa interface co teclado matricial consta de:

1) Unidade de control do controlador (ficheiro keypad_control_unit.vhd), que sincroniza os sinais de entrada e saída do teclado co sistema e co propio controlador. A súa función principal é mostrar en "fila(1:0)" e "columna(1:0)" o código da tecla pulsada á vez que se xera o sinal "pulsada" todo o tempo que a tecla estea pulsada.

2) Temporizador do teclado (keypad_timer.vhd), que temporiza determinados retardos necesarios na máquina de estados da unidade de control. Estes son de exactamente 5 e 500 milisegundos.

3) Divisor de frecuencia (frequency_divider.vhd), que xera o sinal de 1kHz a partir dun reloxo de 50MHz que usaremos para a aplicación.


4) Interfaz do teclado sen o divisor de frecuencia (keypad_16_kaeys_interface.vhd), onde se instancian as tres unidades anteriores.

4) Ficheiro principal (top_keypad_16_keys_interface.vhd), que realiza as funcións necesarias desta parte do diagrama de bloques, instanciando o divisor de frecuencia e a interfaz.


Para comprobar o bo funcionamento do sistema, seguimos a política de realizar simulacións con test benchs de todos e cada un dos ficheiros que necesitamos para realizar a interface co teclado matricial.


SIMULACIÓN TEMPORAL DO TEMPORIZADOR

Para comprobar o funcionamento de temporizador (keypad_timer.vhd) fixemos un test-bench no que se comproba a posta a un dos sinais de fin de temporización de 5 ms e de 500 ms, tras a excitación dos sinais de reset e de start. Para poder velo mellor, representaremos o resultado en dous anacos (un é un fragmento ampliado do outro):

a) Posta a un dos sinal de fin de temporización de 5ms:


b) Posta a un do sinal de fin de temporización de 500ms:


UNIDADE DE CONTROL DA INTERFACE

Por mor da natureza da aplicación e coa idea de poder optimizar o circuito, decidimos facer unha nova máquina de estados para que faga de unidade de control da interface co teclado matricial. Esto responde ás seguintes cuestións:

1)O sinal "pulsada" ha de permanecer a '1' todo o tempo que unha tecla estea pulsada no teclado, o que se pode implementar de maneira sinxela dende a máquina de estados.

2)Cando "pulsada" esté a '1' ten que haber un valor correcto en "fila(1:0)" e en "columna(1:0)", o que se produce cando o sinal "ce_key" estea a '1', que é unha das saídas da unidade de control.

3) Durante todo o tempo que se estea a pulsar unha das teclas ten que suceder o anteriormente descrito, cosa que a unidade de control anterior non facía, xa que ós 500 ms volvía facer unha nova exploración aínda que a mesma tecla seguira pulsada.

A máquina de estados implementada no ferramenta StateCad é a seguinte:

De cara á comprobación da mesma, onde se incluíu o sinal interno "sreg", que define o estado no que se encontra a FSM, estes son os resultados da simulación:

INTERFAZ CO TECLADO MATRICIAL DE 16 TECLAS

O esquemático final da interface co teclado é o seguinte (xa co divisor de frecuencia incluído):

A primeira instancia que se ve é o divisor de frecuencia usado para xerar o sinal de 1 kHz a partires do reloxo do sistema de 50 MHz e a outra instancia é a interfaz do teclado propiamente dita, con tódolos rexistros, máquina de estados, temporizador, ... necesarios para o funcionamento.

Da simulación temporal destacaremos dúas gráficas que amosan o bo funcionamento da interface, desde o punto de vista da exploración e das restriccións adicionais que lle engadimos ó sistema:

1) EXPLORACIÓN:
2) FUNCIONAMENTO:

lunes, 12 de mayo de 2008

Implementación dos osciladores

Aquí detallaremos as decisións fundamentales que tomamos no deseño dun oscilador. A implementación realizarase mediante un filtro IIR con 2 polos de módulo 1 á frecuencia a crear.

Partimos da transformada Z dun coseno que empeza na mostra 0 e de frecuencia discreta w:


x[n]=cos(w*n) <-----> X(z)=(1-cos(w)*z^(-1))/(1 -2*cos(w)*z^(-1) +z^(-2))


Se somos capaces de implementar un filtro con esta resposta ao impulso, entón, obteremos este sinal á saida se introducimos unha delta, que é o que queremos. Os coeficientes serán parámetros do filtro, dependentes da frecuencia a xenerar, e no caso de implementación hardware almacenarémolos nun rexistro antes de empezar a calcular as mostras.

A forma máis habitual de implementar un filtro de orde 2 emprega unha sección na forma trasposta da forma directa II, onde b0,b1 son os coeficientes do numerador e a0, a1 e a2 os do denominador:







No noso caso, debido a que b0=1, a0=1 e a2=1 simplifícase moito:

O funcionamento consistirá en introducir un impulso no filtro, que será equivalente a cargar os rexistros cuns determinados valores iniciais. Se nos olvidamos desto, o esquema resultante é moito máis compacto:


Ademáis, podemos aforrar un cambio de signo se sustituimos o sumador por un restador:


A estructura resultante é moi sinxela, seguramente moito máis que calquera ipcore da ferramenta de Xilinx. Agora somentes nos falta dimensionar a lonxitude dos rexistros, do multiplicador e do sumador.
En primeiro lugar sabemos que a saida do sistema deben ser 12 bits, xa que son os que emprega o convertidor DAC. Por outra banda sabemos que o número mínimo de bits do coeficiente 2cos(w) é de 11 para a parte fraccionaria (segundo o estudio que fixemos anteriormente) e de 2 para a parte enteira (xa que pode ser maior que 1 e empregamos complemento a 2). Para evitar pérdida de precisión operaremos internamente cun número de bits maior que 12, e á saida incluiremos un cuantificador que redondeará ao número de 12 bits máis próximo. O número de bits que empregaremos internamente denominarémolo, a partir de agora, lonxitude do bus, porque será a lonxitude dos rexistros e do bus da parte dereita da figura anterior.
Sabendo que as operacións de multiplicación incrementan o número de bits do resultado será necesario incluir un cuantificador á entrada do rexistro Z0 ( o de arriba).


Posto que a lonxitude do bus influirá no ruido de cuantificación de maneira inversa, e na área ocupada de maneira directa existe aquí un compromiso relación sinal a ruido-area. Debido a esto, e a que non temos restriccións ao respecto, a codificación en VHDL realizarase en función dunha constante para o número de bits do bus, o que permitirá elexir o valor máis conveniente con solo modificar esta constante e recompilar o código.
O filtro en cuestión deberá dotarse duns elementos auxiliares:
  1. Un rexistro no que se almacena o coeficiente -a1 (é dicir, 2cos(w)), para fixar este valor á entrada do multiplicador. Estrictamente non sería necesario, pero, de non existir, implicaría engadir restriccións á interface deste módulo co controlador do teclado.
  2. Unha memoria de 4 posicións na que almacenaremos os coeficientes correspondentes a cada unha das frecuencias a xenerar. Codificaranse como parámetros generic para poder instanciar un oscilador pra filas e outro pra columnas empregando o mesmo código.
  3. Un sumador que combina a saida de ambos osciladores, posto que temos que sacar a suma de dous tonos.
  4. A máquina de estados que se describiu anteriormente.

Debido ao reducido tamaño das memorias non nos plantexamos a súa implementación mediante BRAMs.

En canto á inicialización, diremos que a delta introducida terá amplitude 0.5 para evitar desbordamentos no sumador do punto 3, xa que extraeremos o resultado con 1 bit para a parte enteira. Ademais, realizando contas vemos que deberemos introducir cos(w) no rexistro Z0 e 0.5 no rexistro Z1, e non será necesario introducir (e almacenar na memoria) b0 no filtro, chegará con introducir (almacenar) cos(w) (recordemos que é constante para cada tecla pulsada) e desprazalo á esquerda para obter a1.





jueves, 8 de mayo de 2008

Creación do sinal

Plantéxase agora a implementación do bloque central da nosa arquitectura, un sistema que a partires dun valor para a columna e outro para a fila obterá unha mostra en cada
período de símbolo do sinal correspondente a xerar mentres a tecla estea pulsada.
Deberemos realizar tres accións máis elementais para conseguir esto, dada a información da que dispón o bloque:
  1. Detectar a pulsación e empezar a xerar o sinal
  2. Levar a conta do período de mostreo
  3. Obter o valor de cada mostra
Para a primeira tarefa introduciremos unha máquina de estados, que se encargará, ademais, de dar a orde de conversión ao controlador do convertidor. Para a segunda precisaremos un contador, que reducirá a frecuencia do oscilador de 50MHz da placa por un factor de 1000 aproximadamente, xa que a frecuencia de mostreo será de 50KHz. Finalmente, para o terceiro propósito será necesario un par de osciladores discretos e un sumador, que, a partir dunha orde da máquina de estados, produzan a seguinte mostra.

Ata este punto non se mencionou nada novo, o que restan son detalles de implementación.
A máquina de estados non ten segredo ningún: cando se pulsa unha tecla indica aos osciladores discretos de que poden realizar as inicializacións necesarias e a continuación introdúcese nun bucle que se executa unha vez para cada mostra, no que,en cada iteración, se lles da a orde de obter unha mostra e se comproba se a tecla segue pulsada. A continuación figura o diagrama de estados:





Aclaramos que o sinal seg_mostra levántase cando o contador acada certa cantidade precisada, neste caso será aproximadamente 1000. Este é o punto no que podemos xustificar a non existencia dun sinal busy que proceda do controlador do DAC, xa que o periodo de mostreo é o suficientemente longo como para que a transmisión serie ao DAC e a conversión finalicen antes da seguinte mostra. Esto simplifica a presente máquina de estados.

Sobre a conta do periodo de mostreo non son necesarias aclaracións: será un contador de 10 bits seguido dun combinacional que obteña o sinal seg_mostra.

Finalmente falaremos dos osciladores discretos, que constitúen o corazón de todo o sistema. Plantexámonos diversas opcións:
  1. Implementación mediante ipcore.
  2. Tabulacións e interpolacións.
  3. Creación dun módulo que realizara a función coseno mediante unha aproximación polinómica (Taylor) e outro que fose introducindo a fase instantánea.
  4. Emprego dun filtro IIR
Para cada unha das opcións, ademais, sería necesaria certa cantidade de memoria para almacenar coeficientes e demais parámetros.A continuación discutiremos cada unha das alternativas.
Pra comezar, descartamos os ipcores por diversas razóns, entre elas que non temos acceso á estructura interna/código, e polo tanto non podemos coñecer o seu grado de adecuación para a aplicación en cuestión, nin no que se refire a área, nin a velocidade. Ademais, sería evadir a verdadeira problemática deste proxecto, a parte mais complexa e que mais nos pode aportar.
As opcións 2 e 3 foron descartadas inicialmente pola necesidade de manter a fase instantánea, é dicir, sería preciso levar conta do número de mostra actual, para o que sería necesario un contador. O número de bits deste limitaría o tempo que podería producirse sinal, xa que ao desbordar produciríase unha discontinuidade no sinal de saida. Ademais acarrean un coste computacional elevado e unha necesidade grande de almacenamento en memoria de constantes.
Finalmente, a opción 4 foi a máis adecuada desde o noso punto de vista por diversas razóns:
  1. So se require do almacenamento dun coeficiente por cada tono a xerar.
  2. Emprega somentes un multiplicador e un restador, ademais de 2 rexistros.
  3. Un oscilador feito deste modo é a contraparte discreta dos osciladores senoidales analóxicos que empregan realimentación positiva, e deste xeito aprendemos a realizar osciladores que poidan ser útiles en sistemas máis complexos que funcionan en dixital.
  4. A nosa especialidade é a de comunicacións e escollemos esta asignatura para por en práctica os nosos coñecementos sobre teoría do sinal en FPGAs.

Na seguinte entrada desenvolveremos a implementación destes módulos de maneira detallada, así como a verificación na placa do sistema constituido por esta parte e o controlador do DAC.