4.2 Arquitectura software:

La figura 4-2 muestra la arquitectura software del sistema de modulación FSK implementado en esta práctica:

fig2

Figura 4-2. Arquitectura software del modulador FSK.

Se ha modificado la arquitectura utilizada en lab3 para utilizar interrupciones en lugar de encuesta para la generación de las muestras de salida.

  • Modificaciones:

    • En la inicialización se incluye la habilitación de la interrupción del puerto I2S.

    • En el ejecutivo cíclico, se incluye una llamada a la función lab4() que calcula una nueva muestra de la señal a generar. Esta muestra se almacena en un buffer circular (objeto g_tx_buffer) que comunica el bucle principal con la rutina de servicio de interrupción (ISR) del puerto I2S.

    • Se incluye la rutina de servicio de interrupción del puerto I2S, que se encarga de enviar las muestras al códec WM8731.

4.1.1 Comunicación bucle principal - ISR:

La comunicación entre el bucle principal y la rutina de servicio de interrupción del puerto I2S se realiza mediante un buffer circular de 8 muestras.

  • El bucle principal genera las muestras de la señal FSK y las almacena en el buffer circular.

  • La ISR del puerto I2S extrae las muestras del buffer circular y las envía al códec WM8731.

Para evitar condiciones de carrera en el acceso al buffer circular, se deshabilitan las interrupciones al acceder al buffer desde el bucle principal.

Descripción del buffer circular:

  • El buffer consta de los siguientes elementos:

    • buffer[]: Array que almacena las muestras generadas.

    • head: Índice de la siguiente muestra a escribir por el bucle principal.

    • tail: Índice de la siguiente muestra a leer por la ISR.

  • Operaciones principales:

apilado (push):

Si hay espacio en el buffer (no está lleno), se escribe una muestra en la posición head y se actualiza head.

desapilado (pop):

Si hay muestras disponibles en el buffer (no está vacío), se lee la muestra en la posición tail y se actualiza tail.

  • Condiciones de buffer lleno y vacío:

    • Buffer lleno: (head + 1) % BUFFER_SIZE == tail. Esta condición supone que el número de muestras en el buffer es BUFFER_SIZE - 1.

    • Buffer vacío: head == tail

La figura 4-3 muestra la clase CIRC_BUF que utilizaremos para implementar el buffer circular. De esta clase se crearán dos instancias (objetos): una para la transmisión g_tx_buffer y otra para la recepción g_rx_buffer (se utilizará en lab5).

fig2

Figura 4-3. Clase CIRC_BUF.

Diseño y pruebas clase CIRC_BUF
  1. Preparación del entorno.

    • Descarga y descomprime el archivo de recursos lab4 en tu espacio de trabajo.

    • Los archivos circ_buf.h y circ_buf.c que implementan la clase CIRC_BUF están ubicados en la carpeta src.

  2. Configuración del proyecto.

    • Abre el proyecto lab4.

    • Selecciona el target Test_Circ_buf, que utiliza un simulador para la depuración del código. Esto permite desarrollar y validar el software sin necesidad de disponer del hardware físico.

  3. Tareas a realizar.

    • Escribe el código de la clase CIRC_BUF en el archivo circ_buf.c. Encontrarás la descripción del comportamiento de los métodos en el archivo circ_buf.h.

    • Los objetos g_tx_buffer y g_rx_buffer se definen en el archivo circ_buf.c como variables globales.

    • Asegúrate de que el código compila correctamente y no genera errores.

    • Revisa los casos de prueba definidos en la función main(), ubicada en el archivo test/test_circ_buf.c.

  4. Herramientas de análisis.

    • Inicializa el debugger ico_debug y abre la herramienta Analyzer desde el menú:

      View → Analysis Windows → Logic Analyzer.

      Analyzer mostrará la evolución temporal de las variables globales:

      • g_TestN: número de test.

    • Ejecuta la aplicación ico_run y corrige cualquier error funcional hasta que la clase CIRC_BUF cumpla con la especificación deseada. Si no hay errores, la variable g_TestN debe alcanzar el valor F al finalizar

  5. Test y Resultados esperados.

    El fichero test/test_circ_buf.c incluye los siguientes casos de prueba:

    • Test 1. Comprobar que el buffer está vacío tras inicialización.

    • Test 2. Comprobar que el buffer no está lleno tras inicialización.

    • Test 3. Comprobar que la lectura en vacío devuelve error y pone ceros.

    • Test 4. Llenar el buffer hasta CIRC_BUF_SIZE-1 (el último push debe fallar).

    • Test 5. Comprobar que el buffer está lleno.

    • Test 6. Comprobar que el buffer no está vacío cuando está lleno.

    • Test 7. Leer todos los elementos y comprobar el orden de salida.

    • Test 8. Comprobar que el buffer está vacío tras vaciado.

    • Test 9. Comprobar que el pop en vacío sigue devolviendo error y ceros.

    • Test A. Comprobar que el push vuelve a funcionar tras vaciar el buffer.

    • Test B. Test adicional: comprobación de wrap-around de head y tail (llenar y vaciar varias veces).

    Asegúrate de que todos los casos se ejecutan correctamente y producen los resultados esperados.