PFC 2000
PFC 2000
PFC 2000
PROJECTE FI DE CARRERA
Autor:
Juan Luis Tébar Garcı́a
Tutor:
Josep Vidal Manzano
Profesor Titular del Dept. de Teoria del Senyal i Comunicacions
Universitat Politècnica de Catalunya
Barcelona, 2000
A mi única familia
Agradecimientos
Este Proyecto de Fin de Carrera no hubiera sido posible sin la ayuda de algunas personas
a quienes me gustarı́a expresar mi sincera gratitud.
Comenzaré este turno por mi familia, pues ellos han sido en gran parte los “cul-
pables” de que este trabajo haya visto la luz: A mis padres Eusebio y Emilia por sus
continuos ánimos, a mi hermano Eusebio por ser el responsable de mi reciclaje software, a
José Antonio y Marı́a José por su ayuda y soporte “hardware” en mis viajes a Barcelona,
y en general a todos por su cariño y apoyo moral.
También he de dar las gracias a mi tutor, Josep Vidal, por las facilidades y consejos
prestados a la hora de desarrollar este trabajo en la distancia. No puedo dejarme en el
tintero a mi amigo Cesar, quien con su inestimable ayuda tanto en el plano técnico como en
el anı́mico tiene parte del mérito de este trabajo. Gracias también a mi compañero Cesáreo
por su ayuda con los equipos de medida y a Garve por su apoyo con la mecanografı́a.
No puedo tampoco dejar de nombrar a mis amigos de siempre Avelino, Iñaki, Juan
Ernesto, Claudio y a sus familias por su paciencia conmigo a lo largo de tanto tiempo.
Barcelona
Septiembre del 2000 Juan Luis Tébar Garcı́a
i
Resumen
ii
Índice general
iii
1.10.1. Mejora del Margen Libre de Espúreos mediante dithering de fase . . 53
1.10.2. Generación de barridos “chirp” mediante DDS . . . . . . . . . . . . 55
1.10.3. Generación de modulación de amplitud mediante DDS . . . . . . . . 56
1.10.4. Funcionalidades adicionales en DDS . . . . . . . . . . . . . . . . . . 57
1.10.5. Chips DDS comerciales . . . . . . . . . . . . . . . . . . . . . . . . . 59
3. Medidas de calidad 76
3.1. La Recomendación G.821 ITU . . . . . . . . . . . . . . . . . . . . . . . . . 76
3.2. Asignación de los objetivos G.821 . . . . . . . . . . . . . . . . . . . . . . . . 79
3.3. Especificaciones G.821 para otras velocidades . . . . . . . . . . . . . . . . . 81
4. Modulador DDS 83
4.1. Especificaciones de la placa DDS . . . . . . . . . . . . . . . . . . . . . . . . 84
4.2. Diseño hardware de la placa DDS . . . . . . . . . . . . . . . . . . . . . . . . 87
4.2.1. El modulador AD9853 . . . . . . . . . . . . . . . . . . . . . . . . . . 87
4.2.1.1. Filtrado de datos (FIR + etapas interpoladoras) . . . . . . 91
4.2.2. Bloques funcionales de la placa DDS . . . . . . . . . . . . . . . . . . 97
4.2.2.1. Puerto paralelo de control . . . . . . . . . . . . . . . . . . . 98
4.2.2.2. Buffer de control y datos . . . . . . . . . . . . . . . . . . . 99
4.2.2.3. Modulador DDS . . . . . . . . . . . . . . . . . . . . . . . . 100
4.2.2.4. Generador de reloj de bit . . . . . . . . . . . . . . . . . . . 102
4.2.2.5. Oscilador de referencia . . . . . . . . . . . . . . . . . . . . 105
4.2.2.6. Salida de FI . . . . . . . . . . . . . . . . . . . . . . . . . . 106
4.2.2.7. Entrada-salida de datos . . . . . . . . . . . . . . . . . . . . 107
4.2.2.8. Alimentación . . . . . . . . . . . . . . . . . . . . . . . . . . 108
4.3. Software de control . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 109
4.3.1. Módulo principal mod.c . . . . . . . . . . . . . . . . . . . . . . . . . 109
4.3.1.1. Función ValorDiv . . . . . . . . . . . . . . . . . . . . . . . 111
4.3.1.2. Función ValorFirAx . . . . . . . . . . . . . . . . . . . . . . 112
iv
4.3.2. Módulo de funciones hardware mod hard.c . . . . . . . . . . . . . . 113
4.3.2.1. Función prog hard . . . . . . . . . . . . . . . . . . . . . . . 113
4.3.2.2. Función interpolador . . . . . . . . . . . . . . . . . . . . . 113
4.4. Resultados prácticos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 115
v
Índice de figuras
vi
1.39. Filtro IIR básico . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
1.40. Filtro IIR generalizado . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44
1.41. Interpolador básico . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
1.42. Visión en el dominio frecuencial de la interpolación . . . . . . . . . . . . . . 46
1.43. Decimador básico . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46
1.44. Visión en el dominio frecuencial de la decimación . . . . . . . . . . . . . . . 47
1.45. Convertidor de velocidad de muestreo n/m básico . . . . . . . . . . . . . . . 48
1.46. Etapas básicas de los bloques filtro peine e integrador . . . . . . . . . . . . 49
1.47. Respuesta en frecuencia de los bloques básicos del filtro peine y del integrador 49
1.48. CIC funcionando de interpolador y de decimador . . . . . . . . . . . . . . . 49
1.49. Respuesta en frecuencia del filtro CIC básico . . . . . . . . . . . . . . . . . 50
1.50. Variaciones al bloque CIC básico . . . . . . . . . . . . . . . . . . . . . . . . 51
1.51. Comparación de las respuestas CIC modificadas . . . . . . . . . . . . . . . . 51
1.52. Diagrama de bloques de un modulador DDS genérico . . . . . . . . . . . . . 52
1.53. Compresión de la memoria ROM . . . . . . . . . . . . . . . . . . . . . . . . 53
1.54. Diagrama de bloques de un DDS genérico . . . . . . . . . . . . . . . . . . . 54
1.55. Dithering de fase en un DDS . . . . . . . . . . . . . . . . . . . . . . . . . . 54
1.56. Sistema Chirp basado en DDS . . . . . . . . . . . . . . . . . . . . . . . . . 55
1.57. DDS con control de amplitud . . . . . . . . . . . . . . . . . . . . . . . . . . 56
1.58. Prestaciones añadidas en un sistema DDS . . . . . . . . . . . . . . . . . . . 57
1.59. Modulaciones de fase en un dispositivo DDS . . . . . . . . . . . . . . . . . . 58
vii
4.20. Medidas de salida realizadas con analizador vectorial HP89410A . . . . . . 116
4.21. Medidas de los espúreos de truncamiento de fase de salida . . . . . . . . . . 117
4.22. Medidas en banda ancha para QPSK con imágenes generadas por el proceso
de conversión D/A. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 118
4.23. Medidas en banda ancha para FSK sin filtro antialiasing . . . . . . . . . . . 118
4.24. Efecto del filtro antialiasing de salida. . . . . . . . . . . . . . . . . . . . . . 119
4.25. Espectro cercano para los tres tipos de modulaciones principales. . . . . . . 120
A.1. Conexionado externo para lectura de datos en el puerto paralelo del PC . . 148
A.2. Hardware interno del PC en puertos bidireccionales . . . . . . . . . . . . . . 152
A.3. Utilización particular del puerto paralelo en nuestra aplicación . . . . . . . 154
B.1. Vista general del montaje que contiene las placas DDS y BER . . . . . . . . 156
B.2. Vista interior donde se pueden distinguir las dos placas . . . . . . . . . . . 156
B.3. Vista lateral con los conectores de IF y de entrada/salida de datos . . . . . 157
B.4. Vista lateral con los conectores de control y alimentación . . . . . . . . . . 158
viii
Índice de cuadros
ix
Introducción
1
2
Organización de la memoria
El trabajo se ha organizado en dos partes principales:
Descripciones Teóricas.
Comprenden los 3 primeros capı́tulos, y en ellos se resumen los fundamentos teóricos
de aplicación en los dos montajes del trabajo.
El capı́tulo 1 es el principal componente de este bloque teórico. En él se comentan
los aspectos principales de las técnicas de sı́ntesis digital directa (DDS) haciendo
especial incapié en los procesos de conversión D/A [?]. Como complemento a la
descripción teórica, se ha realizado una labor de recopilación de datos y comparativa
entre algunos de los chips que implementan técnicas DDS de entre los principales
fabricantes [?].
A continuación, el capı́tulo 2 contiene una descripción particularmente interesante
de las caracterı́sticas matemáticas de las secuencias pseudoaleatorias recogidas prin-
cipalmente de [?]. Por último, en el capı́tulo 3 se recogen las precisiones principales
establecidas por la UIT para la realización de medidas de calidad en los enlaces de
datos, obtenidas de las recomendaciones [?] y [?].
Diseño Práctico.
La segunda mitad del trabajo comprende dos capı́tulos que constituyen la memoria
de las mismas aplicaciones prácticas. En ellos se comenta el funcionamiento indivi-
dual de cada circuito incluyendo esquemáticos, y también se hace una descripción
del software de control desarrollado para cada placa.
El capı́tulo 4 está dedicado a la placa PCB donde se ha montado un modulador DDS.
Se trata de un modulador digital QPSK, FSK y 16QAM, con un margen de frecuencia
de salida de hasta 65 Mhz y diversas funcionalidades integradas que se verán durante
su exposición. Entre estas, podemos destacar la inclusión dentro del chip DDS de un
filtro de datos FIR, que permite la realización de gran cantidad de caracterı́sticas de
filtrado en el dominio digital. La aplicación de control del modulador digital dispone
de una pantalla donde se pueden cambiar los coeficientes del filtro. Para servir de
ayuda en el cálculo de los mismos se realiza un ejercicio en Matlab de cálculo de los
coeficientes de un filtro FIR con una curva de respuesta en coseno alzado.
El capı́tulo 5 corresponde a la placa de circuito impreso donde se ha implementado
un generador de secuencias pseudoaleatorias. Este diseño, construido como apoyo de
la placa de modulación DDS, constituye por sı́ mismo un montaje independiente que
puede utilizarse por separado para la medida de tasa de bits erróneos. El programa de
control suministra información sobre los parámetros más importantes recomendados
por la UIT para la realización de medidas de calidad en enlaces. Entre ellos podemos
destacar el número de segundos con errores, los segundos severamente erróneos, y
por supuesto, la tasa de BER del canal bajo prueba.
Las secuencias generadas en la parte de transmisión de este circuito se utilizarán
como señal de información en la placa de modulación DDS sirviendo como trama
digital de entrada al mismo.
Durante la exposición de estos capı́tulos se presentan medidas variadas obtenidas
con diferentes equipos de laboratorio tales como analizador de espectros, analizador
vectorial y osciloscopio.
3
La Sı́ntesis Digital Directa (DDS) se puede definir como un medio de generar señales
a partir de representaciones digitales armónicamente puras y altamente precisas. Esta
representación digital es posteriormente reconstruida mediante un convertidor Digital-
Analógico de alta velocidad, para proporcionar una señal de salida analógica, tı́picamente
un tono sinusoidal o una secuencia de tonos. Como en estos dispositivos la señal se procesa
de forma digital, su generación es fácilmente configurable mediante software, haciendo más
amplia su gama de utilidades.
Actualmente se encuentran disponibles una amplia gama de DACs de altas presta-
ciones con los que se consiguen espúreos de potencia extremadamente baja a la salida del
conjunto DDS-DAC.
Las técnicas DDS ofrecen prestaciones únicas en contraste con los otros métodos
de sı́ntesis. Aunque se encuentran limitados por el criterio de Nyquist (hasta 1/2 de la
frecuencia del reloj aplicado como referencia), la técnica DDS permite un control en la
resolución de frecuencia del orden de milihertzios, al igual que con la resolución en fase,
donde es fácil obtener resoluciones de 0.02o en los dispositivos comerciales.
Adicionalmente, las técnicas DDS no imponen restricciones de tiempo de estableci-
miento (settling time) en cambios de frecuencia, salvo los requeridos por el control digital.
Como resultado se consiguen frecuencias de conmutación extremadamente elevadas, del
orden de nanosegundos.
Todos los cambios de frecuencia se realizan automáticamente sin discontinuidad
de fase. Como la señal se genera en el dominio digital, el proceso se puede manipular
con excepcional precisión. Esto permite un control preciso tanto de la fase como de la
frecuencia, consiguiéndose fácilmente las modulaciones PSK ó FSK.
Si se desea, un sistema controlado por microprocesador se puede utilizar para alma-
cenar datos de compensación de frecuencia en lazo abierto de un dispositivo particular o
de algún parámetro del sistema. El microprocesador puede controlar el DDS para corregir
de forma dinámica la frecuencia según se necesite. Con un detector de frecuencia adecuado
en un sistema de recepción, se puede construir fácilmente un sistema de lazo cerrado.
En resumen, podemos enumerar las ventajas de las técnicas DDS:
4
1.1 Teorı́a de operación 5
Eliminación de los problemas relacionados con los retoques y la sintonı́a fina manual
ocasionados por el envejecimiento de componentes y derivas de temperatura tı́picos
de los sintetizadores analógicos.
Control digital del sistema, con las ventajas que esto conlleva: posibilidad de control
remoto, ajuste optimizado, y cualquier aplicación que se nos pueda ocurrir bajo
control de un microprocesador.
Un DDS está formado básicamente por un contador de elevado número de bits que
direcciona una memoria ROM en la que se han almacenado los valores de amplitud de una
función del tipo seno o coseno. La salida de la memoria va directamente a un convertidor
D/A el cual transforma los “números” almacenados en la memoria en valores de tensión,
reconstruyendo ası́ la señal analógica.
El problema fundamental con esta arquitectura es que para cambiar la frecuencia
de salida es necesario cambiar la frecuencia de reloj, lo que es un método poco práctico.
Para evitar esto, se emplea una técnica hardware muy eficiente que se denomina Oscilador
Controlado Numéricamente (NCO). Un diagrama de bloques de esta técnica se puede ver
en la figura 1.1.
función seno. El acumulador de fase se utiliza para “direccionar” cada uno de los puntos
del cı́rculo y la palabra de sintonı́a M determina el salto del vector en cada pulso de
reloj. La resolución del acumulador N determina el número de puntos en que se divide la
“rueda”.
Para transformar la salida lineal del acumulador de fase en cualquier tipo de ampli-
tud, normalmente senoidal, se necesita una tabla de referencia, generalmente en memoria
ROM. Existen técnicas para ahorrar memoria en esta tabla, por ejemplo el explotar la si-
metrı́a de la forma de onda senoidal, de manera que sólo se guardan los valores de amplitud
correspondientes a 1/4 de ciclo y por medio de los 2 bits más significativos se determina
el cuadrante de situación: el más significativo directamente indica el signo de la amplitud
al DAC, mientras que el segundo determina la forma de recorrer la tabla de referencia.
El acumulador de fase es un contador módulo N que incrementa su valor cada vez
que recibe un pulso de reloj. La magnitud de ese incremento depende de la palabra de
sintonı́a M cargada en el “registro de incremento de fase”. Este registro es el que determina
la cantidad de puntos que se avanzan en cada salto de la rueda de fase. Por tanto si M = 1
la frecuencia del reloj de referencia se divide por 232 (continuando con el ejemplo anterior
de N = 32), si M = 2 por la mitad, y ası́ sucesivamente. De acuerdo con esto, la frecuencia
de salida vale:
1.2 Espectro de salida 7
M · fclk
Fout = (1.1)
2N
Ecuación conocida como de sintonı́a básica del NCO, siendo la resolución en fre-
cuencia:
fclock
∆f = (1.2)
2N
Como la resolución del convertidor D/A de salida está limitada a 12 ó 14 bits, la
salida del acumulador se trunca a los 13 - 15 bits más significativos. Esto reduce el tamaño
de la tabla de referencia y no afecta a la resolución en frecuencia. El truncamiento de fase
solamente añade una cierta cantidad de ruido de fase a la salida del circuito.
La resolución del convertidor D/A es tı́picamente 2 a 4 bits menor que el ancho de
la tabla de referencia, siendo los espúreos generados por el truncamiento del acumulador
inferiores a 90 dBc, [?] y [?], para el caso de emplear 15 bits en el acumulador, valor
superior a las prestaciones que ofrecen los mejores convertidores D/A.
Dado que por mucha resolución que quiera tener un DAC, ésta va a ser siempre
limitada, a su salida la señal siempre tendrá la forma de onda tı́pica con escalones de
amplitud equiespaciados un perı́odo de tiempo igual a la frecuencia de reloj del sistema,
que es la frecuencia a la que se actualiza.
Comparando las figuras 1.4 y 1.5, se puede deducir que la salida del convertidor
es equivalente al muestreo práctico instantáneo de la señal senoidal a reconstruir x(t),
por una señal muestreadora s(t) en forma de trenes de pulsos muestreadores p(t − nTs ),
llevando el caso al lı́mite en el que la duración del pulso es igual al periodo de muestreo;
en la figura corresponde al apartado (d).
El pulso muestreador y la señal muestreadora son:
Y t
∼
p(t) = (1.3)
Ts
1.2 Espectro de salida 8
X
s(t) = p(t − nTs ) (1.4)
n
resultando:
X
xsi (t) = x(nTs ) · p(t − nTs ) (1.5)
n
que es lo mismo que:
" #
X
xsi (t) = p(t) ∗ x(t) · δ(t − nTs ) (1.6)
n
Realizando la transformada de Fourier encontramos el espectro de salida:
1 X m
Xsi (f ) = · P (f ) · X(f − ) (1.7)
Ts m
Ts
como
sen(πf Ts )
P (f ) = Ts · (1.8)
πf Ts
resulta el espectro de salida de la señal generada por el convertidor D/A:
sen(πf Tclk ) X m
XDAC (f ) = · X(f − ) (1.9)
πf Tclk m
Tclk
1.2 Espectro de salida 9
Figura 1.6: Espectro resultante para los diferentes tipos de muestreo práctico
de Nyquist. Las arquitecturas DDS actuales incluyen un filtro con curva caracterı́stica
x/sen(x) que compensa esta caı́da, dejando la respuesta en amplitud a la salida del con-
vertidor A/D prácticamente plana (±0,1 dB) sobre un ancho de banda igual al 45 % de la
frecuencia de reloj, equivalente al 80 % de Nyquist.
Es de destacar la gran amplitud de la primera frecuencia imagen, que para valores
de frecuencia de salida cercanos a Nyquist puede tener niveles de amplitud muy similares
a la componente fundamental. Es preciso, por tanto, realizar un estudio del margen de
frecuencias útiles según la aplicación particular, y especificar un filtro antialiasing apro-
piado.
El resto de imperfecciones del sistema tales como errores de linealidad, energı́a de
glitches asociada al convertidor D/A, acoplamiento de la frecuencia de reloj, etc, no siguen
la curva de caı́da sen(x)/x, dependiendo en este caso del layout del circuito impreso, la
calidad de la fuente de alimentación, la calidad del reloj de referencia, etc. De estos efectos
se hablará en las secciones siguientes.
227
∆f = = 1Hz/25
232
Ahora sólo tenemos que calcular la palabra M de sintonı́a de frecuencia:
Fout = M · ∆f
1.3 Capacidad de sintonı́a en fase y frecuencia de los DDS 11
(a)
(b)
Existen dispositivos DDS con diversos registros adicionales que pueden programarse
con otras palabras de sintonı́a de frecuencia; el contenido de estos registros se ejecuta por
1.4 Efecto del DAC en sistemas DDS 12
Los convertidores D/A son los que marcan las prestaciones de los sistemas DDS.
Dado que el sistema trabaja con representaciones de señales en el dominio digital, por
tanto perfectas en teorı́a y sin fuentes de ruido alguno, de el bloque de conversión D/A va
1.4 Efecto del DAC en sistemas DDS 13
a depender en buena parte la calidad y el funcionamiento final del sistema. En esta sección
se van a analizar los distintos tipos de conversores existentes, sus prestaciones, problemas
prácticos, etc.
Resolución
1.4 Efecto del DAC en sistemas DDS 14
No linealidades
Un convertidor D/A no ideal introduce distorsión por varios motivos, entre los prin-
cipales que podemos citar están las no linealidades del amplificador de entrada, las di-
ferencias entre las fuentes de corriente y los impulsos que se producen al conmutar los
interruptores analógicos. Las dos primeras fuentes de distorsión son difı́ciles de cuantificar
y analizar, pues son parámetros intrı́nsecos del circuito.
El tercer problema es la generación de impulsos o “glitches”. Este efecto presenta la
máxima incidencia a mitad de escala, cuando se pasa del código 1000..00 al 0111..11, y por
tanto se deben conmutar todos los interruptores de corriente al mismo tiempo. En esta
situación, se producen impulsos por el desigual tiempo de conmutación de los interruptores
de corriente lo que produce la aparición de ruido dentro y fuera de la banda de trabajo
del conversor. Este proceso se repite con menor incidencia a 1/4, 1/8 de escala, etc.
(a) (b)
(a) (b)
q
ERRORRM S = √ (1.10)
12
ası́, para una señal sinusoidal tenemos que la relación señal ruido vale:
S
= 6,02N + 1,76dB (1.11)
N
donde “N” es el número de bits. Esta relación solamente es válida si el ruido es medido
en todo el ancho de banda de Nyquist, desde DC a fs /2.
Por ejemplo, un convertidor A/D de 8 bits exhibe un SQR de 49.92 dB. Una precisión
importante a la ecuación 1.11 es que en ella no se hace referencia a la situación frecuencial
de los espúreos ni a su amplitud individual, únicamente se calcula la potencia combinada
total de los mismos en relación a la componente fundamental.
Otro punto a considerar es que la SRQ definida en la ecuación 1.11 toma la amplitud
de salida de la componente fundamental como la del fondo de escala. Por tanto, cuando
tal situación no sea la real se empeorará un factor igual a:
medir de forma precisa la distorsión armónica se deben respetar una serie de normas para
asegurar que realmente se mide la distorsión del A/D. En primer lugar hay que elegir
adecuadamente la relación de frecuencias, y algunas veces inyectar una cierta cantidad de
ruido. Luego hay que tener en cuenta el número de muestras que se toman en la FFT,
pues estas marcan el nivel de ruido de la función. Este nivel vale:
M
GF F T = 10log (1.14)
2
siendo M el número de puntos, por tanto si por ejemplo M=4096, la ganancia de proceso
de la FFT serı́a de 33 dB, por lo que el ruido de la FFT estarı́a 33 dB por debajo del ruido
del conversor A/D.
En la figura 1.13 se puede ver detalladas los distintos parámetros que se usan para
caracterizar un conversor A/D de 12 bits.
Un conversor A/D real presenta una serie de fuentes de ruido y distorsión. En primer
lugar está el buffer de entrada que es un circuito de banda ancha que aporta ruido blanco y
no linealidades, y presenta un ancho de banda limitado. A continuación está el circuito de
muestreo y retención que introduce más no linealidades, limitaciones del ancho de banda
y “jitter”, por último el cuantificador del A/D introduce ruido de cuantificación y no
linealidades diferenciales.
De acuerdo a estas fuentes de error se emplean una serie de parámetros para carac-
terizar los conversores A/D:
Distorsión armónica.
Peor armónico.
Hay varias formas de medir la distorsión armónica de un A/D, pero todas ellas
emplean la FFT para medir dicho valor. Para medir este efecto se introduce al A/D una
señal 1 dB por debajo del fondo de escala y se mide la relación en dB de la señal con
respecto a el peor armónico, para saber el pero caso, o con respecto al valor cuadrático
medio de la suma de todos los armónicos para saber la distorsión armónica total.
La distorsión total más ruido es igual a la distorsión armónica total pero te-
niendo en cuenta el ruido de cuantificación.
La relación señal-ruido-distorsión es la relación entre el valor eficaz de la am-
plitud de la señal con respecto al valor cuadrático medio de todas las demás componentes
espectrales.
El número efectivo de bits se define (ENOB) como:
SIN AD − 1,76dB
EN OB = (1.15)
6,02
La relación señal ruido (S/N) sin armónicos se define como la relación entre el
valor RMS de la señal con respecto al valor medio de la suma de los cuadrados de todas
las demás componentes espectrales excluyendo los 5 primeros armónicos y la componente
contı́nua [?].
El ancho de banda analógico es el valor para el cual el espectro de un barrido
de entrada plano en frecuencia cae 3 dB.
El margen libre de espúreos (SFDR) es uno de las medidas más empleadas y
se define como el valor rms entre la componente principal y los picos de las componente
espúreas, medido sobre la primera ventana de Nyquist. Este valor depende de la amplitud
de la señal y se suele expresar en función del fondo de escala.
La distorsión de intermodulación de dos tonos es igual a la medida clásica en
cualquier circuito analógico. Se emplean dos señales cuya amplitud está 6 dB por debajo
del nivel de fondo de escala del A/D y se miden las componentes nf1 ± mf2 .
La relación de potencia de ruido (NPR) se emplea frecuentemente en los sis-
temas de múltiples por división en frecuencia (FDM). En estos sistemas los canales de voz
se multiplexan en bloques de 4 Khz para su transmisión, por lo que resulta importante
ver la influencia de los canales adyacentes sobre el de interés. Para realizar la medida se
inyecta ruido blanco al A/D y se filtra una banda de 4 Khz por medio de un filtro banda
eliminada, de forma que el ruido que aparece en esa banda es debido a la intermodulación
y distorsión del A/D, midiéndose la relación (NPR) entre el nivel de ruido de entrada y
el de la banda filtrada. Esta medida se puede ver en la figura 1.14.
1.4 Efecto del DAC en sistemas DDS 19
Flash.
Subrango.
Serie.
Figura 1.15: Relación S/N en función del “jitter” de apertura y del reloj de muestreo
amplifica y se aplica al segundo conversor Flash. Por último, la salida de los dos conversores
Flash se combina en una palabra binaria de 8 bits.
Esta técnica de conversión multietapa se puede extender a dos, tres o cuatro etapas
de forma que la precisión en bits puede llegar a ser de 12, 14 ó 16 bits. El tiempo de
conversión se multiplica por el número de etapas de que disponga el sistema, por lo tanto
un A/D de dos etapas y 12 bits tendrá un régimen de muestreo de 50 MSPS.
Por último los conversores Serie emplean una etapa por bit para realizar una con-
versión A/D, por tanto son equivalentes a conversores de subrango con un bit por etapa
y sin corrección de errores. La figura 1.17 muestra un conversor de este tipo.
tipos:
Flash: muy alta velocidad (500 MSPS), con baja resolución (8-9 bits) y elevada
distorsión (SFDR=-30 dBc)
Subrango: alta resolución (10-14 bits) con baja distorsión (SFDR= -60 dBc ) y alta
velocidad de operación (50 MSPS).
error. La equivalencia en grados es de 8.46o , 5.64o y 2.82o para los errores E1, E2 y E3
respectivamente.
A partir de ahı́ el patrón se repite periódicamente conforme el acumulador se incre-
menta a saltos de 6 en 6 posiciones en la circunferencia exterior a cada intervalo de reloj
del sistema.
Obviamente, estos errores de fase introducidos por el truncamiento de fase se tra-
ducirán en errores de amplitud durante el proceso de conversión fase-amplitud inherente
a todo dispositivo DDS. Estos errores son periódicos porque, independientemente de la
palabra de sintonı́a elegida, tras un número determinado de vueltas en la rueda de fase,
la fase de acumulador y la fase truncada coincidirán. Como los errores de amplitud son
periódicos en el tiempo, aparecen como lı́neas espectrales de frecuencia conocidos con el
nombre de espúreos por truncamiento de fase.
En [?] se determina que la magnitud y distribución de los espúreos por truncamiento
de fase dependen de tres factores:
2. Tamaño de la palabra de fase, es decir, el número de bits de fase después del trun-
camiento (P bits)
(a)
(b)
Figura 1.20: Relación del Truncamiento de fase con los espúreos generados
(a) Patrones de palabras de sintonı́a que provocan el máximo
nivel de espúreos
(b) Patrones de sintonı́a que provocan el mı́nimo nivel de
espúreos
1.5 Efecto del truncamiento del acumulador de fase 26
con un 1 en la posición de bit 2A−P −1 y ceros en el resto de los bits de menos peso nos
dan el truncamiento de fase con peor nivel de espúreos (−6,02P dBc).
El otro extremo se da en las palabras de sintonı́a que no producen espúreos algu-
nos. Son palabras de sintonı́a cuya parte “despreciada” es igual a cero. Formalmente son
aquellas que cumplen:
M CD(M, 2(A−P ) ) = 2A−P (1.20)
Para que esta ecuación se cumpla, el patrón de la palabra de sintonı́a debe ser el
del apartado (b) de la figura 1.20. Por tanto, las palabras de sintonı́a que no provocan
espúreos de truncamiento de fase se caracterizan por tener un 1 en la posición de bit 2A−P
y ceros en los restantes bits de menos peso. El resto de patrones de palabra de sintonı́a
provocan niveles intermedios de espureos.
ET W = T modulo 2B (1.22)
1.5 Efecto del truncamiento del acumulador de fase 27
por:
Hasta ahora, hemos analizado en las dos secciones anteriores las dos fuentes prin-
cipales de espúreos en un DDS, el ruido de cuantificación en el convertidor D/A y el
truncamiento de fase. Podemos enumerar otras fuentes adicionales de espúreos a la salida
de un sistema DDS:
(a)
(b)
supone que ésta cae dentro del ancho de banda de Nyquist), en realidad, el espectro de
salida consta de F0 y sus componentes de aliasing como se demostró en la sección 1.2.
También se puede ver el espectro resultante en un ejemplo para un tono sintetizado en la
figura 1.7.
La teorı́a de muestreo en banda base vigente en la generación DDS implica, como
ya se ha dicho, que la señal generada esté en la primera zona de Nyquist. Sin embargo,
siempre es necesario filtrar la salida del convertidor D/A, en primer lugar para eliminar
las componentes generadas fuera de esta zona, pero también para evitar el efecto nocivo de
cualquier señal o espúreo que caiga fuera del ancho de banda de Nyquist, ya que también
tendrán una imagen solapada dentro de esta zona. Por esta razón, un filtro anti-aliasing se
usa en casi todas las aplicaciones DDS. Las especificaciones de este filtro pueden limitar
el margen dinámico a determinadas frecuencias, como se puede ver en la figura 1.26. En
muchas aplicaciones no se emplea todo el ancho de banda de Nyquist por lo que el empleo
de este filtro no es tan riguroso, aunque en las aplicaciones basadas en DSP si se suele
aplicar este criterio.
Transición abrupta.
Respuesta plana en la banda de paso.
1.7 Consideraciones sobre el filtrado de salida 33
Los DDS de alta velocidad con DAC integrado proporcionan una salida en modo
corriente. Esta corriente se puede aplicar a cualquier carga resistiva, incluyendo un corto-
circuito, siempre que la tensión generada en el pin de salida referida a masa, no viole la
especificación de salida del DAC. Esta especificación es simplemente la tensión máxima
que el pin de salida del DAC aguanta. Las tensiones que superen los lı́mites provocarán
distorsión de salida del DAC de moderada a drástica. Normalmente, las salidas se termi-
nan a masa mediante una resistencia, aunque se pueden terminar a cualquier otra tensión
que no viole las especificaciones de operación del DAC. Por regla general la corriente de
salida se puede predefinir mediante una resistencia conectada a un pin especial.
Los convertidores D/A con salida de tensión se evitan en aplicaciones DDS debido
a que las pérdidas internas provocarı́an que la salida variara de acuerdo con la resistencia
de carga. Las salidas de alta impedancia suministran su corriente especificada con pocas
variaciones de salida a ó desde la carga siempre que no se sobrepasen las especificaciones
de tensión de salida. Los DACs con conmutadores de corriente generalmente son los que
exhiben mejores prestaciones a velocidades de reloj altas.
La especificación de resistencia de salida de un DDS/DAC es la impedancia combi-
nada de los dispositivos CMOS que forman los conmutadores y la circuiterı́a de la fuente
de corriente. Normalmente es tan alta (usualmente mayor de 100K), que su presencia
se puede ignorar y es la resistencia de carga elegida por el usuario la que determina la
impedancia de salida del sistema.
En DACs con salida de corriente de tipo unipolar, si la resistencia de carga está ter-
minada en masa, entonces los voltajes que se desarrollan en la resistencia variarán entre
0 y un valor extremo positivo o negativo (fondo de escala). Por el contrario, una corriente
bipolar desarrollará una tensión negativa en un extremo (0 de escala) y positiva en el otro
(fondo de escala). El punto medio entre los dos extremos suele ser 0 voltios.
¿En qué afecta el que la corriente sea unipolar? Primero, los puntos centrales de la
1.8 Caracterı́sticas de salida de los sistemas DDS 36
forma de onda senoidal de salida del DDS tendrán un offset de continua que estará en el
punto central del margen de fondo de escala. Esto puede ser importante cuando se aplica
la señal de salida a algún amplificador acoplado en continua para evitar que la componente
de continua provoque recortes en la forma de onda. Por otro lado, cuando se modula en
AM la salida utilizando la resistencia de control de corriente del DAC, la envolvente de la
modulación será asimétrica, asemejándose más a una salida pulsada, que a una portadora
modulada simétricamente.
transformador.
Otro beneficio del acoplamiento por transformador es el fenómeno del rechazo del
modo común. Si las salidas del DDS-DAC Iout A e Iout B contienen señales comunes o
idénticas tales como acoplamiento del reloj, componentes de la fuente de alimentación, y
otras señales espúreas, estas señales se pueden ver reducidas o eliminadas en el espectro de
salida por el acoplamiento del transformador. Si las señales idénticas están presentes en las
dos entradas del primario del transformador, entonces sus campos opuestos se cancelarán
uno a otro en algún grado. El grado de cancelación depende de la coincidencia del bobinado
del transformador además de la coincidencia de las señales “idénticas”.
Aquı́, g(n), g1 (n), g2 (n), sen(ωc nT ) y cos(ωc nT ) son secuencias de números. Los mul-
tiplicadores y sumadores son elementos lógicos. Su complejidad es función del número de
bits utilizados para representar las muestras de las formas de onda de entrada. Esto parece
fácil en teorı́a. Sin embargo, cuando se implementan en hardware, el número de elementos
de circuiterı́a puede crecer muy rápidamente. Por ejemplo, si las formas de onda digital se
representan como números de 8 bits, entonces se requieren multiplicadores y sumadores
capaces de manejar palabras de 8 bits. Por otra parte, si las señales digitales están repre-
sentadas por números flotantes de doble precisión (64 bits), entonces los multiplicadores
y sumadores se convierten en estructuras muy grandes.
Es en el entorno de los moduladores digitales dónde la tecnologı́a DDS se vuelve
más atractiva. Ello es debido a que un DDS genera directamente las series de números
que representan muestras de una onda senoidal o cosenoidal. Estructuras de moduladores
digitales basadas en DDS se muestran en la figura 1.34.
Un modulador DDS más realista se presenta en la figura 1.35. Con objeto de fa-
cilitar la exposición únicamente se muestra el modulador sinusoidal. La extensión a una
estructura de modulación en cuadratura es trivial.
A primera vista, el modulador DDS parece bastante simple. Sin embargo, existe
una serie de requerimientos que hacen que la modulación digital sea un poco más difı́cil
de implementar. Este requerimiento es que g(n) debe de ser una secuencia muestreada
a la misma frecuencia que la velocidad de muestreo del DDS. De lo contrario, la etapa
de multiplicación estarı́a multiplicando valores que hubiesen sido tomados en instantes de
tiempo completamente distintos.
Pongamos un ejemplo sencillo. Supongamos que la señal moduladora vale
g(n) = cos[2π(1khz)nT1 ]
donde T1 vale 0.25 ms. Por tanto, g(n) se puede describir como una señal de 1 Khz
muestreada a 4 Khz. Supongamos, también, que la salida del DDS es
DDS = cos[2π(3khz)nT2 ]
donde T2 es igual a 0.1 ms. Esto significa que la salida del DDS es una señal de
3khz muestreada a 10 Khz. En el modulador DDS, el valor de n (el ı́ndice de muestra)
del multiplicador es el mismo tanto para las entradas como para las salidas. Ası́, para un
valor especı́fico de n, digamos n = 10, el ı́ndice del tiempo para el DDS es nT2 , el cual
vale 1 ms. Claramente, nT1 6= nT2 (2.5 ms 6= 1 ms). Por tanto, en un ı́ndice de tiempo
n=10, el tiempo DDS es 1 ms mientras que el tiempo g(n) es 2.5 ms. La consecuencia es
que el resultado de salida del multiplicador g(n)cos(ωc nT ), no es lo que se espera que sea,
debido a que la referencia de tiempo de g(n) no es la misma que la de cos(ωc nT ).
El requerimiento de “coincidencia en la velocidad de muestreo” es la primera con-
sideración de diseño en un modulador digital. Si, en un sistema de modulación DDS, la
fuente de la señal g(n) opera a una velocidad de muestreo distinta a la del reloj DDS, se
deben de realizar los pasos necesarios para corregir esta discrepancia en velocidad. El di-
seño de un modulador DDS se convierte entonces en un ejercicio de procesamiento digital
de señal multimuestreo. Este tipo de procesado requiere un conocimiento de las técnicas
implicadas de interpolación y decimado. Sin embargo, la interpolación y el decimado re-
quieren algún conocimiento de filtros digitales. De todo ello hablaremos en las siguientes
secciones.
H(z) = a0 + a1 z −1
donde z = ejω , ω = 2πf /Fs y Fs es la frecuencia de muestreo.
Ahora apliquemos algunos números a nuestro ejemplo para hacer las cosas un poco
más visuales. Supongamos que empleamos una velocidad de muestreo de 10 khz y utili-
zamos a0 = a1 = 0,5. La representación de H(z) en función de la frecuencia resulta en la
figura 1.37.
Claramente, esto constituye una respuesta del tipo paso bajo. En la figura sólo se
representa el ancho de banda de Nyquist por la caracterı́stica de simetrı́a en la banda de
fs /2 a fs .
El comportamiento de un filtro FIR es fácil de analizar si se calcula su respuesta
impulsiva. Su calculo se realiza de forma similar al equivalente analógico. En este caso, la
1.9 Modulación digital con DDS 42
temporal es:
resultando una ecuación de transferencia H(z), para un filtro FIR multietapa de N coefi-
cientes de realimentación:
La parte de la izquierda es una copia exacta de un filtro FIR; esta porción del IIR se
conoce normalmente como la sección “feedforward”. La porción de la derecha es la sección
de realimentación “feedback”. La realimentación es una versión retardada y escalada de
la señal de salida y(n), y todo ello se suma con la salida de la sección feedforward. La
existencia de realimentación en un filtro IIR supone una diferencia sustancial en el com-
portamiento del filtro. Como en cualquier sistema realimentado, la estabilidad se convierte
en un asunto importante. La elección inadecuada de los coeficientes o un desconocimiento
de la señal de entrada pueden provocar inestabilidades en un IIR. El resultado puede ser
oscilaciones o distorsión severa de la señal de salida. El problema de la estabilidad puede
ser suficiente para excluir el uso de un IIR en ciertas aplicaciones.
El ejercicio de cálculo de la respuesta impulsiva realizado para el filtro FIR anterior
puede servirnos de ayuda para examinar el comportamiento del IIR. El comportamiento de
la parte izquierda es exactamente idéntico, esto es, después de n muestras su salida será 0.
La diferencia reside en el bloque de realimentación de la derecha. Cada nuevo instante
de muestreo modifica el valor de y(n) con el valor anterior de y(n) recursivamente. El
resultado es que y(n) continua sacando valores indefinidamente, incluso aunque la señal
de entrada haya desaparecido. Ası́, un impulso único a la entrada puede resultar en una
secuencia infinita de impulsos a la salida. De aquı́ el nombre, filtro de respuesta al impulso
infinita.
Aún ası́, el concepto infinito es un ideal en la práctica. Los filtros IIR solo pueden
ser implementados con una cantidad finita de resolución numérica. Por ejemplo, en apli-
caciones dónde el camino de datos se debe restringir, digamos a palabras de 16 bits, los
valores muy pequeños serán redondeados a un valor de 0. Esto lleva a que el funciona-
miento del IIR se desvı́e del ideal. Un filtro IIR ideal continuarı́a infinitamente su salida
1.9 Modulación digital con DDS 44
cuya función de transferencia general, H(z) resulta ser, para un filtro IIR multietapa de N
coeficientes de realimentación hacia delante y M coeficientes de feedback:
a0 + a1 z −1 + a2 z −2 + . . . + aN −1 z −(N −1)
H(z) = (1.30)
1 − b1 z −1 − b2 z −2 − . . . − bM z −M
1.9.3.1. Interpolación
El problema del ejemplo es un caso de interpolación. La función de un interpolador
es tomar datos que fueron muestreados a una velocidad y convertirlos en nuevos datos
muestreados a otra velocidad mas alta. Los datos deben de ser modificados de tal modo que
cuando se muestreen a mayor velocidad se preserve la señal original. Una representación
gráfica del proceso de interpolación se muestra en la figura 1.41.
Se pueden distinguir dos procesos separados: una sección de entrada que muestrea a
una velocidad Fs y una sección de salida que muestrea a otra velocidad nFs dónde n es un
número entero positivo mayor de 1. La estructura de un interpolador básico indica que para
cualquier muestra de entrada habrá n muestras de salida. Esto nos plantea la pregunta:
¿qué debemos de hacer a los datos originales de manera que, cuando se muestreen a una
velocidad más alta, la señal original quede preservada?.
Se podrı́a razonar intuitivamente que, si se insertan n − 1 ceros entre cada una de
las muestras de entrada, (zero stuffing), entonces el dato de salida tendrı́a la caracterı́stica
deseada. Después de todo, añadir nada (0) a algo, no deberı́a cambiarlo. Es un buen punto
de partida, aunque todavı́a nos faltarı́a algo más para completar el cuadro.
Tal y como se aprecia en la figura 1.42, que es un ejemplo para un factor de interpo-
lación de 3, el proceso de interpolación genera réplicas del espectro de la señal original que
ahora caen dentro del nuevo ancho de banda de Nyquist, 3 veces mayor. Es decir, que para
que la señal interpolada mantenga las propiedades de la señal original, es preciso realizar
un filtrado pasobajo a posteriori, que elimine esas componentes “réplicas”. Lo normal es
realizarlo mediante un filtro FIR en el dominio digital.
1.9 Modulación digital con DDS 46
1.9.3.2. Decimado
En este caso la función del decimado es la opuesta a la de la interpolación: datos que
fueron adquiridos a una velocidad de muestreo Fs1 se vuelven a muestrear a otra velocidad
menor submúltiplo entero de la original Fs2 = Fs1 /m.
La figura 1.43 muestra el esquema de un decimador simple, con m un entero igual
a la relación entre las dos frecuencias de muestreo. De nuevo se nos plantea la misma
cuestión que en el apartado anterior: ¿cómo se deben de manipular los datos originales
para que tomándolos a una velocidad menor no se cambien las caracterı́sticas originales
de la señal?
Se podrı́a pensar que tomando las muestras m-ésimas de la trama original y despre-
ciando las demás, la señal resultante de salida tendrı́a las mismas propiedades. La idea es
buena pero todavı́a no tendrı́amos toda la solución. Observemos la figura 1.44, donde de
nuevo se utiliza un ejemplo sencillo en el que la relación entre las frecuencias de muestreo
es 3.
En este caso, al ser la frecuencia de muestreo de salida 3 veces menor a la de entrada,
1.9 Modulación digital con DDS 47
el criterio de Nyquist cambia y se hace más restrictivo. Para evitar el aliasing en la señal
de salida, es preciso asegurarnos de que la señal de entrada al interpolador cumpla con el
criterio de Nyquist en el nuevo marco de salida, es decir, en un ancho de banda de Nyquist
3 veces menor al de la señal original.
Esto nos lleva a la regla clave de la decimación: El ancho de banda de los datos
antes de la decimación debe de confinarse al ancho de banda de Nyquist de la velocidad de
muestreo menor de salida. Ası́, para un factor de decimación de m, la información original
debe de residir en un ancho de banda dado por Fs1 /(2m), con Fs1 igual a la velocidad
original de muestreo. Si los datos originales contienen información válida en la porción del
espectro más allá de Fs1 /(2m), el decimado no es posible. Este serı́a el caso del ejemplo,
si la porción del espectro de los datos originales más allá de Fs1 /6 de la figura 1.44 fuese
parte integrante de la señal de información en lugar de ruido o señales interferentes.
El filtrado pasobajo previo de la trama digital a decimar se suele realizar, al igual que
en el caso de la interpolación, mediante filtros FIR. El paso siguiente consiste en “sacar”
cada muestra m-ésima utilizando la velocidad de muestreo menor de salida. El resultado
se puede ver en la figura 1.44 (c).
Figura 1.47: Respuesta en frecuencia de los bloques básicos del filtro peine y del integrador
(a)
(b)
Las retos más obvios de un DDS son la velocidad (ancho de banda) y la pureza es-
pectral. Ambos están relacionadas inversamente, mientras que ancho de banda y consumo
lo están de forma directa. Cuanto más densa es la circuiterı́a, más precisa es la forma
de onda de salida y se suprimen más los espúreos, pero la circuiterı́a adicional limita la
velocidad y de aquı́ el ancho de banda, etc. Otros factores son a menudo importantes,
1.10 Evolución y técnicas auxiliares en los DDS 53
(a)
(b)
del margen deseado de la palabra de P bits de salida del acumulador. El número aleatorio se
posiciona de forma que su bit más significativo sea menor que el bit menos significativo de
la palabra de A bits de entrada al convertidor angulo-amplitud (AAC). No se recomienda
desplazar el número aleatorio de forma que se superponga a la palabra de A bits. Hacer
esto desecha el propósito de tener A bits de resolución de fase en primer lugar, ya que ello
añade un ruido que es mayor al ruido de cuantificación asociado a la palabra de A bits.
La posición de la palabra de R bits tiene impacto significativo en la magnitud del
dithering de fase. En efecto, el desplazar a la izquierda el número aleatorio incrementa
su impacto cuando se suma con la palabra de P bits tomada a la salida del acumulador.
Tı́picamente, el bit mas significativo del número aleatorio se posiciona un bit menos del
bit menos significativo de la palabra de A bits que se envı́a al AAC.
El número de bits del número aleatorio determina el modo en el que la fase aleatoria
se disgrega en el espectro de salida del DDS. Tı́picamente, un número aleatorio de 3 a 4
bits es suficiente.
DDS, mientras que para el valor de 1 la salida es la indicada desde el conversor AAC. Se ve
que es una manera inmediata de generar señales AM, también de controlar el transitorio
ON-OFF en señales pulsadas.
(a)
(b)
Acumulador de fase después del sumador, que permite retardos de fase dependiendo
de una palabra de sintonı́a de fase. De este modo se consiguen modulaciones de
fase, con una resolución que depende de los bits de la palabra de sintonı́a de fase.
Tı́picamente se utilizan registros de 14 bits, aunque pueden llegarse a utilizar 32
bits, con lo que la resolución de fase es enorme, figura 1.59 (a).
(a)
(b)
Bloque sinc inverso. Compensa la caı́da sinx/x producida por la curva de respuesta
de la salida cuantificada del DAC minimizando este efecto.
Comparador adicional, que facilita el uso del dispositivo DDS como generador de
reloj, convirtiendo la senoide del DDS en una forma de onda cuadrada.
Terminamos el capı́tulo con una tabla donde se incluye una recopilación realizada
en internet sobre los últimos dispositivos DDS del mercado. Son circuitos de las marcas
Analog Devices, Harris Semiconductor, Qualcom y Standford Telecom.
En cada entrada de la tabla se incluyen las caracterı́sticas fundamentales de cada
circuito, que pueden servir de comparación con el resto de los integrados.
1.10 Evolución y técnicas auxiliares en los DDS 60
1
Qualcomm, http://www.qualcomm.com
2
DAC no incluido en el chip
3
Analog Devices, http://www.analog.com/
4
Harris, http://www.harris.com/
5
Standford Telecom, http://www.stelhq.com/
1.10 Evolución y técnicas auxiliares en los DDS 61
Secuencias pseudoaleatorias y
registros de desplazamiento
1. Cifrado: Se realiza la suma en módulo 2 del mensaje binario con una secuen-
cia generada en un registro de desplazamiento que actúa como “llave”. Para
descifrar se vuelve a sumar la llave al mensaje codificado.
2. Códigos de direcciones múltiples: Diferentes porciones de una secuencia gene-
rada en un registro de desplazamiento se pueden asignar como dirección carac-
terı́stica de un gran número de elementos, estaciones, aeronaves, nodos de red,
etc. Se consigue que un gran número de generadores puedan enviar información
sistemáticamente a su controlador.
62
2.1 Secuencias con propiedades de aleatoriedad 63
donde Z T0 /2
1
K= x2 (t)dt (2.2)
T0 −T0 /2
numero de coincidencias menos numero de desacuerdos
1 comparando un periodo completo de la secuencia con
Rx (τ ) = · (2.3)
p una versión desplazada de la misma un numero τ de
desplazamientos cı́clicos
el sumador a la entrada del registro. El sumador módulo dos puede ser implementado
mediante una puerta or-exclusiva. La operación del registro de desplazamiento se controla
mediante los pulsos de reloj que no aparecen en la figura. En cada pulso de reloj los con-
tenidos de cada etapa del registro se desplazan una etapa a la derecha. También, a cada
pulso de reloj los contenidos de las etapas x3 y x4 se suman módulo 2 (una operación
lineal), y el resultado es llevado de nuevo hacia atrás a la etapa x1 .
Prestemos atención a la sucesión de estados de una etapa, por ejemplo la primera.
Supongamos que la historia del registro está formada por los sucesivos términos a0 , a1 ,
a2 , . . . , an . Desde el punto de vista de la realimentación, an es una suma módulo 2 de los
contenidos de varias etapas del registro en el estado n − 1. De hecho cada registro en la
suma módulo 2 que calcula an se puede tracear hacia atrás hasta llegar a un estado previo
de la primera etapa del registro en sı́. Por tanto, an satisface una ecuación del tipo:
Siguiendo con el ejemplo de la figura 2.1 asumamos que la etapa x1 está inicialmente
a uno y las restantes a cero, esto es, el estado inicial del registro es 1000. De la figura 2.1
podemos ver que la sucesión de estados en las etapas del registro serán las siguientes:
Como el último estado, 1000, se corresponde con el inicial, vemos que el registro
repite la secuencia anterior después de 15 ciclos de reloj. Se han generado todos los estados
posibles exceptuando el 0000. La secuencia de estados de la primera etapa es la siguiente:
100110101111000
an = an−3 + an−4
2.2 Secuencias generadas mediante registros de desplazamiento 66
000100110101111
100010011010111
dccddcdcddddccc
Los dı́gitos coincidentes están etiquetados con una ç”, mientras que con una ”d”se
indican los desacuerdos. Según la ecuación 2.3 el valor de la función de autocorrelación
para este desplazamiento simple de un chip es:
1 1
R(τ = 1) = (7 − 8) = −
15 15
Cualquier desplazamiento cı́clico que difiera de la coincidencia completa resulta tener
el mismo valor de autocorrelación, −1/p. De aquı́ que la secuencia cumple la tercera
propiedad de aleatoriedad.
∞
X
G(x) = an xn (2.4)
n=0
El estado inicial del registro de desplazamiento se puede considerar como
se realimenta al sumador módulo 2 (figura 2.1). También conviene recordar que la resta
en aritmética módulo 2 equivale a la suma.
1
= (a0 + a1 x + · · · + ap−1 xp−1 ) + xp (a0 + a1 x + · · · + ap−1 xp−1 )
f (x)
+x2p (a0 + a1 x + · · · + ap−1 xp−1 ) + . . .
= (a0 + a1 x + · · · + ap−1 xp−1 )(1 + xp + x2p + x3p + . . . )
= (a0 + a1 x + · · · + ap−1 xp−1 )/(1 − xp )
Por tanto:
Según 2.6, G(x) = g(x)/f (x), donde el numerador g(x) tiene un grado menos que
f (x). Si el registro de desplazamiento está aprovechando el hecho de que tiene r etapas,
entonces f (x) tiene grado r, y no se pierde la generalidad si se supone que siempre es éste el
caso. Si g(x) no tiene factores en común con f (x), entonces se sigue cumpliendo el teorema
demostrado anteriormente y el número entero menor p tal que f (x) divide a 1 − xp , es el
perı́odo de la correspondiente secuencia. Al número p se le conoce como exponente de Fax.
El caso particular de la demostración corresponde a g(x) = 1. Otro caso muy importante
se da cuando f (x) es irreducible, en cuyo caso no puede tener factores en común con
g(x), un polinomio de grado más bajo, a no ser que g(x) = 0, que corresponde a unas
condiciones iniciales “todo ceros”. Por lo tanto, cuando f (x) es irreducible, el periodo
de la secuencia del registro de desplazamiento no depende de las condiciones iniciales,
exceptuando únicamente el caso de la condición inicial “todo ceros”.
uno seguido de r − 1 ceros, que constituyen las condiciones iniciales con las que se obtuvo
el polinomio caracterı́stico del registro de desplazamiento. Consecuentemente se cumple
que el perı́odo de la secuencia A es el exponente de f (x). Por reducción al absurdo se
demuestra que no puede cumplirse el que la secuencia sea de longitud máxima si se diera
el caso de que f (x) fuese reducible y tuviera dos factores de la forma f (x) = s(x)t(x),
alcanzándose en este caso una longitud de secuencia menor a 2r − 1.
Tampoco se cumple el recı́proco, es decir, el hecho de que el polinomio caracterı́stico
f (x) sea irreducible no es condición suficiente para establecer que la secuencia sea de
longitud máxima: Por ejemplo, f (x) = x4 + x3 + x2 + x + 1 es irreducible, pero como
divide a 1 − x5 , la secuencia que genera es de periodo 5, en lugar del periodo máximo
24 − 1 = 15. De la misma manera, f (x) = x6 + x3 + 1 es irreducible, pero tiene exponente
9 en vez de 63.
cr 0 0 . . . 0
con unos a lo largo de la diagonal justo encima de la diagonal principal, y los “coeficientes
de realimentación.en la primera columna. Realicemos una verificación explı́cita:
c1 1 0 ... 0
c2 0 1 0
(an−1 , an−2 , . . . , an−r ) .. .. . . ..
. . 1
. .
cr 0 0 . . . 0
= (c1 an−1 + c2 an−2 + · · · + cr an−r , an−1 , an−2 , . . . , an−r+1 )
= (an , an−1 , . . . , an−r+1 )
c1 − λ 1 0 ··· 0
c2
−λ 1 · · · 0
f (λ) = det|M − λI| = c3 0 −λ · · · 0
.. .. .. ..
. . . .
cr 0 0 −λ
h c 1 c2 c 3 cr i
= −(−λ)r 1 − − 2 − 3 − ··· − r
λ λ λ λ
(−1)r+1
1 − (c1 x + c2 x2 + · · · + cr xr )
= r
x
donde se ha realizado la sustitución x = 1/λ. Se puede apreciar que exceptuando el
término(−1)r+1 /xr , la ecuación caracterı́stica de la matriz M es el polinomio caracterı́stico
del registro de desplazamiento.
En este caso, determinar el periodo del registro de desplazamiento equivale, excepto
en casos degenerados, a encontrar la potencia más baja p de la matriz equivalente M tal
que M p = I, la matriz identidad.
La teorı́a de matrices establece que toda matriz cumple su ecuación caracterı́stica:
por tanto f (M ) = 0. Si f (x) divide a 1 − xp , entonces M es una raı́z de I − X p , ya que es
raı́z del factor f (X) = 0. Esto es, si f (x) divide a 1 − xp , entonces M p = I. A la inversa,
si f (x) es irreducible, entonces divide todo polinomio que tenga la raı́z M en común con
él, y dividirá a 1 − xp si M p = I.
algunos textos también llamados polinomios primitivos) de grado r. Estas fórmulas están
constituidas a partir de dos funciones utilizadas usualmente en teorı́a de números y se
definen en esta sección.
Por el teorema de factorización única de aritmética, todo entero n > 1 se puede
descomponer en factores primos,
k
Y
n= pαi i (2.12)
i=1
1X d 8
ψ2 (8) = 2 µ( ) = 30
8 d
d|8
φ(2r − 1)
λ2 (r) = (2.16)
r
Por ejemplo, el número de polinomios primitivos de grado 8 es
φ(255) φ(3,5,17) 2 · 4 · 16
λ2 (8) = = = = 16
8 8 8
Por tanto, en este caso, la mitad de los polinomios irreducibles tienen máximo ex-
ponente. Sin embargo, cuando 2r − 1 es primo, ψ2 (r) = λ2 (r) = (2r − 2)/r.
También se ha tabulado λ2 (r) en 2.3.
2.4 Aleatoriedad de las secuencias de registros de desplazamiento 73
⊕ 1 0 × -1 1
1 0 1 -1 1 -1 (2.17)
0 1 0 1 -1 1
Como Ai + Aj = Ak , ahora Bi Bj = Bk , donde el producto Bi Bj también se toma
término a término. También se cumple (con la excepción de Bk = B0 = {1, 1, 1, . . .}, que
sólo ocurre cuando i = j), que Bk contiene (p − 1)/2 unos y (p + 1)/2 menos unos, por la
propiedad de balance y pertenecer al grupo Abeliano.
La función de autocorrelación ya se enunció en el apartado 2.1.1 pero se repite
particularizada para las secuencias {bn } a continuación:
p
(
1X 1 si τ = 0
Rb (τ ) = bn bn+τ = (2.18)
p −1/p si 0 < τ < p,
n=1
ya que {bn bn+τ } es una secuencia del tipo Bi · Bj , y por tanto también es del tipo
Bk . Entonces, el exceso de +1 con respecto a −1 es p para B0 , y -1 en cualquier otro caso.
De aquı́ se puede establecer que todas las secuencias generadas en registros de des-
plazamiento de longitud máxima cumplen la tercera propiedad de aleatoriedad.
2.5. Resumen
En este capı́tulo se han enunciado las propiedades que cumplen las secuencias bina-
rias consideradas pseudoaleatorias. Se ha visto que un método muy sencillo de generarlas
consiste en utilizar un registro de desplazamiento con realimentación módulo 2.
Las secuencias generadas en registros de desplazamiento satisfacen una relación de
recurrencia lineal an = ri=1 ci an−i , donde los coeficientes ci valen 0 ó 1 en función de si la
P
etapa i está o no implicada en la realimentación.PA partir de esta relación de recurrencia se
deduce el polinomio caracterı́stico f (x) = 1 − ri=1 ci xi , cuyas propiedades matemáticas
determinan el comportamiento de la secuencia. En concreto, se demuestra que el periodo
de la secuencia es el menor entero positivo p para el que se cumple que 1 − xp es divisible
por f (x).
Según términos de teorı́a elemental de números, se enuncian las formulas explı́citas
que determinan el número de polinomios irreducibles de grado r, y el número de polinomios
primitivos, también llamados de máximo exponente, de grado r. Este número coincide
únicamente si 2r − 1 resulta ser un número primo. El número de polinomios irreducibles es
ligeramente menor a 2r /r (asintóticamente igual), y el número de polinomios primitivos
es del mismo orden de magnitud.
Por último, se ha demostrado que las secuencias generadas a partir de polinomios
primitivos satisfacen las tres caracterı́sticas básicas de aleatoriedad.
La referencia [?] constituye una recopilación excelente sobre el tema. En ella se
pueden encontrar diversos procedimientos para encontrar polinomios primitivos, aunque
dada su extensión no se pueden incluir en este trabajo.
Capı́tulo 3
Medidas de calidad
76
3.1 La Recomendación G.821 ITU 77
gundos sucesivos en los cuales la relación de errores de bit ha sido mejor de 10−3 . De la
misma manera que en el caso anterior, los 10 segundos serán parte del tiempo disponible.
Una indicación gráfica de los dos cambios de estado se muestra en la figura 3.1.
La figura 3.2 pone de manifiesto cómo se deben considerar los dos sentidos de un
enlace a la hora de realizar la medida de calidad del mismo en lo que se refiere a tiempos
de disponibilidad. Como se podrı́a deducir fácilmente, el enlace está fuera de servicio o en
periodo de tiempo no disponible cuando alguno de los dos sentidos lo esté.
Los parámetros de servicio son calculados y clasificados sólo para el tiempo dis-
ponible. Esto significa que cuando se realicen las mediciones de servicio es importante
comprobar cuánto tiempo ha sido clasificado como tiempo no disponible.
En el tiempo disponible se usan diferentes términos para definir el nivel de degra-
dación en el enlace. Los términos son los siguientes:
Segundo Erróneo (SE, en inglés ES): Un segundo en tiempo disponible en el cual se
produce al menos un error en un bit.
Segundo Severamente Erróneo (SSE, en inglés SES): Un segundo en tiempo disponi-
ble con una relación de bits erróneos superior a 10−3 , o un segundo en el cual se ha
detectado un alarma.
3.1 La Recomendación G.821 ITU 78
Minuto Degradado (MD, inglés DM): Un minuto en tiempo disponible con una propor-
ción de bits erróneos superior a 10−6 , en la cual los segundos severamente erróneos
son excluidos del tiempo disponible y el resto del tiempo es dividido en bloques de
60 segundos.
Un bloque es un minuto degradado si la proporción de bits erróneos es superior a
10−6 .
de los minutos degradados. Los segundos severamente erróneos son excluidos del tiempo
disponible y la proporción de bits erróneos del tiempo restante es entonces la proporción
residual de bits erróneos.
De todas maneras, a la vista de comparaciones realizadas con otros equipos profe-
sionales de medida de BER, y por coherencia con la filosofı́a adoptada en ellos, no han
sido tomadas en cuenta estas últimas precisiones de la norma acerca de la tasa de BER
residual. Es una medida más realista el tener en cuenta todos y cada uno de los errores,
incluidos los que provocan las conmutaciones de redundancia porque al fin y al cabo, si
dichas conmutaciones se producen, y de hecho ocurre en la práctica, los enlaces y comu-
nicaciones afectados se verán perjudicados por ellas. En tal caso, ¿por qué no van a ser
tenidos en cuenta estos errores en el momento de las mediciones?.
Los segundos erróneos y minutos degradados son asignados a los diferentes grados,
de manera que al grado local le es permitido el 15 % de los objetivos en cada extremo, al
grado medio, el 15 % de los objetivos en cada extremo, y al grado alto, el 40 % restante de
los objetivos.
La asignación de segundos severamente erróneos está basada en un principio dife-
rente. El objetivo total es 0.2 %, y el 0.1 % es asignado a las tres clasificaciones de circuitos
en las mismas relaciones que para los segundos erróneos y los minutos degradados. Esto
da la siguiente distribución:
3.2 Asignación de los objetivos G.821 80
servicio defectuoso del sistema no asegura que el objetivo de calidad se cumpla según el
criterio de la recomendación G.821 a nivel de canal telefónico de 64 kbit/s.
Capı́tulo 4
Modulador DDS
83
4.1 Especificaciones de la placa DDS 84
Modo de trabajo:
La trama de datos a transmitir debe cumplir la condición de ser una fracción par
de la frecuencia del reloj del sistema además de estar sincronizada con él.
Alimentación
Control
1. Frecuencia de salida.
2. Tipo de modulación seleccionada.
3. Estado de activación del aleatorizador y del codificador diferencial.
4. Indicación de la velocidad de transmisión en bps.
la conformación del pulso de salida. Es el caso, por ejemplo, de las conocidas respuestas
en coseno alzado, que eliminan los lóbulos laterales del espectro de salida. Tratándose de
señales en el dominio digital, la manera más cómoda y fiable de sintetizar este filtro con-
formador es mediante una topologı́a del tipo FIR. En el esquema de bloques del AD9853
encontramos en el camino de las tramas I y Q otros elementos poco conocidos llamados
“filtros de interpolación” a continuación de los filtros FIR. Su función resulta imprescin-
dible para el correcto funcionamiento del sistema por lo que se tratarán con un poco más
de detalle en el siguiente apartado.
Para completar el gráfico nos quedarı́an otros cuatro bloques que añaden valor al
sistema, pero que podrı́an no estar dentro del integrado sin que ello supusiera la pérdida
de mérito del circuito. El verdadero mérito consiste en reunir todos los componentes del
proceso de generación de la señal incluyendo un DAC que trabaja a 180 Mhz y 10 bits de
precisión.
Volviendo al hilo de la exposición, el primer módulo que encontramos siguiendo
la ruta de la trama de datos es un codificador Reed-Salomon. La codificación de Reed-
Solomon es un tipo de codificación cı́clica especialmente útil en la corrección de errores
a ráfagas, es decir, es efectiva en canales que tienen memoria. Las referencias [?] y [?]
contienen abundante información sobre este tipo de codificación de bloque.
Desde el punto de vista práctico, un codificador Reed-Solomon añade bits de redun-
dancia a la trama digital de entrada organizada en bloques. Se dice que un codificador R-S
genera un código (N, K), cuando a un bloque de K bytes, se le añaden otros 2t más, con
t siendo el número de bytes erróneos corregibles, (aquı́ los errores se consideran a nivel de
byte, da lo mismo que haya uno u ocho bits erróneos dentro del mismo), resultando una
longitud de bloque de código (mensaje + paridad) de:
N = K + 2t bytes (4.1)
Cuando se utiliza el codificador R-S, los datos del mensaje deben “rellenarse” con
datos no válidos durante el perı́odo en que el codificador añade los 2t bytes de redundancia,
pues durante ese tiempo los bits de entrada son ignorados. Esa circunstancia se refleja en
la figura 4.3
1 + x5 + x6 compatibilidad DAVIC/DVB
1 + x14 + x15 compatibilidad MCNS(DOCSIS)
de proceso del DDS, y por otro lado, eliminar las componentes indeseadas que se generan
en ese sobremuestreo de acondicionamiento.
Dentro del filtrado pasobajo a que se somete la trama de datos, la etapa FIR se
aprovecha para conformar la parte “fundamental” ó significativa de la forma del espectro
de salida, mientras que el efecto de las dos etapas interpoladoras CIC, también de respuesta
pasobajo, no tiene relevancia en este caso. Su pendiente de caı́da en la banda de interés
es menos pronunciada que la de los filtros FIR. Lo que se hace es compensar la caı́da
originada por las etapas interpoladoras en el diseño de la curva de respuesta del filtro de
pulso FIR.
En la sección 1.9 se describe el funcionamiento de los filtros FIR y de los interpola-
dores CIC (Cascaded Integrator Comb).
Los caminos I y Q del modulador contienen cada uno un filtro FIR conformador
del pulso de 41 etapas con coeficientes ai de 10 bits. Los coeficientes se representan me-
diante valores enteros en complemento a dos. Por tanto, cada etapa tiene un coeficiente
multiplicativo con valores posibles −512 ≤ ai ≤ 511.
Respecto a la constitución interna de los filtros, una importante caracterı́stica es que
por diseño y para ahorrar el número de multiplicadores necesarios en total, el fabricante
ha elegido una realización simétrica de los mismos. Al programar los coeficientes, sólo se
pueden definir el de la etapa central y los de las 20 inferiores.
Se puede demostrar, que los filtros digitales cuya respuesta impulsiva es de la forma
y la velocidad de transmisión de datos en bits/seg. Por tanto, habrá que tener en cuenta
o “compensar” este factor de interpolación de sı́mbolo ×4 en el factor total dependiendo
de la modulación que se emplee.
Un ejemplo del filtrado que se puede sintetizar corresponde a la caracterı́stica en
coseno alzado. En primer lugar se calcularán los coeficientes a programar en cada una de
las etapas sin tener en cuenta el efecto ya comentado de las etapas de interpolación. Dicho
efecto se tendrá en cuenta a posteriori.
Puesto que trabajamos con señales reales, se calcula la transformada inversa de
Fourier de la parte positiva de la caracterı́stica, sustituyendo la exponencial compleja por
un coseno. El ejercicio se ha realizado teniendo en cuenta el factor de interpolación ×4
introducido por el filtro FIR. Los detalles del mismo se incluyen en el listado del fichero
de Matlab que se incluye en el apéndice ??.
La figura 4.5 representa el resultado de la simulación de algunas de las respuestas
en coseno alzado para diferentes factores de α.
En las distintas simulaciones de la gráfica 4.5, se fue modificando manualmente el
valor de α en el fichero de comandos ad9853 srrc.m.
Como resultado, se obtuvieron los coeficientes que se debe programar en cada una
de las etapas de los filtros FIR. En la tabla 4.2 se anotan los valores una vez normalizados
al valor máximo de 511, siendo la etapa número 20 el punto central del mismo. Ya se ha
dicho que por construcción interna del modulador DDS, los valores se cargan de forma
simétrica alrededor de la toma central.
α 0 1 2 3 4 5 6 7 8 9 10
0.1 -11 9 25 28 12 -16 -37 -38 -12 27 58
0.5 0 3 2 -2 -5 -2 5 7 1 -7 -7
0.9 0 2 0 -2 -1 2 1 -3 -3 3 4
α 11 12 13 14 15 16 17 18 19 20
0.1 55 13 -52 -102 -97 -13 138 315 457 511
0.5 7 19 7 -34 -71 -48 71 260 438 511
0.9 -5 -8 5 13 -11 -41 11 189 410 511
Cuadro 4.2: Coeficientes de cada etapa del filtro FIR en el AD9853 para las distintas
curvas de respuesta en coseno alzado sin compensar la caı́da provocada por las etapas
interpoladoras.
(a) (b)
(c) (d)
(e) (f)
RM −1
!N
X
−k
HCIC (z) = z (4.4)
k=0
RM −1
!N
X
HCIC (f ) = e−j(2πf /R)k (4.5)
k=0
que es una respuesta pasobajo tal y como se vió en la figura 1.51 para distintos
valores de parámetros M y N.
Cada rama de datos I y Q dispone de dos de estas etapas además del filtro confor-
mador FIR, todas en cascada. Es preciso si se quiere conseguir una función conformadora
lo mas precisa posible, tener en cuenta la variación introducida en la respuesta del filtro
FIR por las etapas CIC, pues su caracterı́stica no es perfectamente plana en la banda
de paso. Lo que sı́ resulta práctico es despreciar el efecto de la segunda de estas etapas,
puesto que como ya hay que tener en cuenta el factor de interpolación total, en este caso
sı́ que resulta despreciable su efecto.
Lo que se hace es “precompensar” la curva de respuesta del filtro FIR en su diseño.
Para ello, multiplicamos su función de transferencia por una función compensadora
1
HCOM P (f ) = (4.6)
HCIC (f )
aplicándola en un margen del 90 % del ancho de banda de interés (parámetro β en
el fichero cic.m de simulación de Matlab). Si se aplica en todo el rango de frecuencias,
el incremento de amplitud que experimentan los lóbulos espúreos fuera de la banda no
compensa con la precisión conseguida en la banda de paso.
Por último, otro efecto importante sobre el que se debe de actuar es el de la escala en
frecuencia. La frecuencia de muestreo a la entrada de la etapa CIC resulta ser la de salida
del filtro FIR, o lo que es lo mismo, cuatro veces la velocidad de sı́mbolo: existe por tanto
un problema de escala. Afortunadamente la solución es fácil puesto que la interpolación
en frecuencia equivalı́a a hacer un cambio de variable en la función de transferencia de
H(f ) por H(f /Escala). En este caso el factor Escala = 4.
Se ha realizado en ejercicio en Matlab donde se ponen en práctica todas estas con-
sideraciones. Su listado se incluye en el fichero cic.m del apéndice C. Aquı́ incluimos
simplemente las gráficas que ponen de manifiesto la precompensación de la respuesta del
filtro en coseno alzado y la tabla con los nuevos valores de los coeficientes. ¿Cual es el
problema principal planteado por este fenómeno? La compensación es especı́fica para un
factor de interpolación del filtro R determinado, ya que según se ha visto en la ecua-
ción 4.5, la curva de respuesta de las etapas CIC depende de este parámetro, que varı́a
según lo haga la velocidad de transmisión. Por tanto, idealmente serı́a necesario recalcular
esta precompensación cada vez que cambiara la tasa de transmisión. En nuestra aplicación
no lo hacemos ası́, y tampoco es que se haya visto una degradación tan importante en la
4.2 Diseño hardware de la placa DDS 96
curva de respuesta, puesto que después de haber jugado con el fichero cic.m cambiando
algunos valores de parámetros, no se aprecia un cambio tan sustancial en los coeficientes
resultantes.
(a) (b)
Nos quedarı́a por determinar cómo se calculan los valores de interpolación que se
deben de cargar en las distintas etapas, pero preferimos posponerlo para la sección 4.3
donde se describe el software, puesto que se tendrá que volver a explicar un problema que
se plantea al respecto.
Etapa 0 1 2 3 4 5 6 7 8 9 10
Valor org. 0 3 2 -2 -5 -2 5 7 1 -7 -7
Valor comp. 1 4 2 -3 -6 -1 7 9 1 -10 -9
Etapa 11 12 13 14 15 16 17 18 19 20
Valor org. 7 19 7 -34 -71 -48 71 260 438 511
Valor comp. 8 24 12 -33 -78 -62 56 251 435 511
Cuadro 4.3: Coeficientes de cada etapa del filtro FIR en el AD9853 antes y
después de la compensación del efecto de las etapas interpola-
doras CIC. Valores de R = 6, α = 0,5 y β = 0,9.
3. Modulador DDS
5. Oscilador de referencia
6. Salida FI
7. Entrada-salida de datos
otros dos módulos: el generador de reloj de bit, del que se obtiene el reloj de transmisión de
datos, y el modulador DDS, constituido por el circuito integrado AD9853 que ya conocemos
en profundidad.
El buffer de control y datos está formado por un grupo de demultiplexores que
reciben las señales enviadas por el bus de datos del puerto paralelo y las acondicionan
para ser utilizadas en el hardware del circuito.
En los siguientes apartados entramos más en detalle en todos y cada uno de estos
bloques.
En este caso, el PC de control sólo lee información de la placa DDS a través del hilo
de estado OD3, desde donde se lee el puerto serie de control del AD9853. Del resto de
circuitos de la placa DDS no hay forma de obtener información.
Casi podrı́amos haber denominado a este bloque como de control, puesto que la
mayorı́a de las señales que se reciben realizan esa función. La excepción corre a cargo del
terminal etiquetado como BUS DATIN del buffer U5, encargado de soportar la comuni-
cación serie con el bus de control del modulador AD9853.
Comentaremos la función de los componentes que constituyen este bloque apoyándo-
nos en la figura 4.8:
U10, 74HC139. Es un demultiplexor dos a cuatro que genera las señales de “enable”
de activación de los drivers que retienen la información enviada desde el PC a través
del bus de datos del puerto paralelo (D0 a D7). Los hilos de selección son los ter-
minales LATCH2 y LATCH3 del puerto de control del PC, y su validación también
llega directamente desde el puerto paralelo a través de la señal de control LATCH1.
En la figura se ve cómo se aprovechan sólo dos de las cuatro salidas demultiplexadas
disponibles (CHIP0 y CHIP1). Es el resultado de la optimización realizada a fin de
reducir en lo posible el tamaño y número de circuitos de la placa.
U3, 74HC574. Es el primero de los buffers triestado de este bloque, siendo el encarga-
do de mantener el byte menos significativo de la palabra de comando de división que
el programa de control envı́a al generador de reloj de bit, P0 a P7. Este componente
tiene anulada su capacidad de poner en estado de alta impedancia sus salidas al no
ser de utilidad en este caso.
La salida se actualiza con el dato presente en los hilos del bus en el flanco de subida
de su señal de enable, CHIP0, que le llega desde U10.
Los tres bits menos significativos completan la función de controlar el divisor pro-
gramable del generador de reloj de bit, P8 a P10. Para programar el divisor ha
de procederse de forma curiosa: si lo que se desea es programar un factor de
división de 2, hay que cargar el valor 37EH , o 111111111102 ; para programar
4.2 Diseño hardware de la placa DDS 100
el máximo valor de división de 2047, en este caso el valor a cargar debe ser
1H . El valor 0H no tiene validez puesto que impide el correcto funcionamiento
del circuito, y serı́a el correspondiente a un factor de división de 2048. Vemos
por tanto que el valor a cargar corresponde al complemento a 2 del factor de
división deseado.
Q4 es el hilo que resetea el modulador DDS, también accesible en el conector de
entrada-salida por si se quiere aprovechar en otro sistema externo.
Q5 es un terminal de control de la transmisión del AD9853 que también juega
un papel importante en la programación del mismo a través de su puerto de
control serie. Su función se comenta con mayor rigor en el apartado dedicado
al conexionado del modulador AD9853.
Q6 a Q8 controlan el flujo de señales en el puerto serie de control del modulador.
Utilizando sus etiquetas de la figura 4.8, 3 STATE BUS es el hilo que controla
el estado de alta impedancia del transceptor U8 incluido dentro del bloque
del modulador DDS. Este transceptor debe estar en alta impedancia durante
las respuestas del integrado hacia el terminal OD3 del puerto paralelo del
PC. BUS DATIN constituye el otro sentido de datos en el puerto serie; su
contenido se envı́a hacia el modulador pasando a través del transceptor U8. Por
último, BUS CLK es el hilo conectado al terminal de reloj que temporiza las
transacciones del puerto serie del modulador DDS. En este caso, se requiere una
alta actividad en el puerto paralelo del PC, puesto que como ya se podrá intuir,
los intercambios de información con el modulador DDS se han de realizar bit a
bit.
REF CLK IN, reloj de referencia de entrada, en este caso se ha elegido 27Mhz, por
estar cerca del lı́mite máximo de 28 Mhz y haberse encontrado con relativa facilidad.
El reloj del sistema, o reloj con el que trabaja el DDS es 6 veces mayor porque se ha
habilitado el multiplicador interno a través del bus de control.
DAT IN, es el terminal al que se aplican los datos a transmitir. Está conectado a la
etiqueta SDI, que llega desde el conector de entrada-salida.
Por ejemplo, para transmitir a la velocidad estándar de 2.048 Mbps, con el cristal
de referencia actual de 27 Mhz se necesita una relación de división de 13.1835, imposible
de conseguir. En ese caso, seleccionando un factor de división de 13 necesitarı́amos una
referencia de 26.624 Mhz, que no sobrepasa el lı́mite superior de frecuencia permitida
por el modulador DDS. El factor de división 14 da como resultado 28.672 Mhz que sı́ lo
sobrepasa. En este ejemplo serı́a necesario, por tanto, sustituir el oscilador de referencia
actual por uno de 26.624 Mhz.
En nuestro diseño no tenı́amos especificada ninguna velocidad en particular, porque
para hacer pruebas de laboratorio lo que importan son los órdenes de magnitud, ası́ que
se escogió la frecuencia que más se acercaba al lı́mite máximo de 28 Mhz y que se en-
contró fácilmente en el mercado: 27 Mhz.
4.2 Diseño hardware de la placa DDS 103
Por lo que respecta a la circuiterı́a en particular, U1,U2 y U4 son los tres contadores
sı́ncronos conectados en cascada que dividen el reloj de referencia CLK BUF. Se trata de
contadores descendentes programables con un terminal de indicación de final de cuenta
RCO empleado como habilitación en el contador siguiente de la cadena. Aún utilizando
este método, se trata de un contador sı́ncrono si se observa que la señal de reloj CLK BUF
se aplica a los tres contadores en paralelo.
El terminal RCO del último contador U4 es la salida asimétrica de este bloque,
y como tal está conectada a JP3; pero también se emplea en la carga de los valores de
programación de todos los contadores después de invertirse en U8A. El terminal Y1 de
U8A es la señal de salida invertida, con lo que al final de cada ciclo se genera un pulso
de bajada de duración igual a la del periodo de la frecuencia de referencia, que al estar
conectado a los terminales LOAD de los contadores, provoca que los valores enviados desde
el buffer de datos P0 a P10 se carguen en la salida de éstos, comenzando de nuevo la cuenta
descendente en el siguiente pulso de reloj. Se deduce que para programar una relación de
división en este circuito lo único que hace falta es colocar el valor adecuado de división en
los hilos P0 a P10 y el mismo circuito se encarga de cargarlo en el siguiente ciclo.
Se observa en la figura 4.11 que no se utiliza el terminal D de carga paralelo en U4.
Esto es porque con 11 terminales, P0 a P10, podemos conseguir un margen de división
de 211 − 1 = 2047 (el valor 7F FH no es válido), margen más que suficiente en QPSK y
16QAM dado que el modulador DDS como máximo tiene un factor de interpolación de
3906 al que hay que descontar el factor multiplicativo ×6 a que se somete la frecuencia de
referencia en el interior del modulador AD9853. La única modulación para la que resulta
útil tanto margen de división es para FSK que no tiene ningún procesado en el modulador
DDS.
Podı́amos habernos casi ahorrado incluso un hilo más de control del contador. No
se hizo ası́ puesto que no se necesitaba para ninguna otra función.
El biestable U7A sobraba y se pensó aprovecharlo para el caso en que se deseara un
factor de forma en la señal de salida de reloj de bit del 50 %. Conectandolo en forma de
biestable T conseguimos que su salida bascule a cada pulso de reloj asimétrico, obteniendo
por tanto un factor adicional de división ×2, además del cambio en la forma de onda.
La selección de salida de un reloj de bit u otro se realiza fı́sicamente en JP3, donde
determinamos el reloj de bit disponible en el conector de entrada-salida:
(a) (b)
(c) (d)
(e) (f)
Obviamente, estos valores dependen del reloj de referencia, por lo tanto se pueden variar
cambiando el oscilador de referencia o utilizando uno externo según las necesidades de
cada momento.
Para ilustrar el funcionamiento independiente de este bloque se han obtenido fácil-
mente las gráficas de la figura 4.2.2.4. Al disponer en el terminal de salida de la placa
DDS de la señal de reloj de bit generada en este bloque, no resulta difı́cil comprobar el
funcionamiento de este circuito. Se puede distinguir el distinto factor de forma de la señal
de salida cuando se intercala el divisor U7A, resultando el factor adicional de división ×2.
Figura 4.13: Oscilador interno de referencia y jumper JP1 de selección de reloj maestro
1. Puente JP1 1-2 aislado. El circuito trabaja con el oscilador interno Y1 de 27 Mhz.
2. Puente JP1 3-4 único. En este caso el reloj de la placa DDS es el externo suministrado
desde el conector de entrada-salida.
3. Puentes JP1 1-2 y 3-4 conjuntos. Ahora el circuito trabaja con el reloj interno y
además disponemos de él en lo que normalmente es entrada, por si queremos utilizar
el reloj de la placa DDS en otro sistema distinto.
4.2.2.6. Salida de FI
Esta etapa comprende el filtro antialiasing y el acoplamiento mediante transformador
para convertir las salidas unipolares de corriente del DAC, a señales bipolares simétricas
tal y como se recomienda en la sección 1.8.
Es un conector plano de diez terminales agrupados en dos filas, y las señales se han
distribuido de tal forma que su correspondencia en el conector de la placa de secuencias
permita un cable plano paralelo de interconexión. De este modo, los terminales conectados
a este conector son los siguientes:
4.3 Software de control 108
SDI Serial Data Input. Entrada de la trama digital de información a transmitir. Debe
de cumplir obligatoriamente la condición que ya se ha repetido muchas veces a esta
altura, pero fundamental para el correcto funcionamiento del sistema: su velocidad
debe ser un submúltiplo par del reloj del sistema, además de estar sincronizado con
él.
CLK DAT Data Clock. Frecuencia de datos creada con la caracterı́stica de ser sı́ncrona
al reloj de referencia de la placa, por tanto apta para servir de señal de reloj en la
circuiterı́a de datos de entrada. La señal viene desde el generador de reloj de bit
que tiene incorporado la placa DDS. En nuestra aplicación particular se utiliza en la
placa de secuencias pseudoaleatorias como señal de reloj de bit y como tal, determina
la velocidad de transmisión de datos.
RESET. Señal de reset del modulador AD9853 generado desde el control de la placa y
que se ha dejado accesible al exterior por si en algún momento fuera de utilidad.
4.2.2.8. Alimentación
El bloque de alimentación está constituido por tres reguladores similares, cada uno
de los cuales suministra la tensión de 5 voltios a partir de los 12 de entrada. El motivo
de separar las distintas alimentaciones está en el intento de mejorar en lo posible las
prestaciones de margen libre de espúreos del modulador DDS. Se ha separado por una
parte la alimentación al convertidor D/A del DDS (+VDA), por otro lado, la alimentación
del PLL interno multiplicador de la frecuencia de referencia de la placa DDS × 6 para
generar el reloj del sistema, en un intento de minimizar el acoplo de la señal de reloj a la
salida (+VD). Por último, la alimentación de la parte digital del modulador DDS y del
resto de la placa, +V.
Con la última nos llevamos la sorpresa de tener que cambiar el regulador por otro que
aguantase más corriente, dado el elevado consumo del AD9853. La sorpresa siguió cuando
descubrimos su calentamiento, lo que nos decidió a instalar un ventilador para mantener
la temperatura dentro de los márgenes de seguridad.
En el apéndice A se puede ver cómo ha quedado montado todo el sistema dentro de
un chasis de aluminio.
4.3 Software de control 109
golpe de ratón o directamente escribiendo un número dentro del mismo. Esta es la forma
de cambiar el valor de frecuencia del reloj de bit generado por la placa DDS, o lo que
es lo mismo, la velocidad de transmisión de datos. La función ValorDiv también es una
función importante porque se llama desde muchas otras funciones del módulo, siempre
que la operación que realize el usuario implique un cambio “serio” de configuración del
sistema.
A priori su funcionamiento no presenta muchas complicaciones conceptuales. De lo
que se trata es de escribir la palabra de programación en el divisor de la placa DDS, y
este trabajo lo descarga sobre la función de bajo nivel gen bit clk. Las complicaciones
surgen cuando se analizan un poco todas las posibilidades de funcionamiento, pues los
valores máximos y mı́nimos de frecuencia de bit permitidos dependen del tipo de modu-
lación seleccionado, y hay que considerar la estructura interna del modulador que no nos
permitirá programar todos los valores que fı́sicamente son posibles de generar. Toda esta
complicación también se descarga sobre la función del módulo mod hard.c interpolador
que trataremos un poco más adelante.
De momento nos sirve con saber que esta función chequea el valor que se ha coman-
dado, y si se detecta un valor imposible de programar, la función interpolador automáti-
camente busca el valor “permitido” por defecto y lo programa. Por supuesto, informa a la
función llamante para que la presentación gráfica se actualize correctamente y le aparezca
al usuario el mensaje de aviso pertinente.
Lo realmente destacable de esta función puede que no sea fácil de distinguir en
su listado: es realmente la función que gobierna la correcta temporización de la placa
DDS. Por un lado se ejecuta cada vez que se cambia el tipo de modulación (FSK, QPSK,
16QAM), también cuando se pulsa el botón del divisor fijo en la misma ventana, por
supuesto cuando se cambia el valor desde el mismo control. A continuación llama a la
función que valida el valor comandado, después llama a la función que modifica fı́sicamente
4.3 Software de control 112
Si observamos la figura 4.18, existe una parte común en los protocolos de lectura y
escritura del modulador en la cual se envı́a la dirección del dispositivo y la del registro
interno al que se quiere acceder, independientemente de que sea para leer o escribir. Co-
mo se habrá podido intuir, el trabajo se ha repartido entre tres funciones de bajo nivel:
carga reg ser, la parte común a las operaciones de lectura/escritura, escribe ser y lee ser,
de función clara según indica su nombre.
Comentando ya el funcionamiento concreto de la instrucción prog hard, se observa
en el listado de la aplicación su función de escribir datos de configuración en el modulador.
Según las hojas de datos del fabricante, la lı́nea fı́sica TXE debe estar desactivada durante
la utilización del puerto serie del modulador. Como durante la secuencia de inicialización
del programa principal, la lı́nea TXE se deshabilita un tiempo considerable, se quiere
evitar esa reiteración de órdenes con la construcción if del interior de la función.
FREF
FBIT = (4.8)
Div
Ahora expresamos la relación entre la frecuencia del sistema y la velocidad de trans-
misión de datos según las hojas del fabricante:
1
FSIS = 4I1 I2 FBIT (4.9)
M
donde el cuatro es un factor de interpolación fijo en la etapa FIR y M es el número
de bits por sı́mbolo de valor 2 en QPSK y 4 en 16QAM.
Operando con todos estos datos, y teniendo en cuenta los valores máximos y mı́nimos
de las etapas de interpolación, obtenemos
I1 I2 = 3Div
I1 I2max = 1953 Divmax = 651
I1 I2min = 6 Divmin = 2 Para QPSK
bit]
I1 I2 = 6Div
I1 I2max = 1953 Divmax = 325
I1 I2min = 12 Divmin = 2 Para 16QAM
Jugando con estos valores y con la ecuación 4.8 podemos calcular los valores máximos
y mı́nimos de frecuencias de transmisión de datos de nuestro sistema.
Podemos erróneamente pensar en este momento que todos los valores de factor de
división entre los lı́mites que se acaban de enunciar son posibles. Sin embargo, hay que
tener en cuenta que los interpoladores están diseñados para funcionar con unos factores
máximos de interpolación de 31 el primero y 63 el segundo. Esto supone una limitación
importante puesto que elimina aquellos valores de división cuya descomposición en factores
primos tenga un factor mayor de 63. Por ejemplo, podrı́amos querer seleccionar un factor
de división de 316 para trabajar en QPSK a una velocidad de 85.443 kbps. Pues bien,
como su descomposición en factores primos es 316 = 79 × 22 , no podemos programar a
ninguno de los interpoladores con el factor 79 y por tanto, aunque el circuito de generación
de reloj de bit admitiese ese valor, luego no podrı́amos trabajar con el modulador DDS.
La función interpolador realiza este trabajo de control sobre los parámetros de
temporización. En la aplicación se ha incluido una tabla con todos los valores que tienen
un factor primo mayor de 63 mediante el fichero de encabezamiento primo 63.h.
Cada vez que se cambia la velocidad de transmisión, lo primero hace esta función es
comprobar si el valor comandado es un valor permitido. Si esto no se cumple, la función
4.4 Resultados prácticos 115
empieza a buscar un valor de velocidad hasta que se encuentra el primero permitido por
defecto.
Cuando se ha encontrado un valor posible o bien el que se comandó ya lo era, la
función busca la repartición del factor de interpolación más adecuada siguiendo las reco-
mendaciones del fabricante. Aconsejan que el factor de interpolación global se reparta lo
más equitativamente posible en cada una de las etapas. Por ello, el algoritmo de búsqueda
empieza haciendo la raı́z cuadrada del valor a conseguir y le asigna a cada interpolador el
entero más cercano a ese valor.
Figura 4.19: Conexionado usual del sistema: placa DDS y placa de BER
trabajando conjuntamente
(a) (b)
(c) (d)
(e) (f)
Figura 4.20: Medidas de salida para vt = 2,7175M bps realizadas con anali-
zador vectorial HP89410A y filtro de datos en coseno alzado de
factor α = 0,28.
(a),(c) y (e) Diagramas I-Q para QPSK, 16QAM y FSK.
(b),(d) y (f) Diagramas de ojos correspondientes
4.4 Resultados prácticos 117
no se modificó el que tiene la aplicación modulAD cargado por defecto en coseno alzado
con α = 0,5.
Por otra parte se incluyen las medidas realizadas con el analizador de espectros,
tanto en banda ancha para observar el comportamiento del modulador en lo referente a
margen libre de espúreos, como en banda estrecha para observar el filtrado que se realiza
en el dominio digital mediante las etapas FIR conformadores del pulso.
(a) (b)
(a) (b)
Figura 4.22: Medidas en banda ancha para QPSK donde se observan las
imágenes generadas por el proceso de conversión D/A.
(a) QPSK a 13.5 Mbps a la frecuencia de 15 Mhz.
(b) QPSK a 13.5 Mbps a la frecuencia de 65 Mhz
Figura 4.23: Medidas en banda ancha para FSK sin filtro antialiasing
4.4 Resultados prácticos 119
133.66 kbps. La razón de volver a incluir una gráfica similar es destacar la mejorı́a en
SFDR de este caso, motivada por el cambio en el esquema de modulación y el régimen
de transmisión: Para todos los esquemas de modulación, el DAC del DDS genera la mis-
ma potencia de salida puesto que no se cambia para nada su configuración de corriente
máxima. Ahora bien, en QPSK y 16QAM la potencia se distribuye uniformemente sobre
todo el ancho de banda ocupado, mientras que en el ejemplo de FSK a baja velocidad,
como el régimen de transmisión es mucho menor, el espectro de salida se asemeja mucho
más a dos tonos, por lo que esa potencia de salida se “concentra” y la relación señal ruido
mejora ostensiblemente.
(a) (b)
(a)
(b)
(c)
Figura 4.25: Espectro cercano para los tres tipos de modulaciones principa-
les.
(a) QPSK a 13.5 Mbps a la frecuencia de 10 Mhz.
(b) 16QAM a 13.5 Mbps a la frecuencia de 10 Mhz.
(c) FSK a 133.66 Kbps a la frecuencia de marca de 10 Mhz.
Capı́tulo 5
121
5.1 Opciones de diseño 122
La primera opción que se barajó fue la de generar las secuencias de datos mediante
un programa desde el ordenador. La ventaja inherente a la generación software estriba
en el control que se tiene sobre la secuencia generada, permitiendo ampliar fácilmente el
número de secuencias y patrones de transmisión para poder simular los nuevos escenarios
prácticos que vayan apareciendo en el futuro.
Por otra parte, el principal inconveniente de esta opción consiste en que el sistema
operativo Windows proporciona un control de temporizaciones que como máximo llega a
1 milisegundo. Por tanto, si se pretende llegar a unos regı́menes de transmisión del orden
de los 15 Mbit/s es preciso enviar a un buffer 15000 bits por operación de entrada/salida,
(15000 bits / 1 ms). El bus ISA del PC funcionarı́a sobrado de capacidad, pero tendrı́amos
el inconveniente de necesitar un dispositivo hardware que estuviese dotado de una memo-
ria de doble puerto que, funcionando en forma de buffer plesiócrono, recibiera los datos
ası́ncronos del PC para enviarlos al modulador DDS de forma sincronizada.
La necesidad de utilizar el bus ISA nos obliga a un desarrollo en forma de tarjeta de
expansión del PC, que dificulta su instalación en un portátil y limita considerablemente
su abanico de utilización a entornos cerrados de laboratorio.
Alternativamente surgió la idea de generar los datos directamente desde hardware,
puesto que incluso la primera opción obligaba a realizar por este mismo método el ya
comentado dispositivo de sincronización. De esta forma se liberarı́a de mucho trabajo a
la CPU principal del PC, a costa de disminuir el grado de libertad en la generación de
secuencias. Se buscaron circuitos integrados que realizaran ese trabajo, encontrándose el
integrado de Dallas DS2172.
En este caso la opción de diseño contempla la realización de una placa de circuito
impreso, siendo necesaria únicamente la programación de los registros del integrado de-
pendiendo de la secuencia que se desee utilizar. Dada la relativamente escasa cantidad
de instrucciones y comandos necesarios, al menos comparada con la primera opción, se
puede utilizar al puerto paralelo del PC como interface de control, que además es una
interfaz ampliamente conocida y sobre la que se puede encontrar multitud de información
al formar parte integral del PC. [?].
Al utilizar el puerto paralelo del PC se gana en flexibilidad de uso, ya que lo único
que hace falta en este caso es un cable paralelo, y por tanto se puede utilizar cualquier
portátil para controlar el circuito en medidas de campo.
Se optó por esta última opción dadas sus ventajas sobre la primera filosofı́a, con
la particularidad de que fue ésta decisión la que determinó el tipo de control a utilizar
5.2 Especificaciones de la placa BER 123
en la placa DDS. No hubiese tenido sentido realizar dos tipos de control independientes
pudiendo controlar los dos circuitos de modo homogéneo.
Puede funcionar conjuntamente con la placa DDS como fuente de bits a transmitir,
o utilizarse como sistema aislado independiente.
Control
Modos de trabajo:
Alimentación
Consumo: 85 mA
Grabación del resultado de los test en fichero de texto con los parámetros más
importantes de la prueba realizada.
g(x) = 1 + xB + xA (5.1)
Velocidades de operación desde DC hasta 52 Mhz. Esto nos permite generar una
amplia gama de velocidades de transmisión. En la práctica esta ventaja no se explota
en su totalidad dado que el reloj maestro del sistema realizado es 27 Mhz, y por
construcción práctica de la placa DDS la máxima velocidad de datos que se puede
conseguir es 27/2 = 13,5 Mbps. Si se utiliza la placa de BER por separado esta
limitación no existe, siempre suministrando la señal de reloj de forma externa.
Puerto paralelo de control de 8 bits. Factor importante que hace que el puerto
paralelo del PC se convierta en una interface casi directa con el chip. Se requiere
una pequeña variación hardware si, como en nuestro caso, se quiere utilizar el puerto
paralelo en modo compatible.
Modo pseudoaleatorio
Por un lado, lo referente a la naturaleza de la secuencia pseudoaleatoria generada.
Su descripción matemática, y por tanto su longitud y patrón vienen determinados por dos
parámetros:
5.3 Diseño hardware de la placa BER 128
Otro de los aspectos destacables de la figura 5.2 es la puerta and incluida en la toma
de realimentación B. El terminal PCR.5 es el que la habilita: Un uno permite que los
valores que se desplazan por el registro de desplazamiento se realimenten a la puerta xor
de entrada, por tanto modificando las caracterı́sticas de la secuencia de salida, siempre
dependiendo del polinomio generador elegido.
Por el contrario, un cero en el terminal PCR.5 anula la realimentación a la entrada
del registro de desplazamiento de los valores que se propagan a su través, resultando una
secuencia periódica o repetitiva, igual al valor inicial cargado en los flip-flops tipo D que
conforman el registro.
De este análisis podemos concluir que es el terminal PCR.5 el que determina el modo
de trabajo del generador de secuencias patrón, bien en el modo pseudoaleatorio, bien en
modo repetitivo.
El terminal EIR.5 realiza la inversión de los bits transmitidos. Esta inversión se
puede configurar de forma permanente desde el controlador, aunque como su nombre
sugiere: EIR, Error Insert Register, forma parte de la circuiterı́a de inserción de errores y
por eso está situado en el camino de la trama de salida.
¿Cuántas secuencias pseudoaleatorias se pueden generar con esta topologı́a del re-
gistro de desplazamiento?. La respuesta más inmediata es ¡muchas!. Obviamente, aunque
no vamos a poder determinar su número exacto, ahora estamos en condiciones de decir
algo más gracias al capı́tulo 2.
La ecuación 2.16 calculaba el número de polinomios primitivos de un grado deter-
minado, de forma que estamos en condiciones de determinar el número de polinomios
primitivos que existen desde grado 2, (1 + x + x2 serı́a la primera secuencia de longitud
máxima generable), hasta grado 32:
r=32 r=32
X X φ(2r − 1)
N P Ptot = λ2 (r) = (5.2)
r
r=2 r=2
r=32
X
N P 3tot = (r − 1) = 496 (5.3)
r=2
Estos 496 polinomios representan otras tantas secuencias, y todas se pueden generar
con nuestro medidor de BER, incluso aquellas que no son de longitud máxima (primitivos).
Aunque no hemos resuelto el problema, quedarı́a ahora por averiguar utilizando técnicas
computacionales, cuáles de esos 496 polinomios son primitivos realmente.
Con la intención de retornar al mundo práctico se incluye la tabla 5.1 enumerando
las secuencias recomendadas por el fabricante, y aunque, se podrı́a programar cualquiera
de la forma 1 + xB + xA , no todo es perfecto y no se ha previsto esa posibilidad en la
aplicación de control. Solamente se realizaron diversas pruebas satisfactorias durante la
fase de desarrollo.
Modo repetitivo
Las secuencias repetitivas que se permite configurar tienen como máximo una lon-
gitud de 32 bits. Este lı́mite viene impuesto por el hardware del integrado, ya que es éste
el número de etapas que posee el registro de desplazamiento.
La verdad es que en este aspecto notamos una cierta limitación de prestaciones,
pues se echa de menos el poder generar secuencias repetitivas de mayor longitud; al menos
esa es una de las pocas diferencias que se han encontrado con respecto a otros equipos
comerciales comparados [?]. Por ejemplo, con 256 bits de longitud se podrı́a simular una
trama E1 de 2048 kbits/s repetitiva, jerarquı́a primaria en Europa.
De cualquier forma, en la tabla 5.2 se reflejan las secuencias repetitivas recomendadas
por el fabricante que son las que se han predefinido en la aplicación de control. Para poder
programar cualquier otra secuencia, esta vez si que se ha dispuesto de una opción en la
pantalla principal de la aplicación de control.
2. Buffer de control
3. Buffer de datos
4. Medidor de BER
5.3 Diseño hardware de la placa BER 131
5. Conector de transmisión/recepción
Cuadro 5.3: Interface entre la placa BER y el puerto paralelo del PC.
Tal y como se ve en la figura 5.4, está constituido por los siguientes componentes:
U10, 74HC139. Es un demultiplexor dos a cuatro que genera las señales de “enable”
de activación de los drivers que retienen la información enviada desde el PC a través
del bus de datos del puerto paralelo (D0 a D7). Los hilos de selección son los ter-
minales LATCH2 y LATCH3 del puerto de control del PC, y su validación también
llega directamente desde el puerto paralelo a través de la señal de control LATCH0.
Su funcionamiento es idéntico a su componente homólogo de la placa DDS, salvo
por la señal de control que lo activa, en aquel caso LATCH1. En este caso, la lı́nea
CHIP0 se emplea para demultiplexar las señales de control hardware de la placa,
y por otro lado CHIP1 se utiliza para cargar el bus del puerto paralelo en el bus
interno de datos.
U5, 74HC574. Es uno de los dos buffers del circuito, y su función es la de fijar todos
los comandos de control recibidos por el bus de datos. Sus hilos de salida reflejan
el valor lógico presente en las entradas justo en el flanco de subida de su señal de
enable CHIP0, que es proporcionada por U10.
Aunque este circuito es un buffer triestado, esta posibilidad no se utiliza en este caso
al realizar funciones de transceptor de control. Por eso el hilo OC está directamente
conectado a masa. Podemos decir que este integrado gobierna el funcionamiento del
resto de recursos hardware de la placa de BER.
2. Seleccionar el driver en el que se quiere escribir el valor mediante los hilos de selección
LATCH2 y LATCH3 (concretamente CHIP0).
4. Desactivar el hilo LATCH0 anterior. Esto provoca que el hilo enable del buffer se
desactive subiendo a nivel lógico alto, y como consecuencia de ello, el dato se fije a
la salida del mismo.
U3, 74HC574. Es el buffer que da paso a los datos desde el puerto paralelo. Su
activación se realiza mediante la selección de la dirección CHIP1 en el bloque de
control y su funcionamiento es análogo a U5 del mismo bloque. En este caso, sin
embargo, si que se debe prestar atención a la dirección de la información puesto que
cuando se quiere enviar algún dato hacia el PC se deben de poner las salidas de U3
en alta impedancia para no interferir en el bus interno AD0 − AD7.
Todas las operaciones están gobernadas mediante hilos del bloque de control, por lo que
toda transferencia de datos hacia el PC estará precedida de los correspondientes envı́os de
comandos de control hacia la placa de BER.
figura 5.6, donde podemos observar el conexionado particular del mismo en nuestra apli-
cación.
El puerto de control AD0 a AD7 está conectado al bus de datos interno de la placa.
Existe un grupo de hilos de control que gobiernan la temporización de los intercambios
de datos tanto de entrada como de salida. Todos estos hilos llegan desde el bloque “buffer
de control” comentado hace unos párrafos en el apartado 5.3.2.2. Se admiten dos tipos
de temporizaciones para los mismos terminales de control dependiendo del estado lógico
del pin BTS, Bus Type Select: Si esta señal está a nivel alto, el bus funciona según la
temporización estándar de Motorola, mientras que si su valor lógico es bajo, el tipo de
temporización que se emplea es la de Intel. Dependiendo de ello, el funcionamiento de los
pines 15, 17 y 18 difiere.
En nuestro diseño se ha escogido arbitrariamente la temporización del tipo Intel, ya
que no existı́a ningún motivo coercitivo que nos obligara a escoger un tipo determinado en
concreto. Realizada esta elección, la función de los terminales de control se puede resumir
del siguiente modo:
Pin 16 Chip Select, CS. Activo a nivel bajo sirve para indicarle al DS2172 que
debe prestar atención al bus, bien para leer o escribir en él.
Pin 17 Address Latch Enable, ALE. Es el terminal que sirve para demultiplexar
las direcciones del bus de datos interno. Los datos de dirección se cargan en el
integrado en el flanco de bajada de este terminal, siempre y cuando esté habilitado
el hilo de Chip Select.
Pin 15 Read, RD. Hilo de lectura de datos desde el registro previamente seleccio-
nado. El chip pone el dato en el bus en el flanco de bajada del terminal. En este
5.3 Diseño hardware de la placa BER 136
caso habrá que tener la precaución de poner el buffer de datos a alta impedancia
previamente.
Existen otros tres pines externos de control que no utilizamos puesto que tienen su
homólogo en un bit de los registros de control, y resulta muy fácil acceder a ellos mediante
software. Para inhabilitar los terminales se han conectado a masa. De todas maneras, los
enumeramos añadiendo un comentario explicativo de su función.
Terminal RL, Receive Load. Un flanco de subida en este pin carga los últimos
32 bits recibidos en los registros PRR, registros de recepción de secuencia patrón.
Su valor lógico está combinado mediante puerta OR con el valor del bit PCR.3 del
registro de control PCR.
Terminal LC, Load Count. Una transición de bajo a alto carga los contadores de
bits recibidos y errores detectados en los registros accesibles al usuario BCR y BECR,
y resetea la cuenta de los registros internos. Se combina mediante puerta OR con el
valor del bit PCR.4 del registro de control de patrón.
Terminal TL, Transmit Load. Es el terminal dual a RL, esta vez referido al gene-
rador de secuencia patrón: El valor de los registros de configuración de patrón PSR
se carga en el registro de desplazamiento que genera la secuencia a transmitir en el
flanco de subida de este terminal. Su valor también está combinado con el bit PCR.7
mediante un operador OR lógico.
Otro terminal que no se utiliza, esta vez no de control sino de estado, es el terminal
RLOS, que es un indicador hardware de sincronización. Como la misma indicación se
puede leer del bit SR.4 del registro de estado, en el montaje este pin se queda sin conexión.
Nosotros utilizaremos en nuestra aplicación la lectura de ese registro para determinar el
correcto “enganche” del medidor a la secuencia recibida.
Aparte de los terminales de alimentación nos queda el bloque de pines de transmi-
sión-recepción, que se comentan en el siguiente apartado.
Es usual en medidas de test prácticas que las secuencias de prueba estén sincroni-
zadas con el resto del sistema. Pensando en esta razón no se incluyó un oscilador
interno que aplicado a este pin permitiera al diseño funcionar independientemente.
Ahora pensamos que no hubiese estado de más incluirlo, aunque sólo hubiera sido
un zócalo para insertar el cristal a la frecuencia necesaria. Sólo se pensó en que para
cualquier aplicación que se utilizara, se necesitarı́a ese sincronismo que obligarı́a a
la generación del reloj de transmisión en el circuito a probar.
Ello nos plantea la necesidad de suministrar la señal de reloj de transmisión desde el
exterior en cualquier tipo de prueba. Con todo, no creemos que sea una desventaja
muy significativa. Siempre se puede utilizar cualquier fuente de señal TTL que actúe
de reloj de transmisión.
TDAT Transmit Data. Hilo de transmisión donde aparece la secuencia generada en
forma de trama de datos serie NRZ (unipolar no retorno a cero). Los datos tienen
sus transiciones en el flanco de subida de TCLK.
TDIS Transmit Disable. A nivel alto deshabilita el reloj de transmisión, por lo que
la secuencia de salida en el pin TDAT se detiene. A nivel bajo permite que la señal
de reloj de bit que llega por TCLK alcance la circuiterı́a de transmisión y ası́ pueda
continuar la secuencia de salida.
Este terminal es útil para aplicaciones donde se necesite que la secuencia de test se
transmita en modo de ráfagas (burst).
RCLK Receive Clock. Reloj de recepción con el mismo margen operativo que el de
transmisión. Es totalmente independiente del reloj de transmisión pero tiene sus
mismas caracterı́sticas en lo que se refiere a factor de forma y sincronismo.
En este caso sı́ que no ocurre como en el parte de transmisión. Aquı́ sı́ que es forzoso
el suministro de la señal de reloj desde el exterior.
RDAT Receive Data. Hilo de recepción donde se muestrean los datos recibidos en el
flanco de subida de RCLK. Los datos han de recibirse en formato NRZ como en el
caso de su homólogo de transmisión.
5.4 Software de control 138
RDIS Receive Disable. A nivel alto impide que los datos recibidos en RDAT se
muestreen. A nivel bajo permite que la señal de reloj de bit recibida entre en la
circuiterı́a interna permitiendo que funcione el bloque de recepción.
Es el terminal dual de TDIS, útil también en aplicaciones en modo burst.
5.3.2.6. Alimentación
La aplicación de control de la placa de BER está constituida por dos ficheros fuente.
Al igual que en la placa DDS, se han separado por un lado las tareas relacionadas directa-
mente con el hardware particular del diseño, y por otro lo que tiene que ver con el entorno
gráfico de usuario y la medida de tasas de bits erróneos.
Del fichero principal ber.c comentaremos únicamente la función bucle, que es una
función lanzada por el temporizador automático de Labwindows cada intervalo de 1 se-
gundo, y es la encargada de realizar todos los cálculos a la hora de ejecutar una prueba
de medida de tasa de error de bit. Para ello utiliza los servicios que prestan las funciones
de bajo nivel contenidas en el otro fichero fuente ber hard.c. También se encarga de la
presentación de los resultados en pantalla.
El fichero auxiliar de funciones hardware ber hard.c es el encargado de canalizar las
instrucciones de control por el puerto paralelo hacia los registros de la placa de BER,
cargando los datos precisos en función de los comandos enviados desde el módulo princi-
pal. En este caso, podemos comentar el funcionamiento de las instrucciones particulares
de lectura y escritura de datos en la placa de BER lee par bert y escribe par bert,
ası́ como la función aplicacion bert, que es la encargada de informar al módulo prin-
cipal del estado de sincronismo de la placa. El resto de las funciones resultan un poco
tediosas puesto que se trata únicamente de funciones reiterativas, cuyo trabajo consiste en
ir enviando el grupo de valores concretos a los registros determinados dependiendo de la
5.4 Software de control 139
Lo primero que hace la función es leer el registro de estado y los registros contadores
de bits recibidos y de errores detectados por el medidor de BER. Para ello llama a la función
aplicación bert que comentaremos en el apartado siguiente. Como esta actualización se
realiza periódicamente, podemos conocer con una demora de un segundo el estado en
tiempo real del medidor de tasas de error DS2172. El resultado de esta consulta será:
Actualización de los valores que se necesitan para calcular la tasa de BER instantánea
del segundo transcurrido desde la última ejecución de esta función.
escribir en la dirección que se le determine el valor pasado como entrada. Para ello genera
la temporización adecuada en las lı́neas de control y datos del puerto paralelo.
En su trabajo, esta función utiliza la librerı́a externa dlportbc.lib que permite el
acceso directo a los puertos de entrada-salida del PC sorteando la barrera de protección
que impone Windows NT para acceder al hardware. La instrucciones más importantes
utilizadas de esta librerı́a son DlPortReadPortUchar(dirección io) y DlPortWrite-
PortUchar(dirección io, byte que se escribe). A partir de estas dos se ha creado la
función base carga pp.
1. Lectura del dato que se acaba de escribir en la placa desde el puerto paralelo. Es decir,
se puede acceder, porque nos interese en un momento determinado, al bus interno
de la placa para comprobar o leer el dato que acabamos de escribir en él utilizando
una función de escritura. Es el caso de una función que se ejecuta periódicamente
para comprobar la correcta conexión de la tarjeta al puerto.
2. Lectura de datos puestos en el bus interno de la placa al leer desde los registros
internos del circuito DS2172. Ésta es la utilización corriente de la función.
reg ini es la dirección hardware del primer registro del cual se desea leer el contenido.
nro reg es un ı́ndice que controla el número de registros que se leen en las direcciones
siguientes a la indicada por la variable reg ini.
Si la opción de operación que se seleccionó fue la de lectura simple del bus interno
(la opción primera), no tiene sentido el contenido de estas dos variables.
La función almacena el resultado en el array global de caracteres reservado al efecto
control bert[nro registro]. El propósito es disponer de un “reflejo” en la memoria de
la aplicación que contenga los contenidos de los registros hardware. Aquı́ acceden las
funciones de alto nivel cuando necesitan conocer estos contenidos.
Recordemos también que la lectura de los datos desde el circuito BER, se realiza en
este caso nibble a nibble, dado que tenemos 4 hilos de lectura de datos hacia el PC. El
hardware del buffer de datos se encarga de multiplexar el bus interno de 8 bits hacia estos
4 hilos del puerto paralelo, y es entonces esta función la que se encarga de ir enviando a la
placa BER los comandos de control necesarios para canalizar el flujo de información hacia
el PC.
5.4 Software de control 142
Aquı́ se almacena también la cuenta de bits recibidos y número de bits erróneos. Vemos
que se ha reservado un lugar especial a cada uno de los bits del registro de estado:
sincro: Estado del sincronizador. Se activa cuando se reciben las secuencias continuas
de 1 ó 0.
5.5 Resultados prácticos 143
A consecuencia de esta “desviación” de lo que uno puede entender como estar sin-
cronizado, fue preciso añadirle a esta función otro parámetro más de entrada, secuencia,
que no es ni mas ni menos que el código de secuencia seleccionada en la aplicación de
control. De este modo se puede decidir de manera fiable sobre el estado de sincronismo
del circuito. En este sentido, la verdad es que la función se acerca bastante a la aplicación
de usuario.
La función considera que el circuito está sincronizado en los siguientes casos:
Para finalizar con el capı́tulo, en esta sección se presenta un ejemplo donde se mues-
tran los resultados prácticos de funcionamiento individual de la placa de BER. Recordemos
que el sistema puede trabajar de forma independiente con la ya comentada restricción de la
necesidad de fuentes externas de reloj. Para emular este caso, las medidas se han realizado
simulando una prueba real.
Como siempre se suele decir, una aplicación nunca está totalmente terminada, pues
seguro que se puede mejorar en un sentido u otro. En este caso podrı́amos acometer estas
mejoras tanto a nivel hardware como de programa de control, puesto que las aplicaciones
y posibilidades del sistema son muy amplias.
En cualquier caso, para competir con los dispositivos comerciales en el mercado se
deberı́a aumentar la flexibilidad del sistema, pues aunque puede parecer que las presta-
ciones son bastante amplias, los equipos comerciales tienen alguna prestación añadida que
les hacen ganar en utilidad.
Por comentar algunas, se podrı́an enumerar las siguientes:
Generador de reloj interno. Esto hace que el equipo se pueda utilizar por sı́ solo, en
vez de necesitar una fuente de reloj externa.
5.6 Mejoras futuras 145
(a)
(b)
Incluir el divisor de reloj y mejorarlo. Nos referimos al generador de reloj de bit que
en nuestro diseño se ha implementado dentro de la placa DDS. A su vez, mejorarlo
para que permita no sólo la generación de secuencias en modo continuo, sino que,
aprovechando los hilos de control de los bloques de transmisión y recepción del
DS2172, también se puedan generar secuencias aleatorias en modo ráfaga.
Esta pequeña modificación del sistema permitirı́a, por ejemplo, la realización de
medidas de BER en un único slot de tiempo de una trama digital de 2.048 Mbps de
la jerarquı́a primaria europea, (se las denomina tramas E1 en la literatura técnica).
Por último, como posible mejora del programa de control mediBER, podrı́a pro-
ponerse la configuración exterior mediante fichero y la grabación automática de la
última configuración antes de abandonar el programa. En este caso, no se perderı́an
los datos de configuración de la última prueba realizada.
Apéndice A
Dado que el método de control utilizado para gobernar todo el sistema es el puerto
paralelo del PC, se realiza a continuación una breve introducción al mismo, con el objetivo
de conocer su funcionamiento y los registros de que consta, pues serán importantes a la
hora de confeccionar las aplicaciones de control.
A.1. Generalidades
El puerto paralelo del PC se conoce normalmente con el nombre de Centronics 1 .
Aunque la idea para la que se concibió originalmente fue la de comunicación con la im-
presora, las evoluciones posteriores del citado bus han ampliado su rango de aplicación,
y actualmente el puerto paralelo es un puerto ampliamente usado como interfaz de todo
tipo de periféricos como scaners de sobremesa, dispositivos de backup, grabadoras de CD
externas, etc.
El puerto está compuesto de 4 lı́neas de control, 5 lı́neas de estado y 8 lı́neas de datos.
Se encuentra normalmente en la parte trasera del PC con un tipo de conector hembra D25.
Aunque también puede existir otro conector D25 macho, éste será un puerto serie RS-232
y por tanto, es totalmente incompatible con el primero. La tendencia actual es la de usar
conectores D9 macho para los puertos serie, por lo que resulta difı́cil la confusión.
Como consecuencia de la evolución en el puerto paralelo se hizo necesaria una estan-
darización del mismo, y ası́ se publicó la norma IEEE 1284 del año 1994, donde se definen
5 modos de operación, que son los siguientes:
1. Modo compatible
3. Modo byte.
El objetivo era desarrollar drivers y dispositivos nuevos que fueran compatibles entre
ellos y también hacia atrás con el Puerto Paralelo Estándar (Standart Paralell Port). Los
modos compatible, nibble y byte utilizan el hardware estándar disponible en las tarjetas de
1
Centronics era el nombre de un fabricante de impresoras
147
A.1 Generalidades 148
puerto paralelo original, mientras que los modos EPP y ECP requieren hardware especı́fico
que pueda correr a velocidades más rápidas, siendo también compatibles hacia atrás con
el Puerto Paralelo Estándar SPP.
El modo compatible o “modo Centronics”, como se conoce normalmente, se di-
señó para enviar datos en dirección de salida a una velocidad tı́pica de 50 Kbytes por
segundo, pudiendo llegar hasta los 150 Kbytes. Para recibir datos, se debe cambiar a
modo nibble o modo byte. El modo nibble puede leer un nibble (4 bits) en la dirección
inversa, es decir desde el periférico hacia el ordenador. El modo byte utiliza la caracterı́sti-
ca que sólo se encuentra en las tarjetas más modernas en las que el puerto paralelo es
bidireccional, de manera que se puede leer directamente un byte en la dirección inversa.
(a) (b)
Los otros dos modos mas avanzados, EPP y ECP, utilizan hardware adicional para
generar y gestionar el protocolo de intercambio de comandos entre el PC y los periféricos
conectados. Normalmente para enviar un byte a una impresora u otro dispositivo en el
modo compatible, el software debe:
3. Activar el hilo de Strobe (hilo 1) a nivel bajo. Esto le indica a la impresora que hay
un dato correcto en las lı́neas de datos. (hilos 2-9).
Los puertos EPP y ECP solventan esta limitación dejando al hardware chequear y
ver si la impresora está ocupada, generar el strobe y realizar el resto de operaciones de
A.2 Propiedades de la interfaz fı́sica 149
Cuadro A.2: Posiciones de la BIOS que almacenan las direcciones de I/O de LPTs
datos será almacenado, pero no estará disponible en los pines de salida. Para inhabilitar
el modo bidireccional, se conecta el bit 5 del puerto de control a cero. Esta caracterı́stica
está únicamente disponible en los puertos bidireccionales.
Sin embargo, no todos los puertos paralelo se comportan de la misma manera. Otros
puertos pueden requerir la activación del bit 6 del puerto de control para habilitar el
modo bidireccional y el bit 5 para inhibirlo. Diferentes fabricantes implementan el puerto
paralelo de forma diferente. Si se quiere profundizar más sobre el funcionamiento del puerto
paralelo del PC, existen varias páginas en internet con bastante información al respecto
[?].
Pin DB-25 Señal SPP Original Aplicación Sentido Registro Inv. Hardware 6
Los ocho hilos de datos constituyen el bus de salida desde el PC. En ellos se colocan
datos válidos que se cargarán en los diferentes registros de las placas de la aplicación. Los
hilos del registro de estado aquı́ los denominaremos como OD7 a OD3, y se utilizan para
la lectura de datos desde las tarjetas del montaje. Los hilos OD7 a OD4 se emplean en
la tarjeta de BER para leer los bytes nibble a nibble (de cuatro en cuatro bits). El hilo
OD3 se utiliza con la placa de modulación DDS, leyéndose desde esa tarjeta los datos de
entrada bit a bit. Esta selección no se ha hecho de forma caprichosa, sino que, como se
ha podido comprobar, ha venido impuesta por la construcción hardware de los integrados
utilizados en la práctica.
6
Invertida por el hardware
7
Señal activa a nivel bajo
A.5 Utilización particular en la aplicación 154
Para terminar, los hilos de control son cuatro, LATH3 a LATH0, y se emplean en
la carga y demultiplexación de los hilos de datos. LATCH3 y LATCH2 son los hilos de
selección de registro dentro de cada tarjeta. LATCH1 carga el contenido del bus de datos
en el registro seleccionado de la placa DDS, y LATCH0 realiza la misma función pero en
este caso con la tarjeta de BER. Estos dos últimos hilos realizan la función de terminales
de selección de tarjeta. En la figura A.3 se representa esquemáticamente la conexión del
puerto paralelo en nuestra aplicación.
155
156
Figura B.1: Vista general del montaje que contiene las placas DDS y BER
Figura B.2: Vista interior donde se pueden distinguir las dos placas
157
Figura B.3: Lateral del chasis donde se pueden observar el conector de salida
de IF y los interfaces de datos de las dos placas
Figura B.4: Lateral del chasis que contiene los conectores de control y ali-
mentación
Pin DB-25 Señal SPP Original Aplicación Sentido Registro Inv. Hardware 1
Pin Función
Tip +12 voltios DC
Ring Masa
Listados fuente
En este apartado se incluyen los listados fuentes de las dos aplicación de control
desarrolladas, modulAD para la placa de modulación DDS y mediBER para la placa de
BER, junto con los ficheros de comandos de Matlab utilizados en la simulación de los
distintos bloques del modulador DDS AD9853.
//DEFINICIONES DE TIPOS
//DECLARACION DE FUNCIONES
void inicializa(int inic);
//VARIABLES GLOBALES
// Del módulo de funciones hardware
extern double esc, esc_old;
// Propias
// Gestion de paneles
static int panel_conf, panel_fir, panel_frec, panel_principal, panel_scr, panel_vel, err;
char puerto_control;
159
C.1 Aplicación modulAD 160
// Inicialización
inicio = SI;
// Utilizamos el puerto paralelo LPT1
puerto_control = 1;
inicializa(SI);
inicio = NO;
// Arranque de la presentación
DisplayPanel (panel_principal);
RunUserInterface ();
return 0;
}
/****************************************************************************
DESCRIPCION DE LAS FUNCIONES
****************************************************************************/
/****************************************************************************
FUNCION: inicializa
DESCRIPCION: Realiza la secuencia de inicialización de la aplicación
C.1 Aplicación modulAD 161
PARAMETROS DE ENTRADA:
PARAMETROS DE SALIDA:
RESULTADO Y ERRORES:
OBSERVACIONES:
****************************************************************************/
void inicializa(int inic) {
unsigned short byte;
byte=0x0;
DlPortWritePortUchar(pp_datos, byte);
byte=DlPortReadPortUchar(pp_estado);
byte=DlPortReadPortUchar(pp_control);
//byte=byte & 0xF0;
byte=byte & 0xD0;
byte=byte | 0x8;
DlPortWritePortUchar(pp_control, byte);
// Inicialización de variables
inicia_hard();
// Inicialización de parámetro de escalado en modulador
esc = 1;
/****************************************************************************
FUNCIONES CVICALLBACK
****************************************************************************/
/****************************************************************************
FUNCION: PulsaFrec
DESCRIPCION: Muestra el panel donde se programa la frecuencia de salida del
modulador
PARAMETROS DE ENTRADA: Los usuales en una función callback
PARAMETROS DE SALIDA:
RESULTADO Y ERRORES: Entero 0, todo OK
OBSERVACIONES:
****************************************************************************/
int CVICALLBACK PulsaFrec (int panel, int control, int event,
void *callbackData, int eventData1, int eventData2)
{
static char panel_visible;
switch (event) {
case EVENT_COMMIT:
if (panel_visible) {
HidePanel(panel_frec);
panel_visible = NO;
}
else {
DisplayPanel (panel_frec);
panel_visible = SI;
}
break;
C.1 Aplicación modulAD 163
case EVENT_RIGHT_CLICK:
break;
}
return 0;
}
/****************************************************************************
FUNCION: PulsaFec
DESCRIPCION: Muestra el panel donde se programan la habilitación o no del
aleatorizador y del codificador diferencial del modulador
PARAMETROS DE ENTRADA: Los usuales en una función callback
PARAMETROS DE SALIDA:
RESULTADO Y ERRORES: Entero 0, todo OK
OBSERVACIONES:
****************************************************************************/
int CVICALLBACK PulsaFec (int panel, int control, int event,
void *callbackData, int eventData1, int eventData2)
{
static char panel_visible;
switch (event) {
case EVENT_COMMIT:
if (panel_visible) {
HidePanel(panel_scr);
panel_visible = NO;
}
else {
DisplayPanel (panel_scr);
panel_visible = SI;
}
break;
case EVENT_RIGHT_CLICK:
break;
}
return 0;
}
/****************************************************************************
FUNCION: PulsaVel
DESCRIPCION: Muestra el panel donde se programa el reloj de bit
PARAMETROS DE ENTRADA: Los tı́picos de las funciones callback
PARAMETROS DE SALIDA:
RESULTADO Y ERRORES: Entero 0, todo OK
OBSERVACIONES:
****************************************************************************/
int CVICALLBACK PulsaVel (int panel, int control, int event,
void *callbackData, int eventData1, int eventData2)
{
static char panel_visible;
switch (event) {
case EVENT_COMMIT:
if (panel_visible) {
HidePanel(panel_vel);
panel_visible = NO;
}
else {
DisplayPanel (panel_vel);
panel_visible = SI;
}
break;
case EVENT_RIGHT_CLICK:
break;
}
return 0;
}
/****************************************************************************
C.1 Aplicación modulAD 164
FUNCION: PulsaFir
DESCRIPCION: Ense~
na la pantalla donde se programan los coeficientes del
filtro FIR integrado dentro del modulador
PARAMETROS DE ENTRADA: Es una función callback
PARAMETROS DE SALIDA:
RESULTADO Y ERRORES: Entero 0, todo OK
OBSERVACIONES:
****************************************************************************/
int CVICALLBACK PulsaFir (int panel, int control, int event,
void *callbackData, int eventData1, int eventData2)
{
static char panel_visible;
switch (event) {
case EVENT_COMMIT:
if (panel_visible) {
HidePanel(panel_fir);
panel_visible = NO;
}
else {
DisplayPanel (panel_fir);
panel_visible = SI;
}
break;
case EVENT_RIGHT_CLICK:
break;
}
return 0;
}
/****************************************************************************
FUNCION: PulsaConf
DESCRIPCION: Activa el panel donde se cambian otros parámetros de
configuración.
PARAMETROS DE ENTRADA: Los de las funciones callback
PARAMETROS DE SALIDA:
RESULTADO Y ERRORES: Entero 0, todo OK
OBSERVACIONES:
****************************************************************************/
int CVICALLBACK PulsaConf (int panel, int control, int event,
void *callbackData, int eventData1, int eventData2)
{
static char panel_visible;
switch (event) {
case EVENT_COMMIT:
if (panel_visible) {
HidePanel(panel_conf);
panel_visible = NO;
}
else {
DisplayPanel (panel_conf);
panel_visible = SI;
}
break;
case EVENT_RIGHT_CLICK:
MessagePopup ("Otros parámetros de Configuración",
"Provoca la visualización de otra pantalla donde cambiar \n"
" la configuración de otros parámetros del modem.");
break;
}
return 0;
}
/****************************************************************************
FUNCION: Salida
DESCRIPCION: Cierra la aplicación
PARAMETROS DE ENTRADA: Función callback
C.1 Aplicación modulAD 165
PARAMETROS DE SALIDA:
RESULTADO Y ERRORES: Entero 0, todo OK
OBSERVACIONES:
****************************************************************************/
int CVICALLBACK Salida (int panel, int control, int event,
void *callbackData, int eventData1, int eventData2)
{
switch (event) {
case EVENT_COMMIT:
QuitUserInterface (0);
break;
case EVENT_RIGHT_CLICK:
MessagePopup ("Botón \"SALIDA\"",
" Salida del programa.");
break;
}
return 0;
}
/****************************************************************************
FUNCION: PulsaMod
DESCRIPCION: Cambia el tipo de modulación con el que se modulan los datos de
entrada. Los tipos de modulación implementados en el modulador AD9853 son
FSK, QPSK y 16QAM.
PARAMETROS DE ENTRADA: Tı́picos de funciones callback
PARAMETROS DE SALIDA:
RESULTADO Y ERRORES: Entero 0, todo OK
OBSERVACIONES:
****************************************************************************/
int CVICALLBACK PulsaMod (int panel, int control, int event,
void *callbackData, int eventData1, int eventData2)
{
static int div_var, div_fijo, tipo_mod, factor_div, overfl;
static char txt_modo[7], modulacion, cod_dif;
switch (event) {
case EVENT_COMMIT:
err = GetCtrlVal (panel_principal, PANEL_MOD_PULSA_MOD, &tipo_mod);
err = GetCtrlVal (panel_vel, PANEL_VEL_VALOR_DIV, &div_var);
err = GetCtrlVal (panel_vel, PANEL_VEL_PUL_DIV_2, &div_fijo);
switch (tipo_mod) {
case 0: //FSK
strcpy(txt_modo, "FSK");
modulacion = FSK;
// control_modem[MODO_MOD] = 0x80;
control_modem[MODO_MOD] = control_modem[MODO_MOD] & 0x3F;
control_modem[MODO_MOD] = control_modem[MODO_MOD] | 0x80;
err = SetCtrlAttribute (panel_vel, PANEL_VEL_VALOR_DIV,
ATTR_MAX_VALUE, 2047);
break;
case 1: //QPSK
strcpy(txt_modo, "QPSK");
modulacion = QPSK;
control_modem[MODO_MOD] = control_modem[MODO_MOD] & 0x3F;
// Control de que no nos pasamos de factor de división
if (factor_div > 651 ) {
if (div_fijo) err = SetCtrlVal (panel_vel, PANEL_VEL_VALOR_DIV, 325);
else err = SetCtrlVal (panel_vel, PANEL_VEL_VALOR_DIV, 651);
err = GetCtrlVal (panel_vel, PANEL_VEL_VALOR_DIV, &div_var);
overfl=SI;
}
err = SetCtrlAttribute (panel_vel, PANEL_VEL_VALOR_DIV,
C.1 Aplicación modulAD 166
ATTR_MAX_VALUE, 651);
break;
case 3: //16QAM
strcpy(txt_modo, "16QAM");
modulacion = _16QAM;
control_modem[MODO_MOD] = control_modem[MODO_MOD] & 0x3F;
control_modem[MODO_MOD] = control_modem[MODO_MOD] | 0x40;
// Control de que no nos pasamos de factor de división
if (factor_div > 325 ) {
if (div_fijo) err = SetCtrlVal (panel_vel, PANEL_VEL_VALOR_DIV, 162);
else err = SetCtrlVal (panel_vel, PANEL_VEL_VALOR_DIV, 325);
err = GetCtrlVal (panel_vel, PANEL_VEL_VALOR_DIV, &div_var);
overfl=SI;
}
err = SetCtrlAttribute (panel_vel, PANEL_VEL_VALOR_DIV,
ATTR_MAX_VALUE, 325);
break;
}
// Se ha de actualizar el registro dependiendo de la codificación diferencial
PulsaCodDif (panel_scr, PANEL_SCR_PULSA_COD_DIF, EVENT_COMMIT, 0, 0, 0);
if (overfl) {
switch (tipo_mod) {
case 1:
MessagePopup ("Error al cambiar el tipo de modulación",
"Se superó el valor máximo de división en QPSK.\n"
"Ajustado el divisor variable al máximo valor permitido.");
break;
case 3:
MessagePopup ("Error al cambiar el tipo de modulación",
"Se superó el valor máximo de división en 16QAM.\n"
"Ajustado el divisor variable al máximo valor permitido.");
break;
default:
break;
}
}
/****************************************************************************
FUNCION: TipoScrambler
DESCRIPCION: Permite la selección del tipo de aleatorizador utilizado,
programando a continuación el registro adecuado
PARAMETROS DE ENTRADA: Los tı́picos de las funciones callback.
PARAMETROS DE SALIDA:
RESULTADO Y ERRORES: Entero 0, todo OK
OBSERVACIONES:
****************************************************************************/
int CVICALLBACK TipoScrambler (int panel, int control, int event,
void *callbackData, int eventData1, int eventData2)
{
char tipo_scr;
switch (event) {
C.1 Aplicación modulAD 167
case EVENT_COMMIT:
err = GetCtrlVal (panel_conf, PANEL_CONF_TIPO_SCRAMBLER, &tipo_scr);
switch (tipo_scr) {
case 0:
control_modem[RS_t] = control_modem[RS_t] & 0xFD;
break;
case 1:
control_modem[RS_t] = control_modem[RS_t] | 0x02;
break;
}
// Programación del hardware
prog_hard(RS_t, 1);
break;
case EVENT_RIGHT_CLICK:
break;
}
return 0;
}
/****************************************************************************
FUNCION: SwitchSpectrum
DESCRIPCION: Actualiza la variable de selección del espectro de salida,
programando el registro implicado.
PARAMETROS DE ENTRADA: Los tı́picos de una callback.
PARAMETROS DE SALIDA:
RESULTADO Y ERRORES: Entero 0, todo OK
OBSERVACIONES:
****************************************************************************/
int CVICALLBACK SwitchSpectrum (int panel, int control, int event,
void *callbackData, int eventData1, int eventData2)
{
static char espectro;
switch (event)
{
case EVENT_COMMIT:
// Selección del espectro de salida
err = GetCtrlVal (panel_conf, PANEL_CONF_SWITCH_SPECTRUM, &espectro);
if (espectro == NORMAL) control_modem[CONF] = control_modem[CONF] | 0x80;
else control_modem[CONF] = control_modem[CONF] & 0x7F;
// Programación del hardware
prog_hard(CONF, 1);
break;
case EVENT_RIGHT_CLICK:
MessagePopup ("Espectro de salida",
"Selección del espectro: Normal Icos - Qsen; Invertido Icos + Qsen.");
break;
}
return 0;
}
/****************************************************************************
FUNCION: SwitchDac
DESCRIPCION: Permite activar o poner en modo shutdown el AD9853
PARAMETROS DE ENTRADA:
PARAMETROS DE SALIDA:
RESULTADO Y ERRORES: Entero 0, todo OK
OBSERVACIONES: Ahorra energı́a cuando no se necesita la se~
nal de salida
****************************************************************************/
int CVICALLBACK SwitchDac (int panel, int control, int event,
void *callbackData, int eventData1, int eventData2)
{
static char rf_sleep;
switch (event)
{
case EVENT_COMMIT:
// Modo de funcionamiento del DAC de salida
C.1 Aplicación modulAD 168
break;
case EVENT_RIGHT_CLICK:
break;
}
return 0;
}
/****************************************************************************
FUNCION: ValorFrecRef
DESCRIPCION: Actualiza la presentación de la velocidad de datos y de la
frecuencia de referencia como consecuencia de una modificación de esta
última.
PARAMETROS DE ENTRADA: Los corrientes de una función callback
PARAMETROS DE SALIDA:
RESULTADO Y ERRORES: 0, OK
OBSERVACIONES:
****************************************************************************/
int CVICALLBACK ValorFrecRef (int panel, int control, int event,
void *callbackData, int eventData1, int eventData2)
{
static double frec_ref;
switch (event) {
case EVENT_COMMIT:
// Obtenemos la nueva frecuencia de referencia
err = GetCtrlVal (panel_conf, PANEL_CONF_VALOR_FREC_REF, &frec_ref);
break;
case EVENT_RIGHT_CLICK:
MessagePopup ("Frecuencia de Referencia",
"Este valor se debe actualizar adecuadamente cada vez que se cambie\n"
"el cristal de referencia de la placa del modem, o se utilize una frecuencia\n"
" de referencia externa distinta.");
break;
}
return 0;
}
/****************************************************************************
FUNCION: ValorFrecMarca
DESCRIPCION: Calcula el valor a programar en el registro de frecuencia
secundario utilizado en FSK, y carga el registro con el contenido
C.1 Aplicación modulAD 169
adecuado.
PARAMETROS DE ENTRADA: Los tı́picos de las funciones callback.
PARAMETROS DE SALIDA:
RESULTADO Y ERRORES: Entero 0, todo OK
OBSERVACIONES:
****************************************************************************/
int CVICALLBACK ValorFrecMarca (int panel, int control, int event,
void *callbackData, int eventData1, int eventData2)
{
static double frec_marca, frec_ref;
switch (event) {
case EVENT_COMMIT:
// Obtenemos la nueva frecuencia de referencia
err = GetCtrlVal (panel_frec, PANEL_FREC_VALOR_FREC_MARCA, &frec_marca);
err = GetCtrlVal (panel_conf, PANEL_CONF_VALOR_FREC_REF, &frec_ref);
// Carga del hardware
frec_32 (frec_marca, NRO_BITS, F1_0, frec_ref);
prog_hard(F1_0, 4);
break;
case EVENT_RIGHT_CLICK:
break;
}
return 0;
}
/****************************************************************************
FUNCION: ValorFrec
DESCRIPCION: Calcula el valor a programar en el registro de frecuencia
y carga el registro con el contenido adecuado.
PARAMETROS DE ENTRADA: Los tı́picos de las funciones callback.
PARAMETROS DE SALIDA:
RESULTADO Y ERRORES: Entero 0, todo OK
OBSERVACIONES:
****************************************************************************/
int CVICALLBACK ValorFrec (int panel, int control, int event,
void *callbackData, int eventData1, int eventData2)
{
static double frec_sal, frec_ref;
static char txt_frec_sal[50];
switch (event) {
case EVENT_COMMIT:
err = GetCtrlVal (panel_frec, PANEL_FREC_VALOR_FREC, &frec_sal);
err = GetCtrlVal (panel_conf, PANEL_CONF_VALOR_FREC_REF, &frec_ref);
// Entorno gráfico
Fmt (txt_frec_sal, "%s<%f[w14p4]", frec_sal);
if (hay_placa_mod) err = SetCtrlVal (panel_principal,
PANEL_MOD_TEXT_FREC_VAL, txt_frec_sal);
// Carga del hardware
frec_32 (frec_sal, NRO_BITS, F0_0, frec_ref);
prog_hard(F0_0, 4);
break;
case EVENT_RIGHT_CLICK:
break;
}
return 0;
}
/****************************************************************************
FUNCION: PulsaCodDif
DESCRIPCION: Permite habilitar / deshabilitar el codificador diferencial
PARAMETROS DE ENTRADA: Los tı́picos de las funciones callback.
PARAMETROS DE SALIDA:
RESULTADO Y ERRORES: Entero 0, todo OK
OBSERVACIONES:
****************************************************************************/
int CVICALLBACK PulsaCodDif (int panel, int control, int event,
C.1 Aplicación modulAD 170
switch (event) {
case EVENT_COMMIT:
err = GetCtrlVal (panel_scr, PANEL_SCR_PULSA_COD_DIF, &cod_dif);
err = GetCtrlVal (panel_principal, PANEL_MOD_PULSA_MOD, &tipo_mod);
switch (cod_dif) {
case 0:
strcpy(txt_cod, "OFF");
switch (tipo_mod) {
case 0: break; //FSK
default: control_modem[MODO_MOD] = control_modem[MODO_MOD] & 0xC0; break; //QPSK
}
break;
case 1:
strcpy(txt_cod, "ON");
switch (tipo_mod) {
case 0: break; //FSK
default: control_modem[MODO_MOD] = control_modem[MODO_MOD] | 0x20; break; // DQPSK
}
break;
}
// Programación del hardware
prog_hard(MODO_MOD, 1);
// Entorno gráfico
if (hay_placa_mod) err = SetCtrlVal (panel_principal,
PANEL_MOD_TEXT_COD_VAL, txt_cod);
break;
case EVENT_RIGHT_CLICK:
break;
}
return 0;
}
/****************************************************************************
FUNCION: PulsaScr
DESCRIPCION: Permite habilitar / deshabilitar el aleatorizador (scrambler),
programando a continuación el registro del chip implicado
PARAMETROS DE ENTRADA: Los tı́picos de las funciones callback.
PARAMETROS DE SALIDA:
RESULTADO Y ERRORES: Entero 0, todo OK
OBSERVACIONES:
****************************************************************************/
int CVICALLBACK PulsaScr (int panel, int control, int event,
void *callbackData, int eventData1, int eventData2)
{
static char txt_scr[4], scr;
switch (event) {
case EVENT_COMMIT:
err = GetCtrlVal (panel_scr, PANEL_SCR_PULSA_SCR, &scr);
switch (scr) {
case 0:
strcpy(txt_scr, "OFF");
control_modem[RS_t] = control_modem[RS_t] | 0x04;
break;
case 1:
strcpy(txt_scr, "ON");
control_modem[RS_t] = control_modem[RS_t] & 0xFB;
break;
}
if (hay_placa_mod) err = SetCtrlVal (panel_principal,
PANEL_MOD_TEXT_SCR_VAL, txt_scr);
// Programación del hardware
prog_hard(RS_t, 1);
C.1 Aplicación modulAD 171
break;
case EVENT_RIGHT_CLICK:
break;
}
return 0;
}
/****************************************************************************
FUNCION: ValorDiv
DESCRIPCION: Permite cambiar el valor del divisor principal para generar la
frecuencia de bit. A continuación carga en la placa del modulador los
datos adecuados.
PARAMETROS DE ENTRADA:
PARAMETROS DE SALIDA:
RESULTADO Y ERRORES: 0, OK
OBSERVACIONES:
****************************************************************************/
int CVICALLBACK ValorDiv (int panel, int control, int event,
void *callbackData, int eventData1, int eventData2)
{
static double frec_ref, dato_clock;
static int div_var, div_fijo, tipo_mod, factor_I1I2;
static char txt_vel_datos[50], modulacion;
switch (event) {
case EVENT_COMMIT:
err = GetCtrlVal (panel_vel, PANEL_VEL_VALOR_DIV, &div_var);
// Demás parámetros necesarios para configurar el modem a las nuevas condiciones
err = GetCtrlVal (panel_conf, PANEL_CONF_VALOR_FREC_REF, &frec_ref);
err = GetCtrlVal (panel_vel, PANEL_VEL_PUL_DIV_2, &div_fijo);
err = GetCtrlVal (panel_principal, PANEL_MOD_PULSA_MOD, &tipo_mod);
switch (tipo_mod) {
case 0: modulacion = FSK; break;
case 1: modulacion = QPSK; break;
case 3: modulacion = _16QAM; break;
default: modulacion = FSK;
}
switch (err) {
/* -1 Número resultante es primo "para los interpoladores" y por tanto
corresponde a un factor de interpolación total no válido
-2 El tipo de modulación es FSK. En este caso la función no tiene
ningún efecto.
-3 El tipo de modulación es QPSK y el valor de división total es
mayor de 651.
-4 El tipo de modulación es 16QAM y el valor de división total es
mayor de 325. */
case -1:
MessagePopup ("Error al cambiar la velocidad de transmisión",
"El comando de división es un valor no permitido.\n"
"Ajustado el factor de división total por defecto.");
break;
case -3:
MessagePopup ("Error al cambiar la velocidad de transmisión",
"Se superó el valor máximo de división permitido en QPSK.\n"
"Ajustado el divisor variable al valor máximo permitido.");
break;
case -4:
MessagePopup ("Error al cambiar la velocidad de transmisión",
"Se superó el valor máximo de división permitido en 16QAM.\n"
"Ajustado el divisor variable al valor máximo permitido.");
break;
}
C.1 Aplicación modulAD 172
// Entorno gráfico
if (hay_placa_mod) {
err = SetCtrlVal (panel_vel, PANEL_VEL_VALOR_VEL_DAT, dato_clock);
Fmt (txt_vel_datos, "%s<%f[w14p4]", dato_clock);
err = SetCtrlVal (panel_principal, PANEL_MOD_TEXT_VEL_VAL, txt_vel_datos);
}
break;
case EVENT_RIGHT_CLICK:
break;
}
return 0;
}
/****************************************************************************
FUNCION: PulDiv2
DESCRIPCION: Pone de manifiesto el efecto producido al activar/desactivar
mediante el puente hardware JP2 el divisor adicional por 2 en el
generador de reloj de bit.
PARAMETROS DE ENTRADA: Es una función callback
PARAMETROS DE SALIDA:
RESULTADO Y ERRORES: 0, OK
OBSERVACIONES:
****************************************************************************/
int CVICALLBACK PulDiv2 (int panel, int control, int event,
void *callbackData, int eventData1, int eventData2)
{
static double frec_ref, dato_clock;
static int div_var, div_fijo, tipo_mod;
static char txt_vel_datos[50], modulacion;
switch (event) {
case EVENT_COMMIT:
err = GetCtrlVal (panel_vel, PANEL_VEL_PUL_DIV_2, &div_fijo);
// Demás parámetros necesarios para configurar el modem a las nuevas condiciones
if (div_fijo == 1) {
SetCtrlVal (panel_vel, PANEL_VEL_MENSG_2, "JP2 pines 3-4");
C.1 Aplicación modulAD 173
/****************************************************************************
FUNCION: PulsaFrecOk
DESCRIPCION: Oculta el panel de la sintonı́a de frecuencia
PARAMETROS DE ENTRADA:
PARAMETROS DE SALIDA:
RESULTADO Y ERRORES: 0, ok
OBSERVACIONES:
****************************************************************************/
int CVICALLBACK PulsaFrecOk (int panel, int control, int event,
void *callbackData, int eventData1, int eventData2)
{
switch (event) {
case EVENT_COMMIT:
PulsaFrec (panel_principal, PANEL_MOD_PULSA_FREC, EVENT_COMMIT, 0, 0, 0);
break;
case EVENT_RIGHT_CLICK:
break;
}
return 0;
}
/****************************************************************************
FUNCION: PulsaOk
DESCRIPCION: Oculta el panel de configuración
PARAMETROS DE ENTRADA:
PARAMETROS DE SALIDA:
RESULTADO Y ERRORES: 0, OK
OBSERVACIONES:
****************************************************************************/
int CVICALLBACK PulsaOk (int panel, int control, int event,
void *callbackData, int eventData1, int eventData2)
{
switch (event) {
case EVENT_COMMIT:
PulsaConf (panel_principal, PANEL_MOD_PULSA_CONF, EVENT_COMMIT, 0, 0, 0);
break;
case EVENT_RIGHT_CLICK:
break;
}
return 0;
}
/****************************************************************************
FUNCION: PulsaFirOk
DESCRIPCION: Oculta el panel de programación de los coeficientes del filtro FIR
PARAMETROS DE ENTRADA:
PARAMETROS DE SALIDA:
RESULTADO Y ERRORES: 0, OK
OBSERVACIONES:
****************************************************************************/
C.1 Aplicación modulAD 174
/****************************************************************************
FUNCION: PulsaVelOk
DESCRIPCION: Oculta el panel de programación del generador de reloj de bit
PARAMETROS DE ENTRADA:
PARAMETROS DE SALIDA:
RESULTADO Y ERRORES: 0, OK
OBSERVACIONES:
****************************************************************************/
int CVICALLBACK PulsaVelOk (int panel, int control, int event,
void *callbackData, int eventData1, int eventData2)
{
switch (event) {
case EVENT_COMMIT:
PulsaVel (panel_principal, PANEL_MOD_PULSA_VEL, EVENT_COMMIT, 0, 0, 0);
break;
case EVENT_RIGHT_CLICK:
break;
}
return 0;
}
/****************************************************************************
FUNCION: PulsaScrOk
DESCRIPCION: Oculta el panel desde el que se habilitan/deshabilitan el
scrambler y el codificador diferencial
PARAMETROS DE ENTRADA:
PARAMETROS DE SALIDA:
RESULTADO Y ERRORES: 0, OK
OBSERVACIONES:
****************************************************************************/
int CVICALLBACK PulsaScrOk (int panel, int control, int event,
void *callbackData, int eventData1, int eventData2)
{
switch (event) {
case EVENT_COMMIT:
PulsaFec (panel_principal, PANEL_MOD_PULSA_FEC, EVENT_COMMIT, 0, 0, 0);
break;
case EVENT_RIGHT_CLICK:
break;
}
return 0;
}
/****************************************************************************
FUNCION: ValorFirAx
DESCRIPCION: Modifican el coeficiente x del filtro FIR de que consta el
modulador AD9853
PARAMETROS DE ENTRADA: Los tı́picos de las funciones Callback
PARAMETROS DE SALIDA:
RESULTADO Y ERRORES:
OBSERVACIONES: Se "escala" el dato introducido en el panel frontal según
los valores que estén programados en los dos interpoladores del integrado
****************************************************************************/
int CVICALLBACK ValorFirA0 (int panel, int control, int event,
void *callbackData, int eventData1, int eventData2)
C.1 Aplicación modulAD 175
{
static short dos_bytes;
switch (event) {
case EVENT_COMMIT:
err = GetCtrlVal (panel_fir, PANEL_FIR_VALOR_FIR_A0, &dos_bytes);
// Escalado del valor
dos_bytes = dos_bytes / esc_old;
dos_bytes = dos_bytes * esc;
control_modem[FIR_A00_L] = dos_bytes & 0xFF;
dos_bytes = dos_bytes >> 2;
control_modem[FIR_A00_H] = dos_bytes & 0xC0;
// Programación del hardware
prog_hard(FIR_A00_L, 2);
break;
case EVENT_RIGHT_CLICK:
break;
}
return 0;
}
switch (event) {
case EVENT_COMMIT:
err = GetCtrlVal (panel_fir, PANEL_FIR_VALOR_FIR_A1, &dos_bytes);
// Escalado del valor
dos_bytes = dos_bytes / esc_old;
dos_bytes = dos_bytes * esc;
control_modem[FIR_A01_L] = dos_bytes & 0xFF;
dos_bytes = dos_bytes >> 2;
control_modem[FIR_A01_H] = dos_bytes & 0xC0;
// Programación del hardware
prog_hard(FIR_A01_L, 2);
break;
case EVENT_RIGHT_CLICK:
break;
}
return 0;
}
switch (event) {
case EVENT_COMMIT:
err = GetCtrlVal (panel_fir, PANEL_FIR_VALOR_FIR_A2, &dos_bytes);
// Escalado del valor
dos_bytes = dos_bytes / esc_old;
dos_bytes = dos_bytes * esc;
control_modem[FIR_A02_L] = dos_bytes & 0xFF;
dos_bytes = dos_bytes >> 2;
control_modem[FIR_A02_H] = dos_bytes & 0xC0;
// Programación del hardware
prog_hard(FIR_A02_L, 2);
break;
case EVENT_RIGHT_CLICK:
break;
}
return 0;
C.1 Aplicación modulAD 176
switch (event) {
case EVENT_COMMIT:
err = GetCtrlVal (panel_fir, PANEL_FIR_VALOR_FIR_A3, &dos_bytes);
// Escalado del valor
dos_bytes = dos_bytes / esc_old;
dos_bytes = dos_bytes * esc;
control_modem[FIR_A03_L] = dos_bytes & 0xFF;
dos_bytes = dos_bytes >> 2;
control_modem[FIR_A03_H] = dos_bytes & 0xC0;
// Programación del hardware
prog_hard(FIR_A03_L, 2);
break;
case EVENT_RIGHT_CLICK:
break;
}
return 0;
}
switch (event) {
case EVENT_COMMIT:
err = GetCtrlVal (panel_fir, PANEL_FIR_VALOR_FIR_A4, &dos_bytes);
// Escalado del valor
dos_bytes = dos_bytes / esc_old;
dos_bytes = dos_bytes * esc;
control_modem[FIR_A04_L] = dos_bytes & 0xFF;
dos_bytes = dos_bytes >> 2;
control_modem[FIR_A04_H] = dos_bytes & 0xC0;
// Programación del hardware
prog_hard(FIR_A04_L, 2);
break;
case EVENT_RIGHT_CLICK:
break;
}
return 0;
}
switch (event) {
case EVENT_COMMIT:
err = GetCtrlVal (panel_fir, PANEL_FIR_VALOR_FIR_A5, &dos_bytes);
// Escalado del valor
dos_bytes = dos_bytes / esc_old;
dos_bytes = dos_bytes * esc;
control_modem[FIR_A05_L] = dos_bytes & 0xFF;
dos_bytes = dos_bytes >> 2;
control_modem[FIR_A05_H] = dos_bytes & 0xC0;
// Programación del hardware
prog_hard(FIR_A05_L, 2);
break;
case EVENT_RIGHT_CLICK:
C.1 Aplicación modulAD 177
break;
}
return 0;
}
switch (event) {
case EVENT_COMMIT:
err = GetCtrlVal (panel_fir, PANEL_FIR_VALOR_FIR_A6, &dos_bytes);
// Escalado del valor
dos_bytes = dos_bytes / esc_old;
dos_bytes = dos_bytes * esc;
control_modem[FIR_A06_L] = dos_bytes & 0xFF;
dos_bytes = dos_bytes >> 2;
control_modem[FIR_A06_H] = dos_bytes & 0xC0;
// Programación del hardware
prog_hard(FIR_A06_L, 2);
break;
case EVENT_RIGHT_CLICK:
break;
}
return 0;
}
switch (event) {
case EVENT_COMMIT:
err = GetCtrlVal (panel_fir, PANEL_FIR_VALOR_FIR_A7, &dos_bytes);
// Escalado del valor
dos_bytes = dos_bytes / esc_old;
dos_bytes = dos_bytes * esc;
control_modem[FIR_A07_L] = dos_bytes & 0xFF;
dos_bytes = dos_bytes >> 2;
control_modem[FIR_A07_H] = dos_bytes & 0xC0;
// Programación del hardware
prog_hard(FIR_A07_L, 2);
break;
case EVENT_RIGHT_CLICK:
break;
}
return 0;
}
switch (event) {
case EVENT_COMMIT:
err = GetCtrlVal (panel_fir, PANEL_FIR_VALOR_FIR_A8, &dos_bytes);
// Escalado del valor
dos_bytes = dos_bytes / esc_old;
dos_bytes = dos_bytes * esc;
control_modem[FIR_A08_L] = dos_bytes & 0xFF;
dos_bytes = dos_bytes >> 2;
control_modem[FIR_A08_H] = dos_bytes & 0xC0;
C.1 Aplicación modulAD 178
break;
}
return 0;
}
switch (event) {
case EVENT_COMMIT:
err = GetCtrlVal (panel_fir, PANEL_FIR_VALOR_FIR_A9, &dos_bytes);
// Escalado del valor
dos_bytes = dos_bytes / esc_old;
dos_bytes = dos_bytes * esc;
control_modem[FIR_A09_L] = dos_bytes & 0xFF;
dos_bytes = dos_bytes >> 2;
control_modem[FIR_A09_H] = dos_bytes & 0xC0;
// Programación del hardware
prog_hard(FIR_A09_L, 2);
break;
case EVENT_RIGHT_CLICK:
break;
}
return 0;
}
switch (event) {
case EVENT_COMMIT:
err = GetCtrlVal (panel_fir, PANEL_FIR_VALOR_FIR_A10, &dos_bytes);
// Escalado del valor
dos_bytes = dos_bytes / esc_old;
dos_bytes = dos_bytes * esc;
control_modem[FIR_A10_L] = dos_bytes & 0xFF;
dos_bytes = dos_bytes >> 2;
control_modem[FIR_A10_H] = dos_bytes & 0xC0;
// Programación del hardware
prog_hard(FIR_A10_L, 2);
break;
case EVENT_RIGHT_CLICK:
break;
}
return 0;
}
switch (event) {
case EVENT_COMMIT:
err = GetCtrlVal (panel_fir, PANEL_FIR_VALOR_FIR_A11, &dos_bytes);
// Escalado del valor
dos_bytes = dos_bytes / esc_old;
C.1 Aplicación modulAD 179
break;
}
return 0;
}
switch (event) {
case EVENT_COMMIT:
err = GetCtrlVal (panel_fir, PANEL_FIR_VALOR_FIR_A12, &dos_bytes);
// Escalado del valor
dos_bytes = dos_bytes / esc_old;
dos_bytes = dos_bytes * esc;
control_modem[FIR_A12_L] = dos_bytes & 0xFF;
dos_bytes = dos_bytes >> 2;
control_modem[FIR_A12_H] = dos_bytes & 0xC0;
// Programación del hardware
prog_hard(FIR_A12_L, 2);
break;
case EVENT_RIGHT_CLICK:
break;
}
return 0;
}
switch (event) {
case EVENT_COMMIT:
err = GetCtrlVal (panel_fir, PANEL_FIR_VALOR_FIR_A13, &dos_bytes);
// Escalado del valor
dos_bytes = dos_bytes / esc_old;
dos_bytes = dos_bytes * esc;
control_modem[FIR_A13_L] = dos_bytes & 0xFF;
dos_bytes = dos_bytes >> 2;
control_modem[FIR_A13_H] = dos_bytes & 0xC0;
// Programación del hardware
prog_hard(FIR_A13_L, 2);
break;
case EVENT_RIGHT_CLICK:
break;
}
return 0;
}
switch (event) {
C.1 Aplicación modulAD 180
case EVENT_COMMIT:
err = GetCtrlVal (panel_fir, PANEL_FIR_VALOR_FIR_A14, &dos_bytes);
// Escalado del valor
dos_bytes = dos_bytes / esc_old;
dos_bytes = dos_bytes * esc;
control_modem[FIR_A14_L] = dos_bytes & 0xFF;
dos_bytes = dos_bytes >> 2;
control_modem[FIR_A14_H] = dos_bytes & 0xC0;
// Programación del hardware
prog_hard(FIR_A14_L, 2);
break;
case EVENT_RIGHT_CLICK:
break;
}
return 0;
}
switch (event) {
case EVENT_COMMIT:
err = GetCtrlVal (panel_fir, PANEL_FIR_VALOR_FIR_A15, &dos_bytes);
// Escalado del valor
dos_bytes = dos_bytes / esc_old;
dos_bytes = dos_bytes * esc;
control_modem[FIR_A15_L] = dos_bytes & 0xFF;
dos_bytes = dos_bytes >> 2;
control_modem[FIR_A15_H] = dos_bytes & 0xC0;
// Programación del hardware
prog_hard(FIR_A15_L, 2);
break;
case EVENT_RIGHT_CLICK:
break;
}
return 0;
}
switch (event) {
case EVENT_COMMIT:
err = GetCtrlVal (panel_fir, PANEL_FIR_VALOR_FIR_A16, &dos_bytes);
// Escalado del valor
dos_bytes = dos_bytes / esc_old;
dos_bytes = dos_bytes * esc;
control_modem[FIR_A16_L] = dos_bytes & 0xFF;
dos_bytes = dos_bytes >> 2;
control_modem[FIR_A16_H] = dos_bytes & 0xC0;
// Programación del hardware
prog_hard(FIR_A16_L, 2);
break;
case EVENT_RIGHT_CLICK:
break;
}
return 0;
}
{
static short dos_bytes;
switch (event) {
case EVENT_COMMIT:
err = GetCtrlVal (panel_fir, PANEL_FIR_VALOR_FIR_A17, &dos_bytes);
// Escalado del valor
dos_bytes = dos_bytes / esc_old;
dos_bytes = dos_bytes * esc;
control_modem[FIR_A17_L] = dos_bytes & 0xFF;
dos_bytes = dos_bytes >> 2;
control_modem[FIR_A17_H] = dos_bytes & 0xC0;
// Programación del hardware
prog_hard(FIR_A17_L, 2);
break;
case EVENT_RIGHT_CLICK:
break;
}
return 0;
}
switch (event) {
case EVENT_COMMIT:
err = GetCtrlVal (panel_fir, PANEL_FIR_VALOR_FIR_A18, &dos_bytes);
// Escalado del valor
dos_bytes = dos_bytes / esc_old;
dos_bytes = dos_bytes * esc;
control_modem[FIR_A18_L] = dos_bytes & 0xFF;
dos_bytes = dos_bytes >> 2;
control_modem[FIR_A18_H] = dos_bytes & 0xC0;
// Programación del hardware
prog_hard(FIR_A18_L, 2);
break;
case EVENT_RIGHT_CLICK:
break;
}
return 0;
}
switch (event) {
case EVENT_COMMIT:
err = GetCtrlVal (panel_fir, PANEL_FIR_VALOR_FIR_A19, &dos_bytes);
// Escalado del valor
dos_bytes = dos_bytes / esc_old;
dos_bytes = dos_bytes * esc;
control_modem[FIR_A19_L] = dos_bytes & 0xFF;
dos_bytes = dos_bytes >> 2;
control_modem[FIR_A19_H] = dos_bytes & 0xC0;
// Programación del hardware
prog_hard(FIR_A19_L, 2);
break;
case EVENT_RIGHT_CLICK:
break;
}
return 0;
C.1 Aplicación modulAD 182
switch (event) {
case EVENT_COMMIT:
err = GetCtrlVal (panel_fir, PANEL_FIR_VALOR_FIR_A20, &dos_bytes);
// Escalado del valor
dos_bytes = dos_bytes / esc_old;
dos_bytes = dos_bytes * esc;
control_modem[FIR_A20_L] = dos_bytes & 0xFF;
dos_bytes = dos_bytes >> 2;
control_modem[FIR_A20_H] = dos_bytes & 0xC0;
// Programación del hardware
prog_hard(FIR_A20_L, 2);
break;
case EVENT_RIGHT_CLICK:
break;
}
return 0;
}
/****************************************************************************
FUNCION: Bucle
DESCRIPCIÓN: Realiza el chequeo necesario para determinar la existencia
de la placa DDS, actuando en consecuencia sobre la interface de usuario
PARAMETROS DE ENTRADA: Función callback.
PARAMETROS DE SALIDA: No hay
RESULTADO Y ERRORES: 0 OK
OBSERVACIONES:
****************************************************************************/
int CVICALLBACK Bucle (int panel, int control, int event,
void *callbackData, int eventData1, int eventData2)
{
switch (event) {
case EVENT_TIMER_TICK:
hay_placa_mod = busca_equipo_mod();
if (!hay_placa_mod) {
if (primer_bucle) {
primer_bucle = NO; // Control de ejecución del bucle
// Mensaje de error
err = SetCtrlVal (panel_principal, PANEL_MOD_TEXT_FALLO,
"Fallo del puerto de control. Imposible controlar el modulador");
// Display
err = DefaultCtrl (panel_principal, PANEL_MOD_TEXT_FREC_2);
err = DefaultCtrl (panel_principal, PANEL_MOD_TEXT_FREC);
err = DefaultCtrl (panel_principal, PANEL_MOD_TEXT_MOD);
err = DefaultCtrl (panel_principal, PANEL_MOD_TEXT_VEL);
err = DefaultCtrl (panel_principal, PANEL_MOD_TEXT_VEL_2);
err = DefaultCtrl (panel_principal, PANEL_MOD_TEXT_SCR);
err = DefaultCtrl (panel_principal, PANEL_MOD_TEXT_COD);
/****************************************************************************
MODULO: Recopilación de funciones hardware para la aplicacion de control
del modulador a partir del integrado AD9853
FICHERO: mod_hard.c VERSION: 1.0
-----------------------------------------------------------------------------
AUTOR: Juan Luis Tébar FECHA: 27 de Abril del 2000
-----------------------------------------------------------------------------
DESCRIPCION:
****************************************************************************/
#include <userint.h>
#include <ansi_c.h>
#include <utility.h>
#include "DLPORTIO.h"
#include "mod_def.h" // Defines de todo el proyecto
#include "mod_hard_.h"
#include "primo_63.h" // Contiene tablas del fabricante
// Variables importadas
// caracteres reservados para el envı́o de parámetros a los registros del modem
extern unsigned char control_modem[74];
extern unsigned char inicio;
DlPortWritePortUchar(pp_control, byte);
break;
case CHIP2:
byte=byte | 0x0; // Selección de CHIP2 (Ya estaba seleccionado)
DlPortWritePortUchar(pp_control, byte);
break;
case CHIP3:
byte=byte | 0x4; // Selección de CHIP3
DlPortWritePortUchar(pp_control, byte);
break;
default: break;
}
return 0;
}
/****************************************************************************
FUNCION: carga_reg_ser
DESCRIPCION:Realiza la secuencia de selección de registro dentro del integrado
AD9853 para posteriormente escribir o leer datos del mismo.
PARAMETROS DE ENTRADA:
reg: Registro al que se desea acceder a continuación.
PARAMETROS DE SALIDA: No hay
RESULTADO Y ERRORES: Entero -1 error, esclavo no contesta; 0 todo bien
OBSERVACIONES: En esta función se ejecuta la parte común de los ciclos de
lectura y escritura del chip AD9853 tal y como se describe en la página
13 de las hojas de datos del fabricante
****************************************************************************/
int carga_reg_ser(char reg) {
unsigned char un_byte, byte_s;
int n;
// Start.
// linea de reloj a alto
byte_alto = byte_alto | 0x80;
carga_pp(byte_alto, LATCH1, CHIP1);
// linea de datos a bajo
byte_alto = byte_alto & 0xBF; //Datos a uno
byte_alto = byte_alto & 0xDF; //Desactivación de tri-state
carga_pp(byte_alto, LATCH1, CHIP1);
byte_alto = byte_alto | 0x40; //Datos a cero (invierte el hardware)
carga_pp(byte_alto, LATCH1, CHIP1);
// linea de reloj a bajo
byte_alto = byte_alto & 0x7F;
carga_pp(byte_alto, LATCH1, CHIP1);
C.1 Aplicación modulAD 186
return 0;
}
/****************************************************************************
FUNCION: lee_ser
C.1 Aplicación modulAD 187
// Start.
// linea de reloj a alto
byte_alto = byte_alto | 0x80;
carga_pp(byte_alto, LATCH1, CHIP1);
// linea de datos a bajo
byte_alto = byte_alto & 0xBF; //Datos a uno
byte_alto = byte_alto & 0xDF; //Desactivación de tri-state
carga_pp(byte_alto, LATCH1, CHIP1);
byte_alto = byte_alto | 0x40; //Datos a cero (invierte el hardware)
carga_pp(byte_alto, LATCH1, CHIP1);
// linea de reloj a bajo
byte_alto = byte_alto & 0x7F;
carga_pp(byte_alto, LATCH1, CHIP1);
// Inicio del bucle de lectura que se repite tantas veces como registros
// se van a leer, y viene indicado en el parámetro de entrada nro_reg
un_byte = 0x0;
for (m = reg_ini; m < (reg_ini + nro_reg); m++) {
// Puesto que seguimos leyendo datos desde el slave, la lı́nea debe de
// seguir en alta impedancia
// lectura de un byte
C.1 Aplicación modulAD 188
// Stop
// linea de datos a bajo
byte_alto = byte_alto | 0x40; //Datos a cero (invierte el hardware)
carga_pp(byte_alto, LATCH1, CHIP1);
// reloj a alto
byte_alto = byte_alto | 0x80;
carga_pp(byte_alto, LATCH1, CHIP1);
// linea de datos a alto, condición de STOP
byte_alto = byte_alto & 0xBF; //Datos a uno (invierte el hardware)
carga_pp(byte_alto, LATCH1, CHIP1);
// reloj a bajo
byte_alto = byte_alto & 0x7F;
carga_pp(byte_alto, LATCH1, CHIP1);
// linea de datos a alta impedancia
byte_alto = byte_alto | 0x20; //Activación de tri-state
carga_pp(byte_alto, LATCH1, CHIP1);
C.1 Aplicación modulAD 189
return 0;
}
/****************************************************************************
FUNCION: escribe_ser
DESCRIPCION: Realiza la secuencia de escribir datos en los registros del
modulador AD9853 a partir del registro seleccionado previamente con la
función carga_reg_ser.
PARAMETROS DE ENTRADA:
reg_ini: registro donde se va a escribir el primer byte.
nro_reg: Número de registros a escribir a partir del cargado como
dirección en la ejecución obligatoria anterior de la función carga_reg_ser.
PARAMETROS DE SALIDA: No hay
RESULTADO Y ERRORES: Entero -1 error; 0 todo bien
OBSERVACIONES: Los valores a escribir son los contenidos en el array de
caracteres global control_modem[], con ı́ndice igual al del registro
escrito.
****************************************************************************/
int escribe_ser(char reg_ini, char nro_reg) {
unsigned char un_byte, byte_s;
int n;
char m;
// Inicio del bucle de escritura que se repite tantas veces como registros
// se van a escribir, y viene indicado en el parámetro de entrada nro_reg
for (m = reg_ini; m < (reg_ini + nro_reg); m++) {
un_byte = control_modem[m];
//Desactivación de tri-state
byte_alto = byte_alto & 0xDF;
carga_pp(byte_alto, LATCH1, CHIP1);
for (n=0; n<8; n++) {
// datos, empezando por el bit mas significativo
if ((un_byte & 0x80)== NO) byte_alto = byte_alto | 0x40;// cero
else byte_alto = byte_alto & 0xBF; // uno
carga_pp(byte_alto, LATCH1, CHIP1);
un_byte = un_byte * 0x2; // Desplazamiento a la derecha
// linea de reloj a alto
byte_alto = byte_alto | 0x80;
carga_pp(byte_alto, LATCH1, CHIP1);
// linea de reloj a bajo
byte_alto = byte_alto & 0x7F;
carga_pp(byte_alto, LATCH1, CHIP1);
}
// Recepción del acknowledge desde el modem esclavo
// linea de datos a alta impedancia
byte_alto = byte_alto | 0x20; //Activación de tri-state
carga_pp(byte_alto, LATCH1, CHIP1);
// reloj a alto
byte_alto = byte_alto | 0x80;
carga_pp(byte_alto, LATCH1, CHIP1);
// lectura de la linea de datos
byte_s=DlPortReadPortUchar(pp_estado);
// reloj a bajo
byte_alto = byte_alto & 0x7F;
carga_pp(byte_alto, LATCH1, CHIP1);
if (byte_s & 0x8) return -1; // esclavo no envió acknowledge
}
//Desactivación de tri-state
byte_alto = byte_alto & 0xDF;
carga_pp(byte_alto, LATCH1, CHIP1);
// Stop
// linea de datos a bajo
byte_alto = byte_alto | 0x40; //Datos a cero (invierte el hardware)
carga_pp(byte_alto, LATCH1, CHIP1);
// reloj a alto
C.1 Aplicación modulAD 190
return 0;
}
/****************************************************************************
FUNCION: activa_txe
DESCRIPCION: Realiza la secuencia de activación (puesta a uno) de la lı́nea TXE
del modulador AD9853. Se debe ejecutar una vez terminados de programar los
registros del integrado para habilitar el funcionamiento del mismo
PARAMETROS DE ENTRADA:
PARAMETROS DE SALIDA: No hay
RESULTADO Y ERRORES: Entero -1 error; 0 todo bien
OBSERVACIONES:
****************************************************************************/
int activa_txe (void) {
byte_alto = byte_alto | 0x10;
carga_pp(byte_alto, LATCH1, CHIP1);
return 0;
}
/****************************************************************************
FUNCION: desactiva_txe
DESCRIPCION: Realiza la desactivación (puesta a cero) de la linea TXE de control
del modulador AD9853. Es condición para programar los registros del chip
PARAMETROS DE ENTRADA:
PARAMETROS DE SALIDA: No hay
RESULTADO Y ERRORES: Entero -1 error; 0 todo bien
OBSERVACIONES:
****************************************************************************/
int desactiva_txe (void) {
byte_alto = byte_alto & 0xEF;
carga_pp(byte_alto, LATCH1, CHIP1);
return 0;
}
/****************************************************************************
FUNCION: reset_9853
DESCRIPCION: Realiza la secuencia de activar-desactivar la linea de reset
del modulador, como punto de partida para programar todos sus registros
a las condiciones de trabajo que se deseen
PARAMETROS DE ENTRADA:
PARAMETROS DE SALIDA: No hay
RESULTADO Y ERRORES: Entero -1 error; 0 todo bien
OBSERVACIONES:
****************************************************************************/
int reset_9853(void) {
byte_alto = byte_alto & 0xF7;
carga_pp(byte_alto, LATCH1, CHIP1);
Delay(0); // Regula la duración del pulso
byte_alto = byte_alto | 0x8;
carga_pp(byte_alto, LATCH1, CHIP1);
return 0;
}
/****************************************************************************
FUNCION: prog_hard
DESCRIPCION: Función base para la programación de los registros del integrado
C.1 Aplicación modulAD 191
/****************************************************************************
FUNCION: inicia_hard
DESCRIPCION: Inicialización de valores que no se modifican a lo largo de la
aplicación por ningún otra función, pero que son necesarios de cargar
a los registros del AD9853.
PARAMETROS DE ENTRADA:
PARAMETROS DE SALIDA:
RESULTADO Y ERRORES:
OBSERVACIONES:
****************************************************************************/
void inicia_hard() {
// Inicialización de la memoria de configuración
control_modem[RS_k]=0xFF;
control_modem[RS_t]=0x02; //RS OFF, Scrambler de 15 bits ON
control_modem[RAND_L]=0xFF; //Valores de inicio del scrambler todo unos
control_modem[RAND_H]=0xFF;
/****************************************************************************
FUNCION: frec_32
DESCRIPCION: Realiza el cálculo del valor a cargar en el registro de
frecuencia
PARAMETROS DE ENTRADA:
val_frec: Es el valor en Hz de la frecuencia a programar
n_bits: Número de bits del registro donde se cargará el valor.
reg: Registro donde cargar el valor calculado. Se necesita la dirección
C.1 Aplicación modulAD 192
/****************************************************************************
FUNCION: gen_bit_clk
DESCRIPCION: Realiza la programación del divisor que crea el reloj de bit
a partir de la frecuencia de referencia existente en la placa del modulador
PARAMETROS DE ENTRADA: .
div_1: número a programar en los divisores del oscilador de referencia
div_2: útil para calcular la velocidad de bit, ya que con él se incluye
el efecto de activar mediante el puente hardware JP3 3-4 la división
adicional por dos que introduce U7A.
frec_ref: double conteniendo la frecuencia de referencia utilizada
PARAMETROS DE SALIDA:
RESULTADO Y ERRORES: double con el valor final de reloj de bit programado.
OBSERVACIONES:
****************************************************************************/
double gen_bit_clk (int div_1, int div_2, double frec_ref) {
static unsigned short dos_bytes;
static unsigned char un_byte;
static int factor_div, n;
static double clk_bit;
return clk_bit;
}
/****************************************************************************
FUNCION: busca_esc
DESCRIPCION: Realiza una tarea de búsqueda de los parámetros de escalado de
la ganancia de cada etapa de interpolación en función del valor de
programación (sobremuestreo) de las mismas.
PARAMETROS DE ENTRADA: int I1, int I2, valor de la interpolación realizada
en cada una de las etapas.
PARAMETROS DE SALIDA:
RESULTADO Y ERRORES: Devuelve el valor resultante de ganancia parcial
correspondiente a los dos valores calculados.
Se actualiza el valor de las variables globales control_modem[INT1_SCALE]
y control_modem[INT2_SCALE], que sirven para programar la ganancia de los
interpoladores.
OBSERVACIONES: La carga del valor al que se actualizan las dos variables
globales dentro de los registros del AD9853 es responsabilidad de la
aplicación de usuario
****************************************************************************/
double busca_esc(int I1, int I2) {
static double gain_tot, gain_1;
static char int1, int2;
return gain_tot;
}
/****************************************************************************
FUNCION: interpolador
DESCRIPCION: Calcula el valor de interpolación de cada etapa para
sobremuestreo de los datos hasta acomodarlos a la frecuencia de reloj
del sistema dentro del AD9853
PARAMETROS DE ENTRADA: int div_1, int div_2, valores seleccionados en los
divisores.
int modulacion, tipo de modulación seleccionada
PARAMETROS DE SALIDA:
RESULTADO Y ERRORES:
0 No se produjo error
-1 Número resultante es primo "para los interpoladores" y por tanto
corresponde a un factor de interpolación total no válido
-2 El tipo de modulación es FSK. En este caso la función no tiene
ningún efecto.
-3 El tipo de modulación es QPSK y el valor de división total es
mayor de 651.
-4 El tipo de modulación es 16QAM y el valor de división total es
mayor de 325.
hecho=NO;
correccion=NO;
do {
// Cálculo del factor de interpolación global
if (div_2==SI) factor_I1I2 = *div_1 * 2;
else factor_I1I2 = *div_1; // División total realizada en generador de reloj de bit
if (modulacion == QPSK) {
factor_I1I2 = factor_I1I2 * 3; //QPSK
if (factor_I1I2 > 1953) {
if (div_2==SI) *div_1=325;
else *div_1=651;
correccion=33;
}
}
else {
factor_I1I2 = factor_I1I2 * 6; //16QAM
if (factor_I1I2 > 1953) {
if (div_2==SI) *div_1=162;
else *div_1=325;
correccion=66;
}
}
/****************************************************************************
FUNCION: busca_equipo_mod
DESCRIPCION: Función que se ejecuta únicamente para comprobar la correcta
conexión de la placa de medición de BER
PARAMETROS DE ENTRADA:
PARAMETROS DE SALIDA:
RESULTADO Y ERRORES: int 1 si la placa funciona correctamente, 0 si no se
encuentra (porque no está alimentada, o no conectada al puerto paralelo)
OBSERVACIONES:
****************************************************************************/
int busca_equipo_mod(void) {
static unsigned char byte_s, cero, uno;
//Escribimos cero
byte_alto = byte_alto & 0xDF; //Desactivación de tri-state
carga_pp(byte_alto, LATCH1, CHIP1);
byte_alto = byte_alto | 0x40; // cero
carga_pp(byte_alto, LATCH1, CHIP1);
C.1 Aplicación modulAD 196
// Escribimos uno
byte_alto = byte_alto & 0xDF; //Desactivación de tri-state
carga_pp(byte_alto, LATCH1, CHIP1);
byte_alto = byte_alto & 0xBF; // uno
carga_pp(byte_alto, LATCH1, CHIP1);
//DECLARACION DE FUNCIONES
void inicializa(void);
//VARIABLES GLOBALES
static int panel_ber, panel_sec, err;
char puerto_control;
double tiempo_fin_test, tiempo_test;
// Variables de ajuste dentro del bucle periódico. Se hacen globales para poder
// controlar el punto de ejecución al seleccionar algunas opciones de operacion
char hay_test, cambio_sec, primer_seg;
/****************************************************************************
DESCRIPCION DE LAS FUNCIONES
****************************************************************************/
/****************************************************************************
FUNCION: inicializa
DESCRIPCION: Realiza la secuencia de inicialización de la aplicación
PARAMETROS DE ENTRADA: No
PARAMETROS DE SALIDA: No
RESULTADO Y ERRORES: Ninguno
OBSERVACIONES:
****************************************************************************/
void inicializa(void) {
unsigned char byte, n;
// Arranque inicial del bert. Para que se cargen los parámetros por defecto
inicia_hard_bert();
}
/****************************************************************************
DESCRIPCION DE FUNCIONES CVICALLBACK
****************************************************************************/
/****************************************************************************
FUNCION: TipoSecuencia
DESCRIPCION: Selector de la secuencia utilizada al realizar el test de BER
PARAMETROS DE ENTRADA: Los tı́picos de las funciones callback de Labwindows
PARAMETROS DE SALIDA:
RESULTADO Y ERRORES: 0 todo OK
OBSERVACIONES: Si se cambia de secuencia mientras el test está arrancado,
éste se vuelve a reiniciar.
****************************************************************************/
C.2 Aplicación mediBER 199
if (hay_test) habia_test=SI;
else habia_test=NO;
switch (event) {
case EVENT_COMMIT:
// Cambio de variable para mensajes
cambio_sec = SI;
// Se detiene el test para reprogramar
StopTest(panel_ber, BER_STOP_TEST, EVENT_COMMIT, 0, 0, 0);
// Actualización de la configuración del bert
err = GetCtrlVal(panel_ber, BER_TIPO_SECUENCIA, &secuencia);
prog_sec(secuencia, sec_usuario);
// Si el test estaba corriendo se reinicia
if (habia_test) IniciaTest(panel_ber, BER_RUN_TEST, EVENT_COMMIT, 0, 0, 0);
// Cambio de variable para mensajes
cambio_sec = NO;
break;
case EVENT_RIGHT_CLICK:
MessagePopup ("Selector de \"Secuencia patrón\"",
"Permite la selección de la secuencia pseudoaleatoria o repetitiva\n"
"con la que se trabajará al realizar el tests.");
break;
}
return 0;
}
/****************************************************************************
FUNCION: DuracionTest
DESCRIPCION: Selección de la duración del test
PARAMETROS DE ENTRADA: Los tı́picos de las funciones callback de Labwindows
PARAMETROS DE SALIDA:
RESULTADO Y ERRORES: 0 todo OK
OBSERVACIONES: Actualización de la variable global que gobierna la duración
de los test "tiempo_fin_test"
****************************************************************************/
int CVICALLBACK DuracionTest (int panel, int control, int event,
void *callbackData, int eventData1, int eventData2)
{
static int min_test;
switch (event) {
case EVENT_COMMIT:
// Lectura del valor seleccionado.
err = GetCtrlVal(panel_ber, BER_DURACION_TEST, &min_test);
// Actualización de la variable global (representa el tiempo en
// segundos)
tiempo_fin_test = 60.0 * min_test;
break;
case EVENT_RIGHT_CLICK:
MessagePopup ("Selector de \"Duración del test\"",
"Selección del tiempo durante el que se realiza la prueba\n"
"de BER de entre unos perı́odos determinados.");
break;
}
return 0;
}
/****************************************************************************
FUNCION: ErrorAuto
DESCRIPCION: Activa en el DS2172 la inserción automática de errores para
obtener una tasa de BER determinada
PARAMETROS DE ENTRADA: Los tı́picos de las funciones callback de Labwindows
PARAMETROS DE SALIDA:
C.2 Aplicación mediBER 200
switch (event) {
case EVENT_COMMIT:
// Lectura del valor seleccionado.
err = GetCtrlVal(panel_ber, BER_ERROR_AUTO, &valor_err_auto);
error_auto(valor_err_auto);
break;
case EVENT_RIGHT_CLICK:
MessagePopup ("Selector de \"Errores automáticos\"",
"Producción automática de errores hasta "
"conseguir la tasa de BER indicada.");
break;
}
return 0;
}
/****************************************************************************
FUNCION: SecUser
DESCRIPCION: Hace visible u oculta el panel donde se programa la secuencia
repetitiva de usuario.
PARAMETROS DE ENTRADA: Los tı́picos de las funciones callback de Labwindows
PARAMETROS DE SALIDA:
RESULTADO Y ERRORES: 0 todo OK
OBSERVACIONES:
****************************************************************************/
int CVICALLBACK SecUser (int panel, int control, int event,
void *callbackData, int eventData1, int eventData2)
{
static char panel_visible;
switch (event) {
case EVENT_COMMIT:
if (panel_visible) {
HidePanel(panel_sec);
panel_visible = NO;
}
else {
DisplayPanel (panel_sec);
panel_visible = SI;
}
break;
case EVENT_RIGHT_CLICK:
MessagePopup ("Pulsador \"Secuencia usuario\"",
"Hace visible u oculta el panel de selección de la secuencia "
"repetitiva de usuario.");
break;
}
return 0;
}
/****************************************************************************
FUNCION: InsertaError
DESCRIPCION: Provoca la inserción o transmisión intencionada de un único
error en la secuencia de salida.
PARAMETROS DE ENTRADA: Los tı́picos de las funciones callback de Labwindows
PARAMETROS DE SALIDA:
RESULTADO Y ERRORES: 0 todo OK
OBSERVACIONES:
****************************************************************************/
int CVICALLBACK InsertaError (int panel, int control, int event,
void *callbackData, int eventData1, int eventData2)
C.2 Aplicación mediBER 201
{
switch (event) {
case EVENT_COMMIT:
if (hay_test) {
inserta_error();
err_ins++; //Contador para informes
SetCtrlVal (panel_ber, BER_EVENTOS,
"\nError insertado por el usuario");
}
break;
case EVENT_RIGHT_CLICK:
MessagePopup ("Pulsador \"Insertar error\"",
"Inserción manual de un error en la secuencia de salida.");
break;
}
return 0;
}
/****************************************************************************
FUNCION: GrabaRes
DESCRIPCION: Genera un fichero de texto a modo de informe con los resultados
que actualente presentan los indicadores de la aplicación.
PARAMETROS DE ENTRADA: Función callback
PARAMETROS DE SALIDA:
RESULTADO Y ERRORES: 0 todo OK
OBSERVACIONES: El fichero generado se crea en modo escritura, de modo que si
existe un fichero anterior con el mismo nombre se perderá este último.
****************************************************************************/
int CVICALLBACK GrabaRes (int panel, int control, int event,
void *callbackData, int eventData1, int eventData2)
{
static char nombre_file[MAX_PATHNAME_LEN], proj_dir[MAX_PATHNAME_LEN];
static int pfile;
static char aux[MAX_LONG_STRING];
switch (event) {
case EVENT_COMMIT:
GetProjectDir (proj_dir);
if (FileSelectPopup (proj_dir, "*.txt", "*.txt",
"Nombre del Fichero de Informe",
VAL_OK_BUTTON, 0, 1, 1, 0, nombre_file) > 0) {
// Valores programados
err = GetCtrlIndex (panel_ber, BER_TIPO_SECUENCIA, &index);
err = GetLabelFromIndex (panel_ber, BER_TIPO_SECUENCIA, index, aux);
FmtFile (pfile, "%s<%s%s%s",
"Tipo de secuencia utilizada:\t\t\t", aux, "\n");
err = GetCtrlIndex (panel_ber, BER_DURACION_TEST, &index);
err = GetLabelFromIndex (panel_ber, BER_DURACION_TEST, index, aux);
FmtFile (pfile, "%s<%s%s%s",
"Tiempo de duración programada del test:\t\t", aux, "\n");
err = GetCtrlIndex (panel_ber, BER_ERROR_AUTO, &index);
err = GetLabelFromIndex (panel_ber, BER_ERROR_AUTO, index, aux);
FmtFile (pfile, "%s<%s%s%s",
"Inserción de errores automáticos:\t\t", aux, "\n\n");
C.2 Aplicación mediBER 202
// Datos de interés
err = GetCtrlVal (panel_sec, SEC_STRING_SEC, aux);
FmtFile (pfile, "%s<%s%s%s",
"Secuencia de usuario programada:\t\t", aux, "\n");
// Valores resultantes
err = GetCtrlVal (panel_ber, BER_IND_TIEMPO_TEST, aux);
FmtFile (pfile, "%s<%s%s%s",
"Tiempo de duración real del test:\t\t", aux, "\n");
/****************************************************************************
FUNCION: IniciaTest
DESCRIPCION: Activación de las medidas.
PARAMETROS DE ENTRADA: Los tı́picos de las funciones callback de Labwindows
PARAMETROS DE SALIDA:
RESULTADO Y ERRORES: 0 todo OK
OBSERVACIONES:
****************************************************************************/
int CVICALLBACK IniciaTest (int panel, int control, int event,
void *callbackData, int eventData1, int eventData2)
{
switch (event) {
case EVENT_COMMIT:
// Actualización de variables del entorno
hay_test = SI;
primer_seg = SI;
// Inicio del contador de errores manuales para report
err_ins = 0;
/****************************************************************************
FUNCION: StopTest
DESCRIPCION: Finalización de las medidas.
PARAMETROS DE ENTRADA: Los tı́picos de las funciones callback de Labwindows
PARAMETROS DE SALIDA:
RESULTADO Y ERRORES: 0 todo OK
OBSERVACIONES:
****************************************************************************/
int CVICALLBACK StopTest (int panel, int control, int event,
void *callbackData, int eventData1, int eventData2)
{
switch (event) {
case EVENT_COMMIT:
// Cambios hardware para detener el test
stop_test();
C.2 Aplicación mediBER 204
/****************************************************************************
FUNCION: Salida
DESCRIPCION: Finaliza la aplicación
PARAMETROS DE ENTRADA: Los tı́picos de las funciones callback de Labwindows
PARAMETROS DE SALIDA:
RESULTADO Y ERRORES: 0 todo OK
OBSERVACIONES:
****************************************************************************/
int CVICALLBACK Salida (int panel, int control, int event,
void *callbackData, int eventData1, int eventData2)
{
switch (event) {
case EVENT_COMMIT:
QuitUserInterface (0);
break;
case EVENT_RIGHT_CLICK:
MessagePopup ("Pulsador \"Salida Programa\"",
"Fin de aplicación y cierre del entorno gráfico.");
break;
}
return 0;
}
/****************************************************************************
FUNCION: StringSec
DESCRIPCION: Entrada de la secuencia arbitraria de ususario
PARAMETROS DE ENTRADA: Los tı́picos de las funciones callback de Labwindows
PARAMETROS DE SALIDA:
RESULTADO Y ERRORES: 0 todo OK
OBSERVACIONES:
****************************************************************************/
int CVICALLBACK StringSec (int panel, int control, int event,
void *callbackData, int eventData1, int eventData2)
{
static char sec[9], mensaje[80], *fin;
static double valor;
static int secuencia;
switch (event) {
case EVENT_COMMIT:
err = GetCtrlVal(panel_sec, SEC_STRING_SEC, sec);
sec_usuario = strtoul (sec, &fin, 16);
if (*fin != NULL) {
sprintf(mensaje,
"El valor %s no se puede convertir a número hexadecimal", fin);
MessagePopup ("¡ Error al convertir la secuencia !", mensaje);
DefaultCtrl (panel_sec, SEC_STRING_SEC);
}
err = GetCtrlVal(panel_ber, BER_TIPO_SECUENCIA, &secuencia);
if (secuencia == 34) TipoSecuencia(panel_ber,
C.2 Aplicación mediBER 205
/****************************************************************************
FUNCION: PulsaSecOk
DESCRIPCION: Cierra el panel de selección de la secuencia de usuario
PARAMETROS DE ENTRADA: Los tı́picos de las funciones callback de Labwindows
PARAMETROS DE SALIDA:
RESULTADO Y ERRORES: 0 todo OK
OBSERVACIONES:
****************************************************************************/
int CVICALLBACK PulsaSecOk (int panel, int control, int event,
void *callbackData, int eventData1, int eventData2)
{
switch (event) {
case EVENT_COMMIT:
SecUser (panel_ber, BER_PUL_SEC_USER, EVENT_COMMIT, 0, 0, 0);
break;
case EVENT_RIGHT_CLICK:
MessagePopup ("Pulsador \"CERRAR\"",
"Cierre del panel de selección de la secuencia de usuario.");
break;
}
return 0;
}
/****************************************************************************
FUNCION: Bucle
DESCRIPCION: Función principal de la aplicación. Se ejecuta automáticamente
cada segundo, y en ella se realizan varias tareas importantes como la
medición de bits y errores recibidos para calcular todos los indicadores
del test, ası́ como la vigilancia para determinar si la placa de hardware
está correctamente controlada
PARAMETROS DE ENTRADA: Los tı́picos de las funciones callback de Labwindows
PARAMETROS DE SALIDA:
RESULTADO Y ERRORES: 0 todo OK
OBSERVACIONES: Si se determina que la placa no se puede controlar, se detiene
el test y se inhabilitan los controles del entorno gráfico.
Los resultados calculados de tasa de BER y demás inicadores se
almacenan en variables globales para poder ser recuperadas al generar el
fichero de informe.
****************************************************************************/
int CVICALLBACK Bucle (int panel, int control, int event,
void *callbackData, int eventData1, int eventData2)
{
static double seg, min_t, min, horas_t, horas, dias;
static double tiempo_dis;
static double seg_dis, min_t_dis, min_dis, horas_t_dis, horas_dis, dias_dis;
if (event == EVENT_TIMER_TICK) {
hay_placa_ber = busca_equipo_ber();
if (hay_placa_ber) {
if (primer_bucle == NO) {
primer_bucle = SI; // Control de ejecución del bucle
switch (hay_test) {
case SI:
tiempo_test++;
GetCtrlVal(panel_ber, BER_TIPO_SECUENCIA, &secuencia);
// Deshecho de la primera lectura de información desde el chip
if (primer_seg) {
primer_seg = NO;
cambio_periodo = NO;
// Limpiamos los registros del integrado
aplicacion_bert(&datos_estado, secuencia);
// Inicializamos las variables de estadı́stica
tiempo_test = tiempo_dis = 0.0;
datos_estado.bits_rx = 0.0;
datos_estado.bits_err = 0.0;
es = ses = dm = ber = bits_rx_total = bits_err_total = 0.0;
ber_i = ber_60 = 0.0;
disponibilidad = SI;
// Indica estado de disponibilidad del segundo anterior
periodo_anterior = DISPONIBLE;
if (disponibilidad) {
switch (periodo_anterior) {
case DISPONIBLE:
tiempo_dis++;
es = es + es_i_0; //(double)es_i;
ses = ses + (double)ses_i;
// Cálculo del ber
bits_rx_total = bits_rx_total + datos_estado.bits_rx;
bits_err_total = bits_err_total + datos_estado.bits_err;
ber = bits_err_total / bits_rx_total;
// Almacenamiento para tasa de DM
if (!ses_i) {
bits_rx_dm[index_dm] = datos_estado.bits_rx;
bits_err_dm[index_dm] = datos_estado.bits_err;
index_dm++;
if (index_dm == 59) {
index_dm = 0;
for ( n=0, bits_rx_60=0.0, bits_err_60=0.0; n<60;
n++) {
bits_rx_60 = bits_rx_60 + bits_rx_dm[n];
bits_err_60 = bits_err_60 + bits_err_dm[n];
}
ber_60 = bits_err_60 / bits_rx_60;
if (ber_60 > 0.000001) dm = dm + 1.0;
}
}
break;
case NO_DISPONIBLE:
// Los 10 segundos anteriores se suman a las estadı́sticas
tiempo_dis = tiempo_dis + 10.0;
es = es + es_acumul;
ses = ses + (double)ses_acumul; //ses_acumul debe ser cero
// Cálculo del ber
bits_rx_total = bits_rx_total + bits_rx_acumul;
C.2 Aplicación mediBER 208
// Colores de leds
alarma ? SetCtrlVal (panel_ber, BER_LED_SINCRO, OFF)
: SetCtrlVal (panel_ber, BER_LED_SINCRO, ON);
datos_estado.todo_1 ? SetCtrlVal (panel_ber, BER_LED_UNOS, ON)
: SetCtrlVal (panel_ber, BER_LED_UNOS, OFF);
datos_estado.todo_0 ? SetCtrlVal (panel_ber, BER_LED_CEROS, ON)
: SetCtrlVal (panel_ber, BER_LED_CEROS, OFF);
// Entorno gráfico
DefaultCtrl (panel_ber, BER_IND_NRO_BITS);
Fmt (txt_bits_rx, "%s<%f[b4p6e2]", bits_rx_total);
err = SetCtrlVal (panel_ber, BER_IND_NRO_BITS, txt_bits_rx);
/****************************************************************************
MODULO: Recopilación de funciones hardware para la aplicacion de control
del generador de secuencias pseudoaleatorias a partir del DS2172
FICHERO: ber_hard.c VERSION: 1.0
-----------------------------------------------------------------------------
AUTOR: Juan Luis Tébar Garcı́a jltebar@retemail.es
FECHA: 27 de Abril del 2000
-----------------------------------------------------------------------------
DESCRIPCION:
****************************************************************************/
#include <userint.h>
#include <ansi_c.h>
#include <utility.h>
#include "dlportio.h"
#include "ber_def.h"
// Defines de todo el proyecto
#include "ber_hard.h"
return 0;
}
/****************************************************************************
FUNCION: lee_par_bert
DESCRIPCION: Realiza la secuencia de leer datos a través del puerto paralelo,
a partir del registro seleccionado. Las instrucciones están adaptadas
al hardware de la placa de ber.
Los datos se leen a través del puerto de estado.
PARAMETROS DE ENTRADA:
dir: sirve para indicar la "dirección" desde donde se leen los datos, si
desde el bus de datos (sentido desde el pc de control), o desde el
punto de vista de la respuesta del DS2172.
BUS, 1 - se lee el dato puesto en el bus desde el pc de control
DS2172, 0 - se lee el dato puesto en el bus por el integrado DS2172.
reg_ini: registro del que se va a obtener el primer byte leı́do.
nro_reg: Número de registros a leer a partir del valor reg_ini.
PARAMETROS DE SALIDA: No hay
RESULTADO Y ERRORES:
OBSERVACIONES: Los parámetros de entrada reg_ini y nro_reg sólo tienen valor
en el caso de estarse leyendo registros del integrado. Si lo que se lee
es el valor del bus, únicamente se leerá un valor, y éste es justo el que
hay en el bus de datos.
El byte(s) leı́do se almacena siempre en la variable global byte_datos,
y además, si la lectura se realiza sobre los registros del DS2172, sobre
el array, también global, donde se guardan los valores de los contenidos
de los registros control_bert[reg_ini], y superiores si la lectura se
realiza sobre varios registros. En este caso, al final de la función, la
variable byte_datos contendrá el último valor leı́do
****************************************************************************/
int lee_par_bert(char dir, char reg_ini, char nro_reg) {
unsigned char byte_m, byte_l, m;
switch (dir) {
case DS2172: //datos desde DS2172
C.2 Aplicación mediBER 213
// Inicio del bucle de lectura, que se repite tantas veces como registros
// se van a leer, y viene indicado en el parámetro de entrada nro_reg
for (m = (unsigned)reg_ini; m < (reg_ini + nro_reg); m++) {
// Activación de ALE
byte_control = byte_control | 0x08;
carga_pp (byte_control, LATCH0, CHIP0);
byte_datos = byte_m;
control_bert[m] = byte_m;
// Desactivación de #CS
byte_control = byte_control | 0x1;
carga_pp (byte_control, LATCH0, CHIP0);
}
break;
byte_datos = byte_m;
}
return 0;
}
/****************************************************************************
FUNCION: escribe_par_bert
DESCRIPCION: Realiza la secuencia de escribir datos a partir del registro
seleccionado, una cantidad de registros igual al número de entrada
PARAMETROS DE ENTRADA:
reg_ini: registro donde se va a escribir el primer byte.
nro_reg: Número de registros a escribir a partir del valor reg_ini.
PARAMETROS DE SALIDA: No hay
RESULTADO Y ERRORES: Entero -1 error; 0 todo bien
OBSERVACIONES: Los valores a escribir son los contenidos en el array de
caracteres global control_bert[], con ı́ndice igual al del registro
escrito.
****************************************************************************/
int escribe_par_bert(char reg_ini, char nro_reg) {
unsigned char un_byte, m;
int n;
// Inicio del bucle de escritura que se repite tantas veces como registros
// se van a escribir, y viene indicado en el parámetro de entrada nro_reg
for (m = (unsigned)reg_ini; m < (reg_ini + nro_reg); m++) {
// Activación de ALE
byte_control = byte_control | 0x08;
carga_pp (byte_control, LATCH0, CHIP0);
// Desactivación de #CS
byte_control = byte_control | 0x1;
carga_pp (byte_control, LATCH0, CHIP0);
}
return 0;
}
/****************************************************************************
FUNCION: inicia_hard_bert
DESCRIPCION: Carga inicial de los registros del integrado
PARAMETROS DE ENTRADA: Ninguno
PARAMETROS DE SALIDA: Ninguno
RESULTADO Y ERRORES: 0, todo OK
OBSERVACIONES: Necesaria en la inicialización de la aplicación.
Posteriormente el resto de funciones actualiza los registros del integrado
****************************************************************************/
int inicia_hard_bert(void) {
char n;
// Configuración de partida
control_bert[PATTERN_CONTROL] = 0x20;
// No se insertan errores
control_bert[ERROR_INSERT] = 0x00;
control_bert[BIT_ERR_COUNT_3] = 0x00;
control_bert[BIT_ERR_COUNT_2] = 0x00;
control_bert[BIT_ERR_COUNT_1] = 0x00;
control_bert[BIT_ERR_COUNT_0] = 0x00;
control_bert[PATTERN_RX_3] = 0x00;
control_bert[PATTERN_RX_2] = 0x00;
control_bert[PATTERN_RX_1] = 0x00;
control_bert[PATTERN_RX_0] = 0x00;
control_bert[STATUS] = 0x00;
return 0;
}
/****************************************************************************
FUNCION: prog_sec
DESCRIPCION: Cambios en los registros internos del chip para modificar la
secuencia con la que se realizará el test de BER
PARAMETROS DE ENTRADA: int secuencia: Código de secuencia utilizada
unsigned long _4_bytes: valor de la secuencia repetitiva cuando se
selecciona la secuencia arbitraria de usuario.
PARAMETROS DE SALIDA:
RESULTADO Y ERRORES: 0, OK
OBSERVACIONES: Si la secuencia seleccionada no es la de usuario, el parámetro
de entrada _4_bytes es indiferente
****************************************************************************/
int prog_sec (int secuencia, unsigned long _4_bytes) {
static char longitud;
static unsigned long mas_bytes;
switch (secuencia) {
case 1: // Secuencia 2^3 - 1
control_bert[PATTERN_3] = 0xFF;
control_bert[PATTERN_2] = 0xFF;
control_bert[PATTERN_1] = 0xFF;
control_bert[PATTERN_0] = 0xFF;
control_bert[PATTERN_LENGTH] = 0x2;
control_bert[POLYNOMIAL_TAB] = 0x0;
// QRSS=0 y PATTERN SELECT=1
control_bert[PATTERN_CONTROL] = control_bert[PATTERN_CONTROL] & 0xBF;
control_bert[PATTERN_CONTROL] = control_bert[PATTERN_CONTROL] | 0x20;
escribe_par_bert(PATTERN_3, 7);
//TINV=RINV=0
control_bert[ERROR_INSERT] = control_bert[ERROR_INSERT] & 0x0F;
escribe_par_bert(ERROR_INSERT, 1);
break;
case 2: // Secuencia 2^4 - 1
control_bert[PATTERN_3] = 0xFF;
control_bert[PATTERN_2] = 0xFF;
control_bert[PATTERN_1] = 0xFF;
control_bert[PATTERN_0] = 0xFF;
control_bert[PATTERN_LENGTH] = 0x3;
control_bert[POLYNOMIAL_TAB] = 0x0;
// QRSS=0 y PATTERN SELECT=1
control_bert[PATTERN_CONTROL] = control_bert[PATTERN_CONTROL] & 0xBF;
control_bert[PATTERN_CONTROL] = control_bert[PATTERN_CONTROL] | 0x20;
escribe_par_bert(PATTERN_3, 7);
//TINV=RINV=0
control_bert[ERROR_INSERT] = control_bert[ERROR_INSERT] & 0x0F;
escribe_par_bert(ERROR_INSERT, 1);
break;
case 3: // Secuencia 2^5 - 1
control_bert[PATTERN_3] = 0xFF;
control_bert[PATTERN_2] = 0xFF;
control_bert[PATTERN_1] = 0xFF;
control_bert[PATTERN_0] = 0xFF;
control_bert[PATTERN_LENGTH] = 0x4;
control_bert[POLYNOMIAL_TAB] = 0x1;
// QRSS=0 y PATTERN SELECT=1
C.2 Aplicación mediBER 217
control_bert[PATTERN_3] = 0xFF;
control_bert[PATTERN_2] = 0xFF;
control_bert[PATTERN_1] = 0xFF;
control_bert[PATTERN_0] = 0xFF;
control_bert[PATTERN_LENGTH] = 0x8;
control_bert[POLYNOMIAL_TAB] = 0x4;
// QRSS=0 y PATTERN SELECT=1
control_bert[PATTERN_CONTROL] = control_bert[PATTERN_CONTROL] & 0xBF;
control_bert[PATTERN_CONTROL] = control_bert[PATTERN_CONTROL] | 0x20;
escribe_par_bert(PATTERN_3, 7);
//TINV=RINV=0
control_bert[ERROR_INSERT] = control_bert[ERROR_INSERT] & 0x0F;
escribe_par_bert(ERROR_INSERT, 1);
break;
case 9: // Secuencia 2^10 - 1
control_bert[PATTERN_3] = 0xFF;
control_bert[PATTERN_2] = 0xFF;
control_bert[PATTERN_1] = 0xFF;
control_bert[PATTERN_0] = 0xFF;
control_bert[PATTERN_LENGTH] = 0x9;
control_bert[POLYNOMIAL_TAB] = 0x2;
// QRSS=0 y PATTERN SELECT=1
control_bert[PATTERN_CONTROL] = control_bert[PATTERN_CONTROL] & 0xBF;
control_bert[PATTERN_CONTROL] = control_bert[PATTERN_CONTROL] | 0x20;
escribe_par_bert(PATTERN_3, 7);
//TINV=RINV=0
control_bert[ERROR_INSERT] = control_bert[ERROR_INSERT] & 0x0F;
escribe_par_bert(ERROR_INSERT, 1);
break;
case 10: // Secuencia 2^11 - 1 O.152 y O.153 (tipo 2047)
control_bert[PATTERN_3] = 0xFF;
control_bert[PATTERN_2] = 0xFF;
control_bert[PATTERN_1] = 0xFF;
control_bert[PATTERN_0] = 0xFF;
control_bert[PATTERN_LENGTH] = 0xA;
control_bert[POLYNOMIAL_TAB] = 0x8;
// QRSS=0 y PATTERN SELECT=1
control_bert[PATTERN_CONTROL] = control_bert[PATTERN_CONTROL] & 0xBF;
control_bert[PATTERN_CONTROL] = control_bert[PATTERN_CONTROL] | 0x20;
escribe_par_bert(PATTERN_3, 7);
//TINV=RINV=0
control_bert[ERROR_INSERT] = control_bert[ERROR_INSERT] & 0x0F;
escribe_par_bert(ERROR_INSERT, 1);
break;
case 11: // Secuencia 2^15 - 1 O.151
control_bert[PATTERN_3] = 0xFF;
control_bert[PATTERN_2] = 0xFF;
control_bert[PATTERN_1] = 0xFF;
control_bert[PATTERN_0] = 0xFF;
control_bert[PATTERN_LENGTH] = 0xE;
control_bert[POLYNOMIAL_TAB] = 0xD;
// QRSS=0 y PATTERN SELECT=1
control_bert[PATTERN_CONTROL] = control_bert[PATTERN_CONTROL] & 0xBF;
control_bert[PATTERN_CONTROL] = control_bert[PATTERN_CONTROL] | 0x20;
escribe_par_bert(PATTERN_3, 7);
//TINV=RINV=1
control_bert[ERROR_INSERT] = control_bert[ERROR_INSERT] | 0x30;
escribe_par_bert(ERROR_INSERT, 1);
break;
case 12: // Secuencia 2^17 - 1
control_bert[PATTERN_3] = 0xFF;
control_bert[PATTERN_2] = 0xFF;
control_bert[PATTERN_1] = 0xFF;
control_bert[PATTERN_0] = 0xFF;
control_bert[PATTERN_LENGTH] = 0x10;
control_bert[POLYNOMIAL_TAB] = 0x2;
// QRSS=0 y PATTERN SELECT=1
control_bert[PATTERN_CONTROL] = control_bert[PATTERN_CONTROL] & 0xBF;
C.2 Aplicación mediBER 219
control_bert[PATTERN_2] = 0xFF;
control_bert[PATTERN_1] = 0xFF;
control_bert[PATTERN_0] = 0xFF;
control_bert[PATTERN_LENGTH] = 0x15;
control_bert[POLYNOMIAL_TAB] = 0x0;
// QRSS=0 y PATTERN SELECT=1
control_bert[PATTERN_CONTROL] = control_bert[PATTERN_CONTROL] & 0xBF;
control_bert[PATTERN_CONTROL] = control_bert[PATTERN_CONTROL] | 0x20;
escribe_par_bert(PATTERN_3, 7);
//TINV=RINV=0
control_bert[ERROR_INSERT] = control_bert[ERROR_INSERT] & 0x0F;
escribe_par_bert(ERROR_INSERT, 1);
break;
case 18: // Secuencia 2^23 - 1 O.151
control_bert[PATTERN_3] = 0xFF;
control_bert[PATTERN_2] = 0xFF;
control_bert[PATTERN_1] = 0xFF;
control_bert[PATTERN_0] = 0xFF;
control_bert[PATTERN_LENGTH] = 0x16;
control_bert[POLYNOMIAL_TAB] = 0x11;
// QRSS=0 y PATTERN SELECT=1
control_bert[PATTERN_CONTROL] = control_bert[PATTERN_CONTROL] & 0xBF;
control_bert[PATTERN_CONTROL] = control_bert[PATTERN_CONTROL] | 0x20;
escribe_par_bert(PATTERN_3, 7);
//TINV=RINV=1
control_bert[ERROR_INSERT] = control_bert[ERROR_INSERT] & 0x3F;
control_bert[ERROR_INSERT] = control_bert[ERROR_INSERT] | 0x30;
escribe_par_bert(ERROR_INSERT, 1);
break;
case 19: // Secuencia 2^25 - 1
control_bert[PATTERN_3] = 0xFF;
control_bert[PATTERN_2] = 0xFF;
control_bert[PATTERN_1] = 0xFF;
control_bert[PATTERN_0] = 0xFF;
control_bert[PATTERN_LENGTH] = 0x18;
control_bert[POLYNOMIAL_TAB] = 0x2;
// QRSS=0 y PATTERN SELECT=1
control_bert[PATTERN_CONTROL] = control_bert[PATTERN_CONTROL] & 0xBF;
control_bert[PATTERN_CONTROL] = control_bert[PATTERN_CONTROL] | 0x20;
escribe_par_bert(PATTERN_3, 7);
//TINV=RINV=0
control_bert[ERROR_INSERT] = control_bert[ERROR_INSERT] & 0x0F;
escribe_par_bert(ERROR_INSERT, 1);
break;
case 20: // Secuencia 2^28 - 1
control_bert[PATTERN_3] = 0xFF;
control_bert[PATTERN_2] = 0xFF;
control_bert[PATTERN_1] = 0xFF;
control_bert[PATTERN_0] = 0xFF;
control_bert[PATTERN_LENGTH] = 0x1B;
control_bert[POLYNOMIAL_TAB] = 0x2;
// QRSS=0 y PATTERN SELECT=1
control_bert[PATTERN_CONTROL] = control_bert[PATTERN_CONTROL] & 0xBF;
control_bert[PATTERN_CONTROL] = control_bert[PATTERN_CONTROL] | 0x20;
escribe_par_bert(PATTERN_3, 7);
//TINV=RINV=0
control_bert[ERROR_INSERT] = control_bert[ERROR_INSERT] & 0x0F;
escribe_par_bert(ERROR_INSERT, 1);
break;
case 21: // Secuencia 2^29 - 1
control_bert[PATTERN_3] = 0xFF;
control_bert[PATTERN_2] = 0xFF;
control_bert[PATTERN_1] = 0xFF;
control_bert[PATTERN_0] = 0xFF;
control_bert[PATTERN_LENGTH] = 0x1C;
control_bert[POLYNOMIAL_TAB] = 0x01;
// QRSS=0 y PATTERN SELECT=1
control_bert[PATTERN_CONTROL] = control_bert[PATTERN_CONTROL] & 0xBF;
C.2 Aplicación mediBER 221
control_bert[PATTERN_0] = 0xFE;
control_bert[PATTERN_LENGTH] = 0x01;
control_bert[POLYNOMIAL_TAB] = 0x00;
//QRSS=PATTERN SELECT=0
control_bert[PATTERN_CONTROL] = control_bert[PATTERN_CONTROL] & 0x9F;
escribe_par_bert(PATTERN_3, 7);
//TINV=RINV=0
control_bert[ERROR_INSERT] = control_bert[ERROR_INSERT] & 0x0F;
escribe_par_bert(ERROR_INSERT, 1);
break;
case 27: // Secuencia doble alternada de unos y ceros
control_bert[PATTERN_3] = 0xFF;
control_bert[PATTERN_2] = 0xFF;
control_bert[PATTERN_1] = 0xFF;
control_bert[PATTERN_0] = 0xFC;
control_bert[PATTERN_LENGTH] = 0x03;
control_bert[POLYNOMIAL_TAB] = 0x00;
//QRSS=PATTERN SELECT=0
control_bert[PATTERN_CONTROL] = control_bert[PATTERN_CONTROL] & 0x9F;
escribe_par_bert(PATTERN_3, 7);
//TINV=RINV=0
control_bert[ERROR_INSERT] = control_bert[ERROR_INSERT] & 0x0F;
escribe_par_bert(ERROR_INSERT, 1);
break;
case 28: // Secuencia de 3 unos en 24 ceros
control_bert[PATTERN_3] = 0xFF;
control_bert[PATTERN_2] = 0x20;
control_bert[PATTERN_1] = 0x00;
control_bert[PATTERN_0] = 0x22;
control_bert[PATTERN_LENGTH] = 0x17;
control_bert[POLYNOMIAL_TAB] = 0x00;
//QRSS=PATTERN SELECT=0
control_bert[PATTERN_CONTROL] = control_bert[PATTERN_CONTROL] & 0x9F;
escribe_par_bert(PATTERN_3, 7);
//TINV=RINV=0
control_bert[ERROR_INSERT] = control_bert[ERROR_INSERT] & 0x0F;
escribe_par_bert(ERROR_INSERT, 1);
break;
case 29: // Secuencia de 1 uno en 16 ceros
control_bert[PATTERN_3] = 0xFF;
control_bert[PATTERN_2] = 0xFF;
control_bert[PATTERN_1] = 0x00;
control_bert[PATTERN_0] = 0x01;
control_bert[PATTERN_LENGTH] = 0x0F;
control_bert[POLYNOMIAL_TAB] = 0x00;
//QRSS=PATTERN SELECT=0
control_bert[PATTERN_CONTROL] = control_bert[PATTERN_CONTROL] & 0x9F;
escribe_par_bert(PATTERN_3, 7);
//TINV=RINV=0
control_bert[ERROR_INSERT] = control_bert[ERROR_INSERT] & 0x0F;
escribe_par_bert(ERROR_INSERT, 1);
break;
case 30: // Secuencia de 1 uno en 18 ceros
control_bert[PATTERN_3] = 0xFF;
control_bert[PATTERN_2] = 0xFF;
control_bert[PATTERN_1] = 0xFF;
control_bert[PATTERN_0] = 0x01;
control_bert[PATTERN_LENGTH] = 0x07;
control_bert[POLYNOMIAL_TAB] = 0x00;
//QRSS=PATTERN SELECT=0
control_bert[PATTERN_CONTROL] = control_bert[PATTERN_CONTROL] & 0x9F;
escribe_par_bert(PATTERN_3, 7);
//TINV=RINV=0
control_bert[ERROR_INSERT] = control_bert[ERROR_INSERT] & 0x0F;
escribe_par_bert(ERROR_INSERT, 1);
break;
case 31: // Secuencia de 1 uno en 4 ceros
control_bert[PATTERN_3] = 0xFF;
C.2 Aplicación mediBER 223
control_bert[PATTERN_2] = 0xFF;
control_bert[PATTERN_1] = 0xFF;
control_bert[PATTERN_0] = 0xF1;
control_bert[PATTERN_LENGTH] = 0x03;
control_bert[POLYNOMIAL_TAB] = 0x00;
//QRSS=PATTERN SELECT=0
control_bert[PATTERN_CONTROL] = control_bert[PATTERN_CONTROL] & 0x9F;
escribe_par_bert(PATTERN_3, 7);
//TINV=RINV=0
control_bert[ERROR_INSERT] = control_bert[ERROR_INSERT] & 0x0F;
escribe_par_bert(ERROR_INSERT, 1);
break;
case 32: // Secuencia D4 bucle activado
control_bert[PATTERN_3] = 0xFF;
control_bert[PATTERN_2] = 0xFF;
control_bert[PATTERN_1] = 0xFF;
control_bert[PATTERN_0] = 0xF0;
control_bert[PATTERN_LENGTH] = 0x04;
control_bert[POLYNOMIAL_TAB] = 0x00;
//QRSS=PATTERN SELECT=0
control_bert[PATTERN_CONTROL] = control_bert[PATTERN_CONTROL] & 0x9F;
escribe_par_bert(PATTERN_3, 7);
//TINV=RINV=0
control_bert[ERROR_INSERT] = control_bert[ERROR_INSERT] & 0x0F;
escribe_par_bert(ERROR_INSERT, 1);
break;
case 33: // Secuencia D4 bucle desactivado
control_bert[PATTERN_3] = 0xFF;
control_bert[PATTERN_2] = 0xFF;
control_bert[PATTERN_1] = 0xFF;
control_bert[PATTERN_0] = 0xFC;
control_bert[PATTERN_LENGTH] = 0x02;
control_bert[POLYNOMIAL_TAB] = 0x00;
//QRSS=PATTERN SELECT=0
control_bert[PATTERN_CONTROL] = control_bert[PATTERN_CONTROL] & 0x9F;
escribe_par_bert(PATTERN_3, 7);
//TINV=RINV=0
control_bert[ERROR_INSERT] = control_bert[ERROR_INSERT] & 0x0F;
escribe_par_bert(ERROR_INSERT, 1);
break;
case 34: // Definida por el usuario
mas_bytes = _4_bytes;
// Determinación de la longitud de la secuencia de usuario
for (longitud = 31; ((!(mas_bytes & 0x80000000)) && (longitud > 0)); longitud--)
mas_bytes = mas_bytes << 1;
control_bert[PATTERN_LENGTH] = longitud;
control_bert[PATTERN_0] = _4_bytes & 0xFF;
_4_bytes = _4_bytes >> 8;
control_bert[PATTERN_1] = _4_bytes & 0xFF;
_4_bytes = _4_bytes >> 8;
control_bert[PATTERN_2] = _4_bytes & 0xFF;
_4_bytes = _4_bytes >> 8;
control_bert[PATTERN_3] = _4_bytes & 0xFF;
control_bert[POLYNOMIAL_TAB] = 0x00;
//QRSS=PATTERN SELECT=0
control_bert[PATTERN_CONTROL] = control_bert[PATTERN_CONTROL] & 0x9F;
escribe_par_bert(PATTERN_3, 7);
//TINV=RINV=0
control_bert[ERROR_INSERT] = control_bert[ERROR_INSERT] & 0x0F;
escribe_par_bert(ERROR_INSERT, 1);
break;
}
return 0;
}
/****************************************************************************
FUNCION: inserta_error
C.2 Aplicación mediBER 224
return 0;
}
/****************************************************************************
FUNCION: inicia_test
DESCRIPCION: Cambios en los registros internos para la activación de la
secuencia de salida y el conteo de bits recibidos y bits erróneos
PARAMETROS DE ENTRADA: Ninguno
PARAMETROS DE SALIDA: Ninguno
RESULTADO Y ERRORES: 0, OK
OBSERVACIONES:
****************************************************************************/
int inicia_test(void) {
static int n;
return 0;
}
/****************************************************************************
FUNCION: stop_test
DESCRIPCION: Cambios en los registros internos para la desactivación de la
secuencia de salida.
PARAMETROS DE ENTRADA: Ninguno
PARAMETROS DE SALIDA: Ninguno
RESULTADO Y ERRORES: 0, OK
OBSERVACIONES:
****************************************************************************/
int stop_test(void) {
// Se detiene la operación del chip. TDIS y RDIS a uno
byte_control = byte_control | 0xC0;
carga_pp (byte_control, LATCH0, CHIP0);
return 0;
}
/****************************************************************************
C.2 Aplicación mediBER 225
FUNCION: error_auto
DESCRIPCION: Cambios en el registro interno del DS2172 para que inserte
errores automáticamente de forma que se obtenga una tasa de error arbitraria
PARAMETROS DE ENTRADA: char valor, con la tasa de BER artificial codificada
PARAMETROS DE SALIDA: No
RESULTADO Y ERRORES: 0, todo OK
OBSERVACIONES:
****************************************************************************/
int error_auto(unsigned char valor) {
// Nos aseguramos de que el parámetro de entrada no interfiere
valor = valor & 0x7;
// Modificamos el registro implicado
control_bert[ERROR_INSERT] = control_bert[ERROR_INSERT] & 0xF8;
control_bert[ERROR_INSERT] = control_bert[ERROR_INSERT] | valor;
escribe_par_bert(ERROR_INSERT, 1);
return 0;
}
/****************************************************************************
FUNCION: aplicacion_bert
DESCRIPCION: Lectura del registro de estado y de los contadores de bits
recibidos y erróneos para realimentar a la aplicación principal.
PARAMETROS DE ENTRADA:
int secuencia: código de la secuencia utilizada.
PARAMETROS DE SALIDA:
ptd, puntero a estructura t_datos, donde se guardan todos los resultados
RESULTADO Y ERRORES: char SI, si se determina que el chip está sincronizado
en función de las alarmas leı́das en el registro de estado, NO en caso
contrario. Depende de la secuencia que se esté utilizando.
OBSERVACIONES: La función determina sincronismo si se reciben todo unos, pero
la secuencia utilizada es esa misma, y tambien si se reciben todo ceros,
y la secuencia es de ceros. En caso contrario, estas dos circustancias
son consideradas como anómalas y producen que el resultado de la función
sea negativo.
****************************************************************************/
char aplicacion_bert(t_datos *ptd, int secuencia) {
char hay_sincronismo;
// El chip se ha sincronizado
if (hay_sincronismo) {
// Reseteo de los contadores
control_bert[PATTERN_CONTROL] = control_bert[PATTERN_CONTROL] & 0xEF;
escribe_par_bert(PATTERN_CONTROL, 1); // LATCH COUNT = 0
control_bert[PATTERN_CONTROL] = control_bert[PATTERN_CONTROL] | 0x10;
escribe_par_bert(PATTERN_CONTROL, 1); // LATCH COUNT = 1
// Actualización de variables
ptd->bits_rx = (control_bert[BIT_COUNT_3] * 16777216.0) +
(control_bert[BIT_COUNT_2] * 65536.0) +
(control_bert[BIT_COUNT_1] * 256.0) +
(control_bert[BIT_COUNT_0] * 1.0);
ptd->bits_err= (control_bert[BIT_ERR_COUNT_3] * 16777216.0) +
(control_bert[BIT_ERR_COUNT_2] * 65536.0) +
(control_bert[BIT_ERR_COUNT_1] * 256.0) +
(control_bert[BIT_ERR_COUNT_0] * 1.0);
return SI;
}
// No hay sincronismo
else {
// Reseteo de los contadores
control_bert[PATTERN_CONTROL] = control_bert[PATTERN_CONTROL] & 0xEF;
escribe_par_bert(PATTERN_CONTROL, 1); // LATCH COUNT = 0
control_bert[PATTERN_CONTROL] = control_bert[PATTERN_CONTROL] | 0x10;
escribe_par_bert(PATTERN_CONTROL, 1); // LATCH COUNT = 1
return NO;
}
}
/****************************************************************************
FUNCION: busca_equipo_ber
DESCRIPCION: Función que se ejecuta únicamente para comprobar la correcta
conexión de la placa de medición de BER
PARAMETROS DE ENTRADA: No
PARAMETROS DE SALIDA: No
RESULTADO Y ERRORES: int 1 si la placa funciona correctamente, 0 si no se
encuentra (porque no está alimentada, o no conectada al puerto paralelo)
OBSERVACIONES:
****************************************************************************/
int busca_equipo_ber(void) {
// Escritura en el bus del dato a cargar
// byte_datos = 0x80;
byte_datos = 0xA5;
carga_pp (byte_datos, LATCH0, CHIP1);
stopband = 0.5*(1+alfa);
passband = 0.5*(1-alfa);
% fn es un array de [0:stopband], que son los valores para los que la integral no es nula
for m = 1 : freq_pts
array_1(m)= SRRCpos(fn(m), passband, stopband, alfa);
array_2(m)= cos( t_taps(i)*2*pi .*fn(m));
end
Array_temp = array_1 .* array_2;
h(i) = trapz(Array_temp);
end
% Borramos algunas variables temporales
clear Array_temp array_1 array_2 m i
% Rotulamos la grafica
xlabel(’TAP’);
ylabel(’htap’);
title(’ RESPUESTA IMPULSIVA SCCR ’);
% Escalamos la grafica
axis([0 40 min(htap)-10 max(htap)+10]);
% Calculamos el modulo
Modulo_H = abs(HTap(1:126));
%Modulo_H = abs(HTap(1:250));
% NOTA : se calcula el modulo solo de la mitad de los
% puntos, ya que el espectro es simetrico
C.3 Ficheros de Matlab 228
% Pasamos a logaritmico
Modulo_H_dB = 20 * log10(Modulo_H);
plot(f,Modulo_H_dB) grid
% Rotulamos la grafica
xlabel(’FREQUENCIA (fn)’);
ylabel(’Hn (dB)’);
title(’ RESPUESTA EN FRECUENCIA NORMALIZADA SCCR ’);
% Escalamos la grafica
axis([0 max(f) -65 max(Modulo_H_dB)+5]);
% Escalamos la grafica para detalle
%axis([0 1 -6 max(Modulo_H_dB)]);
C.3 Ficheros de Matlab 229
Fichero cic.m
% FICHERO DE SIMULACIÓN DE FILTRO FIR EN COSENO ALZADO COMPENSANDO
% LA CAIDA DE LAS ETAPAS CIC
clear
BW = 0.5*(1+alfa);
PROC_GAIN=1;
SCALE = 511;
TAPS = 41;
FreqScale = 4;
% Factor de interpolación
R = 6;
% Detalles de construcción interna del filtro CIC
N = 4; M = 1;
% Parámetro de ajuste
beta = 0.90;
% fn es un array de [0:stopband], que son los valores para los que la integral no es nula
for m = 1 : freq_pts
array_1(m)= SRRCpos(fn(m), passband, stopband, alfa);
array_2(m)= cos( t_taps(i)*2*pi .*fn(m));
end
Array_temp = array_1 .* array_2;
h(i) = trapz(Array_temp);
end
% Borramos algunas variables temporales
clear Array_temp array_1 array_2 m i
% Escalamos la grafica
axis([0 40 min(htap)-10 max(htap)+10]);
% Rotulamos la grafica
xlabel(’TAP’);
ylabel(’htap’);
title(’ RESPUESTA IMPULSIVA SCCR’);
% Escalamos la grafica
axis([0 40 min(htap)-10 max(htap)+10]);
% Calculamos el modulo
Modulo_H = abs(HTap(1:126));
%Modulo_H = abs(HTap(1:250));
% NOTA : se calcula el modulo solo de la mitad de los
% puntos, ya que el espectro es simetrico
% Pasamos a logaritmico
Modulo_H_dB = 20 * log10(Modulo_H);
plot(f,Modulo_H_dB) grid
% Rotulamos la grafica
xlabel(’FREQUENCIA (fn)’);
ylabel(’Hn (dB)’);
title(’ RESPUESTA EN FRECUENCIA NORMALIZADA SCCR ’);
% Escalamos la grafica
axis([0 max(f) -65 max(Modulo_H_dB)+5]);
% Escalamos la grafica para detalle
%axis([0 1 -6 max(Modulo_H_dB)]);
% fn es un array de [0:stopband], que son los valores para los que la integral no es nula
for m = 1 : freq_pts
if fn(m)<(beta*BW)
si(m) = abs( hcic( 0, R, M, N ) / hcic( fn(m)/FreqScale, R, M, N ));
else
si(m) = 1;
end
array_1(m)= SRRCpos(fn(m), passband, stopband, alfa)*si(m);
array_2(m)= cos( t_taps(i)*2*pi .*fn(m));
end
Array_temp = array_1 .* array_2;
h1(i) = trapz(Array_temp);
end
% Rotulamos la grafica
xlabel(’TAP’);
ylabel(’h1tap’);
title(’ RESPUESTA IMPULSIVA SCCR COMPENSADA’);
% Escalamos la grafica
axis([0 40 min(h1tap)-10 max(h1tap)+10]);
C.3 Ficheros de Matlab 231
% Calculamos el modulo
Modulo_H_cic = abs(HTap_cic(1:126));
% Pasamos a logaritmico
Modulo_H_cic_dB = 20 * log10(Modulo_H_cic);
plot(f_cic,Modulo_H_cic_dB) grid
% Rotulamos la grafica
xlabel(’FREQUENCIA (fn)’);
ylabel(’Hn (dB)’);
title(’ RESPUESTA EN FRECUENCIA COMPENSADA SCCR ’);
% Escalamos la grafica
axis([0 max(f_cic) -65 max(Modulo_H_cic_dB)+5]);
% Escalamos la grafica para detalle
figure (5)
plot (tap,htap,tap,h1tap,’r’)
grid
% Rotulamos la grafica
xlabel(’TAP’);
ylabel(’htap , h1tap’);
title(’ RESPUESTA IMPULSIVA Y MODIFICADA SCCR ’);
% Escalamos la grafica
axis([0 40 min(htap)-10 max(htap)+10]);
figure(6)
plot(f,Modulo_H_dB,f,Modulo_H_cic_dB,’r’)
grid
% Rotulamos la grafica
xlabel(’FREQUENCIA (fn)’);
ylabel(’H (dB) , H precom (dB)’);
title(’ RESPUESTA EN FRECUENCIA NORMALIZADA Y MODIFICADA SCCR ’);
% Escalamos la grafica
axis([0 max(f) -65 max(Modulo_H_dB)+5]);
Bibliografı́a
[1] Inc. Analog Devices. High Speed Design Techniques. Prentice Hall, California USA,
2 edition, 1996.
[2] RF/SS. Sss-online. Compañı́a consultora, RF/Spread Spectrum Consulting, sss-
mag.com/dds.html, 1998.
[3] Solomon W. Golomb. Shift Register Sequences. Aegean Park Press, California, 1982.
[4] Recomendación UIT-T G.821. Caracterı́stica de error de una conexión digital inter-
nacional que funciona a una velocidad binaria inferior a la velocidad primaria y forma
parte de una red digital de servicios integrados. Technical report, UIT-T, 1996.
[5] Recomendación UIT-T G.826. Parámetros y objetivos de caracterı́stica de error para
trayectos digitales internacionales de velocidad binaria constante que funcionan a la
velocidad primaria o a velocidades superiores. Technical report, UIT-T, 1996.
[6] Harris. Technical report, harris semiconductors. Technical report, www.Harris.com,
1998.
[7] Analog. Analog devices. Technical report, www.analog.com, 2000.
[8] H. Nicholas III and H. Samueli. An analysis of the output spectrum of direct digital
frequency synthesizers in the presence of phase-accumulator truncation. Technical
report, 41 st Annual Frequency Control Symposium, 1987.
[9] Bernard Sklar. Digital Communications, fundamentals and applications. Prentice-
Hall International, New Jersey, 1988.
[10] Lhon G. Proakis. Digital Communications. McGraw-Hill International, USA, 2 edi-
tion, 1989.
[11] Alan V. Oppenheim y Ronald W. Schafer. Discrete-Time Signal Processig. Prentice-
Hall International, New Jersey, 1989.
[12] Analog Devices. Ad9853.pdf. Catálogo del fabricante, Analog Devices, 1999.
[13] Craig Peacock. Interfacing the standard parallel port. Portal de internet,
www.geocities.com/SiliconValley/Bay/8302/, Abril 1997-1999.
[14] Dallas Semiconductor. Ds2172.pdf. Catálogo del fabricante, Dallas Semiconductor,
1998.
[15] TTC. Fireberd 6000 user´s guide. Manual de usuario, Telecomunications Tecniques
Corporation, Germantown, Maryland, 1988.
232
BIBLIOGRAFÍA 233