68
i [1] Proyecto Fin de Carrera Ingeniería de Telecomunicación Configuración y programación del DSP integrado en la plataforma BeagleBoard-xM Autor: Francisco Javier Buenavida Durán Tutor: Fernando Muñoz Chavero Departamento de Ingeniería Electrónica Escuela Técnica Superior de Ingeniería Universidad de Sevilla Sevilla, 2013

Proyecto Fin de Carrerabibing.us.es/proyectos/abreproy/12165/fichero/Configuración+y... · iv Proyecto Fin de Carrera: Configuración y programación del DSP integrado en la plataforma

  • Upload
    lamhanh

  • View
    215

  • Download
    0

Embed Size (px)

Citation preview

i

[1]

Proyecto Fin de Carrera

Ingeniería de Telecomunicación

Configuración y programación del DSP

integrado en la plataforma BeagleBoard-xM

Autor: Francisco Javier Buenavida Durán

Tutor: Fernando Muñoz Chavero

Departamento de Ingeniería Electrónica

Escuela Técnica Superior de Ingeniería

Universidad de Sevilla Sevilla, 2013

ii

Proyecto Fin de Carrera

Ingeniería de Telecomunicación

Configuración y programación del DSP integrado en la

plataforma BeagleBoard-xM

Autor:

Francisco Javier Buenavida Durán

Tutor:

Fernando Muñoz Chavero

Profesor titular

Departamento de Ingeniería Electrónica

Escuela Técnica Superior de Ingeniería

Universidad de Sevilla

Sevilla, 2013

iv

Proyecto Fin de Carrera: Configuración y programación del DSP integrado en la plataforma BeagleBoard-xM

Autor: Francisco Javier Buenavida Durán

Tutor: Fernando Muñoz Chavero

El tribunal nombrado para juzgar el Proyecto arriba indicado, compuesto por los siguientes miembros:

Presidente:

Vocales:

Secretario:

Acuerdan otorgarle la calificación de:

Sevilla, 2013

El Secretario del Tribunal

v

A mi familia y amigos

vii

Resumen

Este proyecto muestra como configurar y programar la placa de desarrollo BeagleBoard-xM. Esta placa

contiene un procesador DM3730 que integra dos núcleos, un procesador de propósito general ARM Cortex-A8

(donde puede ejecutarse un sistema operativo como Windows, Linux o Android) y un DSP de punto fijo

C64x+ para tareas de procesamiento de audio y video. En éste se describe el proceso para poder programar

tanto el núcleo ARM como el DSP, de tal manera que se muestra como acceder y configurar el DSP mediante

las herramientas que Texas Instruments proporciona.

Además se ha empleado una aplicación de procesamiento de audio que sirve a modo de ejemplo para mostrar

las posibilidades que ofrece la placa. Dicha aplicación se ejecuta en ambos núcleos, siendo el procesador de

propósito general el que se encarga de controlar los dispositivos de audio para generar y reproducir las

muestras de audio y el DSP donde se procesan.

ix

Abstract

This project shows how to configure and program the development board BeagleBoard-xM. This board

contains a processor DM3730. The DM3730 includes an ARM Cortex-A8 CPU (which can run an operating

system like Windows, Linux or Android) and a C64x+ fixed-point DSP for accelerated video and audio

decoding. It describes the process to program both cores. Because of this, it shows how to access and set the

integrated DSP using the tools that Texas Instruments provided.

In addition, an audio processing application is used to show the potential of the board. This application runs

on both cores, the general purpose processor checks the audio devices and the DSP processes the audio

samples.

x

Índice

Resumen vii

Abstract ix

Índice x

Notación xiii

1 Introducción 15 1.1. Objetivo 16 1.2. Organización de la memoria 16

2 BeagleBoard-xM 18 2.1 Descripción de la placa 19

2.1.1 Procesador DM3730 21 2.1.1.1 Microprocesador ARM Cortex-A8 22 2.1.2 Memoria 23 2.1.3 Control de alimentación TPS65950 23 2.1.4 Puerto USB 2.0 OTG 23 2.1.5 Conector DC 24 2.1.6 Puertos USB 2.0 y Ethernet 24 2.1.7 Conector JTAG 24 2.1.8 Conector Serie RS-232 24 2.1.9 Conector S-Video 24 2.1.10 Conector DVI-D 24 2.1.11 Conector microSD 25 2.1.12 Conector de audio entrada/salida 25 2.1.13 Pines de expansión 25 2.1.14 Botones 25 2.1.15 Indicadores 25

3 Configuración y puesta a punto 26 3.1 Instalación del sistema operativo 26 3.2 Montaje 29 3.3 Toolchain 29 3.4 Entorno de desarrollo Eclipse 30

3.4.1 Instalación 30 3.4.2 Configuración 31 3.4.3 Compilando un código en C 32

4 Comunicación con el DSP 33 4.1 DSPLink 33

4.1.1 Funciones disponibles 33 4.1.2 Posibles escenarios 35 4.1.3 Instalación de DSPLink 37

4.2 C6Run 43 4.2.1 C6RunLib 43 4.2.2 C6RunApp 44 4.2.3 Configuración 44

5 Aplicación de Audio 45 5.1 ALSA 45 5.2 Código de la aplicación 46

xi Configuración y programación del DSP integrado en la plataforma BeagleBoard-xM

5.2.1 main.c 46 5.2.2 audio_thread.c 46 5.2.3 audio_input_output.c 47 5.2.4 audio_process.c 47 5.2.5 Makefile 48

6 Conclusiones 49

Referencias 50

Índice de Figuras 52

Anexo: Código del programa 53 main.c 53 audio_thread.c 54 audio_input_output.c 59 audio_process.c 64 Makefile 64

xiii

Notación

ALU Arithmetic Logic Unit Unidad Aritmético-Lógica

ALSA Advanced Linux Sound Architecture

API Application Programming Interface Interfaz de programación de aplicaciones

ARM Advanced RISC Machine Arquitectura RISC Avanzada

BIOS Basic Input-Output System Sistema Básico de Entrada/Salida

CGT Code Generation Tools Herramientas de Generación de Código

CMEM Contiguous Memory Allocator

CPU Central Processing Units Unidad Central de Procesamiento

DDR Double Data Rate Doble Tasa de Transferencia

DSP Digital Signal Processsor Procesador Digital de Señal

DVI Digital Visual Interface Interfaz Visual Digital

FIR Finite Impulse Response Respuesta finita al impulso

GCC GNU Compiler Collection Colección de Compiladores GNU

GNU GNU is Not Unix GNU no es Unix

GPP General Purpose Processor Procesador de Propósito General

GPIO General Purpose Input/Output Entrada/Salida de Propósito General

HDMI High Definition Multimedia Interface Interfaz multimedia de alta definición

I2C Inter Integrated Circuit Bus de Comunicación entre Circuitos

JTAG Joint Test Action Group

LCD Liquid Crystal Display Pantalla de Cristal Líquido

LED Light-Emitting Diode Diodo emisor de luz

LPM Local Power Management Gestor de Energía Local

MAC Multiply and Accumulate Unit Unidad de sumas y multiplicaciones

McBSP2 Multi-Channel Buffered Serial Port 2 Puerto Serie Multicanal con Capacidad de

almacenamiento

MIDI Musical Instrument Digital Interface Interfaz Digital de Instrumentos Musicales

NTSC National Television System Committee

OMAP Open Multimedia Applications Platform

OTG On-The-Go

PAL Phase Alternating Line Línea de Fase Alternada

PC Personal Computer Computadora personal

PCB Printed Circuit Board Placa de Circuito Impreso

PCM Pulse-Code Modulation Modulación por impulsos codificados

POP Package on Package Tipo de encapsulado

RAM Random-Access Memory Memoria de Acceso Aleatorio

RS232 Recommended Standard 232 Bus de comunicaciones RS232

SD Secure Digital

SoC System On Chip Sistema en un Chip

UART3 Universal Asynchronous Receiver-

Transmitter

Transmisor-Receptor Asíncrono Universal

URL Uniform Resource Locator Localizador de Recursos Uniforme

USB Universal Serial Bus Bus Serie Universal

VCL Video Coding Layer Capa de Codificación de Vídeo

VLIW Very Long Instruction Word Procesador con Instrucciones Complejas

15

1 INTRODUCCIÓN

n sistema embebido (anglicismo “embedded”) consiste en un sistema de computación cuyo hardware y software están específicamente diseñados y optimizados para resolver un problema concreto eficientemente. Al contrario de lo que ocurre con los ordenadores de propósito general (como por

ejemplo una computadora personal o PC) que están diseñados para cubrir un amplio rango de necesidades, los sistemas embebidos se diseñan para cubrir necesidades específicas.

El término "embebido" (también se le conoce como “empotrado”) hace referencia al hecho que la electrónica o el sistema electrónico de control es una parte integral del sistema en que se encuentra. La característica principal que diferencia a los “embebidos” de los demás sistemas electrónicos es que, por estar insertados dentro del dispositivo que controlan, están sujetos en mayor medida a cumplir requisitos de tamaño, fiabilidad, consumo y coste, y su existencia puede no ser aparente. Algunos ejemplos de Sistemas Embebidos son los sistemas de información integrados en automóviles, trenes o aviones, y controladores de procesos en sistemas de producción industrial. [2]

Figura 1.1 – BeagleBoard-xM

Debido la globalización y la fuerte presión de los mercados emergentes, todos los sectores están focalizando

sus esfuerzos en aumentar su competitividad. Es ahí donde cobra un papel importante los sistemas embebidos

debido a su gran aplicabilidad en cualquier ámbito sectorial así como el valor añadido que aportan los mismos

a los productos que los contienen, hace que el desarrollo de estos sistemas sea un área estratégica preferente

para muchas empresas que buscan precisamente este aumento de su competitividad. Es por ello que desde el

departamento de Ingeniería Electrónica y el departamento de Teoría de la Señal y Comunicaciones de la

Escuela Técnica Superior de Ingenieros de la Universidad de Sevilla se estudió como implementar algoritmos

para la detección no invasiva del electrocardiograma fetal en un sistema embebido. Con ello se busca

desarrollar un diseño de un prototipo final que pueda dar un servicio de utilidad clínica. [3]

U

Introducción

16

La plataforma elegida fue la BeagleBoard que se engloba dentro de los llamados “hardware libre”, es decir,

dispositivos cuyas especificaciones y diagramas esquemáticos son de acceso público. De esta manera, sería

posible desarrollar el prototipo mencionado tomando como base alguna de placas que ofrece BeagleBoard.org.

En concreto, la versión que se ha empleado en el desarrollo de este proyecto es la BeagleBoard-xM, la cual

contiene un procesador DM3730 que integra a su vez un procesador de propósito general ARM Cortex-A8 a 1

GHz y un DSP TMS320C64x+ a 800 Mhz. Además incorpora una serie de puertos y conectores que le permite

ofrecer una amplia gama de funcionalidades y expansiones.

1.1. Objetivo

Este proyecto nace con la idea de estudiar la placa BeagleBoard-xM de tal manera que sea posible

familiarizarse con los sistemas embebidos de arquitectura ARM, así como acceder al DSP de punto fijo que

tiene integrado. Esto se debe a que los procesadores de doble núcleo como el DM3730 (basado en el

OMAP3530 de Texas Instruments) permiten el uso del DSP para llevar a cabo el procesado de señal en tiempo

real mientras que la interacción con el usuario (recibir comandos a través del teclado, dibujar gráficos en la

pantalla, etc.) es gestionada por el procesador de propósito general ARM. De esta manera se lleva a cabo un

reparto muy eficiente de tareas. Estos procesadores se pueden ver como la evolución natural, optimizada, del

esquema tradicional (esto es, aquel compuesto de un PC de sobremesa conectado a la placa del DSP por medio

de un bus o un puerto USB, con una comunicación entre sistemas considerablemente más lentos y limitados).

También es materia de este proyecto desarrollar una aplicación que utilice tanto el procesador ARM como el

DSP, de tal manera que se haga uso de las herramientas que permiten la comunicación entre ambos

microprocesadores. Para ello se usará el software que ofrece Texas Instruments para tal propósito, DSPLink.

Por último, el objetivo final de este trabajo sería la de proporcionar un manual que permita al lector

introducirse en el sistema BeagleBoard-xM o similares, así como su puesta en marcha y ofrecer nociones

básicas sobre las herramientas disponibles para poder programar una aplicación en este tipo de sistemas. Por

tanto se deja para futuros trabajos la implementación de algoritmos para la detección no invasiva del

electrocardiograma fetal y del desarrollo de un prototipo portátil.

1.2. Organización de la memoria

La memoria está compuesta de 6 capítulos más un anexo. El primer capítulo es la introducción donde se ha presentado el proyecto, los objetivos o motivación para la realización del mismo así como esta pequeña reseña donde se explica la composición de la memoria.

En el capítulo 2 se ha tratado de presentar el hardware utilizado, BeagleBoard-xM, desde un punto de vista hardware, describiendo brevemente cada uno de los principales componentes de la placa como el procesador de doble núcleo DM3730 y el resto de componentes de la placa. Para la documentación de este capítulo se ha tomado gran parte de la información de las siguientes fuentes [4] [5] [6].

En el capítulo 3 se describe la puesta en marcha del sistema. Empieza presentando dos de los posibles sistemas operativos que se pueden usar en la tarjeta como son Ubuntu y Angstrom, además se incluye un pequeño tutorial para la instalación se estos. También se introduce en el uso de toolchains para la compilación de software en la arquitectura ARM empleada en este tipo de sistemas embebidos desde otra arquitectura diferente como es la arquitectura x86 que tienen los PC convencionales. Por último se explica cómo configurar un entorno de desarrollo como Eclipse para poder usar estas herramientas.

17 Configuración y programación del DSP integrado en la plataforma BeagleBoard-xM

En el capítulo 4 se presenta DSPLink. Se trata del software distribuido por Texas Instruments que permite la comunicación con el DSP integrado en la BeagleBoard-xM. Además se detallan los pasos para crear los módulos o drivers necesarios por el sistema operativo para tener control del DSP. Una vez lograda la comunicación con el DSP, se explica brevemente la herramienta de software libre C6Run que emplea el software anterior, simplificando más aun la programación en el DSP.

En el capítulo 5 se explica el funcionamiento de cada uno de los ficheros que componen la aplicación desarrollada en este proyecto, la cual consiste en un filtro de audio. Para obtener el audio y poder reproducirlo, la aplicación hace uso de las librerías que ofrece ALSA (Advanced Linux Sound Architecture), dicho software es descrito de manera muy breve en este capítulo.

El capítulo 6 son las conclusiones obtenidas en la elaboración de este proyecto. Tras este capítulo, se recoge el índice de figuras, las referencias empleadas a lo largo de la memoria así como un anexo que contiene el código C de la aplicación que se ha desarrollado.

BeagleBoard-xM

18

2 BEAGLEBOARD-XM

a fundación BeagleBoard.org es una organización sin ánimo de lucro con sede en Estados Unidos que

nació con la idea de proporcionar un sistema para la enseñanza de software y hardware libre.

Pensada para usos en ámbitos universitarios, un grupo de personas entre las que se encontraban

empleados de Texas Instrumentes, crearon el sistema embebido de código abierto, BeagleBoard. La fundación

Beagelboard.org no recibe ningún beneficio económico por la venta de cada tarjeta, siendo esta una de las

razones por las que resultan tan económicas. La ayuda para la producción original la proporcionó Digi–Key

junto con Texas Instruments, pero actualmente la distribución de las tarjetas BeagleBoard se ha abierto a

decenas de distribuidores en todo el mundo.

Figura 2.1 - Logo BeagleBoard.org

La BeagleBoard básicamente es una placa base de bajo costo que tiene un procesador de baja potencia ARM de

la serie Cortex-A, producido por Texas Instruments. Estos procesadores son de la categoría “System on Chips”

(SoCs), es decir, circuitos integrados que contienen todos los componentes de una computadora o sistema

electrónico, especialmente diseñados para sistemas portátiles y tecnología móvil. Pensados inicialmente con la

idea de permitir a las distribuciones de Linux mejorar la compatibilidad con los dispositivos ARM,

actualmente y gracias a su éxito, BeagleBoard tiene el apoyo de numerosas distribuciones de Linux y el

soporte por parte de casi todos los desarrolladores, como Ubuntu, QNX, Windows Embedded y Android.

La BeagleBoard está equipada con un conjunto mínimo de funciones para evitar elevar el coste de la placa

innecesariamente. No obstante mediante la utilización de interfaces estándar, la BeagleBoard es altamente

extensible pudiéndose añadir muchas características e interfaces. Pese a que los creadores de la BeagleBoard

no tuvieron en mente hacer uso de las placas en productos finales, toda la información de diseño está

disponible de forma libre y se puede utilizar como la base para la realización de otros productos. Como se

comentó en la introducción, esta es una de las razones principales por las que se ha usado la BeagleBoard en

este proyecto, la idea principal sería aprender a desarrollar aplicaciones en este hardware para luego poder

crear un dispositivo que utilice como base el diseño hardware empleado en la BeagleBoard.

BeagleBoard ha seguido desarrollando nuevas tarjetas con la intención de mejorar su diseño, como es el caso

de la tarjeta que se ha utilizado en este proyecto, Beagleboard-xM, o las tarjetas BeagleBone y BeagleBone

Black, que son la línea más económica y están enfocadas para aplicaciones más específicas como por ejemplo

la robótica. En la figura 2.2, extraída de la propia web de la organización [6], se puede observar las diferencias

principales a nivel de hardware y precio entre las distintas tarjetas.

L

19 Configuración y programación del DSP integrado en la plataforma BeagleBoard-xM

2.1 Descripción de la placa

La BeagleBoard-xM consta de un procesador DM3730 que integra a su vez un microprocesador de propósito

general ARM Cortex-A8 y un DSP de punto fijo TMS320C64+. También contiene una memoria de 512 MB

RAM DDR de bajo consumo de energía.

El diseño de esta tarjeta incluye salidas de video, entradas y salidas de audio, conexiones USB, entre otras.

Además el diseño de hardware abierto mejora el rendimiento permitiendo que tengas prácticamente un

ordenador portátil, así como la capacidad de expansión y el bajo consumo de energía.

Sus principales características son:

- Procesador DM3730

- 512 MB RAM LPDDR

Figura 2.2 - Comparación entre las diferentes tarjetas de Beagleboard.org

BeagleBoard-xM

20

- USB 2.0 de alta velocidad

- Puertos Ethernet 10/100

- DVI-D (salida HDMI para monitores de alta definición)

- S-video (salida de TV)

- Salida de audio estéreo

- Ranura microSD

- JTAG

En la figura 2.3 se puede observar la ubicación en la placa de cada uno de los dispositivos que se detallarán a

continuación.

Figura 2.3 - Vista superior de la BeagleBoard-xM

21 Configuración y programación del DSP integrado en la plataforma BeagleBoard-xM

2.1.1 Procesador DM3730

El procesador DM3730 es el corazón de la BeagleBoard-xM y el encargado de gobernar cada dispositivo

de la misma. Se trata de una nueva versión del anterior SoC (System on Chip) utilizado en la BeagleBoard

original, el OMAP 3530, que ofrece todas las características del anterior pero logrando mejorar tanto en

rendimiento como en estabilidad.

Los sistemas SOC integran en un único chip toda la funcionalidad de un sistema digital completo basado

en microprocesador. Esto incluye al menos uno o varios núcleos o unidades de proceso (CPUs, Central

Processing Units), memoria y periféricos. También se pueden encontrar bloques de lógica reconfigurable y

bloques analógicos integrados en el mismo chip. [4]

Figura 2.4 - Encapsulado tipo POP

El hecho de integrar todo el sistema, proporciona una gran reducción de tamaño y aumento de la

fiabilidad, ya que todos los componentes están sometidos al mismo y único proceso de fabricación, lo que

permite reducir costes y tiempo de diseño de los sistemas embebidos finales. Además, la propagación de

señales es mejor a nivel de silicio que a nivel de PCB (Printed Circuit Board), mejorando así la capacidad

de comunicación de los subsistemas internos. El encapsulado que permite esa integración mencionada es

de tipo POP (Package on Package), donde la memoria está soldada sobre el propio chip, de modo que no es

posible visualizarlo directamente. Con este tipo de encapsulado se consigue reducir el número de pistas

necesarias para la conexión de las memorias optimizando el espacio en la PCB. [4]

El DM3730 está diseñado para permitir un gran rendimiento tanto en aplicaciones con la arquitectura

ARM como en el procesamiento de aplicaciones multimedia mientras ofrece un bajo consumo. Para ello

posee dos núcleos o unidades de proceso, un procesador ARM Cortex-A8 de propósito general a 1GHz y

un chip llamado TMS320C64+ que incluye un procesador digital de señales DSP (Digital Signal Processor)

a 800 Mhz de la familia C64x y una versión más potente del core gráfico SGX, optimizador para trabajar

con datos de video en tiempo real.

El equilibrio entre rendimiento y potencia que ofrece este dispositivo permite un alto rendimiento en

procesado de vídeo, imágenes y gráficos. Gracias a ello, este procesador proporciona soporte a alguna de

las siguientes funcionalidades:

- Streaming de vídeo

- Procesado 2D/3D en dispositivos portátiles.

- Vídeo conferencia.

- Alta resolución de imágenes.

- Captura de vídeo en terminales móviles

Los diferentes subsistemas que conforma en el procesador DM3730 se muestran en la figura 2.5.

BeagleBoard-xM

22

Figura 2.5 - Diagrama de bloques del procesador DM3730

A continuación se describirán brevemente los dos núcleos que componen el procesador DM3730

anteriormente citados, el microprocesador ARM Cortex-A8 y el TMS320C64+. Ambos núcleos son de

arquitecturas diferentes y cuya comunicación se verá en posteriores capítulos.

2.1.1.1 Microprocesador ARM Cortex-A8

El microprocesador ARM Cortex-A8 es un procesador de propósito general de bajo consumo y de altas

prestaciones, siendo la frecuencia de reloj a la que trabaja en esta versión de la BeagleBoard de 1 GHz.

Está basado en la arquitectura ARMv7 y consta de trece etapas en el ciclo de instrucción, dos unidades

aritmético lógicas o ALUs (Arithmetic Logic Units) y una unidad de multiplicación que permite ejecutar

hasta dos instrucciones simultáneamente.

Además, este microprocesador incorpora un coprocesador (NEON) optimizado para aplicaciones

multimedia con unidad de multiplicación-acumulación (MAC) propia y soporte para operaciones en

coma flotante.

2.1.1.2 TMS320C64+

El TMS320C64+ es un procesador de 32 bits de punto fijo con arquitectura VLIW (Very Long Instruction Word)

basado en la versión programable mejorada del núcleo “C64x” a 800 MHz y que incluye un DSP y un

acelerador de audio y video SGX. Al ser un procesador de punto fijo, supone ciertas restricciones en cuanto a

procesamiento de señales respecto a un procesador de punto flotante, no obstante, el consumo de energía es

mucho menor, lo que convierte a este tipo de procesadores en los más adecuados para dispositivos portátiles.

Otro detalle de interés es que la arquitectura de bus es Harvard, en oposición a la de Von Neumann.

23 Configuración y programación del DSP integrado en la plataforma BeagleBoard-xM

El núcleo “C64x+” posee ocho unidades de cálculo con alto grado de independencia en su funcionamiento:

dos unidades de multiplicación capaces de hacer productos de 16 x 16 bits en cada ciclo de reloj y seis ALUs.

Dichas unidades soportan instrucciones especializadas para operaciones con datos de vídeo.

2.1.2 Memoria

La memoria en la BeagleBoard-xM vienen encapsulada en el propio chip DM3730 gracias a la técnica POP,

dotando a la placa de 4Gb de memoria MDDR SDRAM con un bus de 32 líneas (512MB @ 166MHz).

A diferencia de la BeagleBoard original, en la versión xM no hay una memoria NAND en la placa, sin

embargo podremos añadir más memoria no volátil utilizando cualquiera de las siguientes opciones:

- Mediante una tarjeta microSD

- Añadiendo un pendrive o disco duro con adaptador USB en cualquiera de los puertos USB de la

tarjeta o el puerto USB OTG.

2.1.3 Control de alimentación TPS65950

EL TPS65950 se utiliza para proporcionar energía a la tarjeta Beagleboard-xM a excepción de un regulador de

3.3V que se utiliza para proporcionar energía al codificador DVI-D y el controlador RS-232. El TPS65950 da

soporte de energía a:

- La entrada de audio estéreo

- La salida de audio estéreo

- El LED de estado

- USB OTG PHY

El TPS65950 también integra un codificador/descodificador de audio (codec) que incluye cinco convertidores

digital/analógico (DAC) y dos convertidores analógico/digital (ADC). Además cuenta con amplificadores

para la salida así como una entrada de línea estéreo y una interfaz para micrófonos digitales.

2.1.4 Puerto USB 2.0 OTG

El puerto USB OTG se puede utilizar como fuente de alimentación primaria y también como enlace de

comunicación. Para utilizarlo como alimentación desde un PC será necesario un mínimo de 500mA. En la

mayoría de los casos un PC o portátil no suministra suficiente corriente como para alimentar la placa, ya que

no proporciona los 500mA al completo. No obstante es posible suministrar hasta 1A con un cable en Y, como

se muestra en la figura 2.6. Obviamente, cuando no se usa el conector USB OTG para alimentar la tarjeta, es

necesario alimentar ésta a través del conector de alimentación DC.

Figura 2.6 - Cable USB en Y

BeagleBoard-xM

24

2.1.5 Conector DC

El conector DC de 5V permite alimentar la placa. A diferencia del conector OTG, mediante este conector es

posible suministrar a la placa la suficiente energía para tener acceso a todas las funcionalidades de la placa.

Cuando se enchufa este conector, la alimentación mediante el puerto USB OTG queda anulada.

2.1.6 Puertos USB 2.0 y Ethernet

Se pueden encontrar hasta 4 puertos de este tipo en la placa. Estos puertos pueden suministrar energía de

hasta 500mA y 5V de tensión, siempre que la placa esté alimentada por una corriente continua de 3A como

mínimo. Los puertos USB no funcionarán a menos que este alimentado por el conector DC, ya que no pueden

ser alimentados desde el puerto USB OTG. Además la placa contiene un puerto 10/100 Ethernet.

2.1.7 Conector JTAG

La tarjeta BeagleBoard-xM incorpora un conector de 14 pines para permitir el desarrollo y depuración de

software.

2.1.8 Conector Serie RS-232

En la BeagleBoard-xM es posible la comunicación serie RS-232 gracias al conector DB9 que incluye la placa.

Este conector está comunicado con la UART3 del procesador, para ello incorpora entre ambos un dispositivo

para adaptar los niveles de tensión de la comunicación RS-232 a los de la UART3 empleada para manejar la

comunicación serie (CMOS).

La conexión a través de RS-232 es empleada como interfaz de usuario para mostrar un terminal de consola del

sistema operativo embebido en la BeagleBoard, permitiendo el envío y recepción de comandos.

2.1.9 Conector S-Video

Se dispone de un conector DIN de 4 pines para acceder a la salida S-Video de la BeagleBoard-xM. Se trata de

una salida independiente del procesador y puede contener diferentes datos de salida de vídeo de lo que se

encuentra en la salida DVI-D si el software está configurado para hacerlo.

Soporta los formatos NTSC y PAL. El valor predeterminado es NTSC, pero se puede cambiar a través del

Software.

2.1.10 Conector DVI-D

La BeagleBoard-xM se puede conectar a un monitor LCD que lleve incorporado una entrada DVI-D. Para ello,

el procesador ofrece un interfaz DVI-D que soporta 24 bits de color de salida. Dado el gran tamaño del

conector DVI-D y a la falta de espacio en la tarjeta, ésta incorpora un conector HDMI, de dimensiones

reducidas, por lo que para conectar un monitor con entrada DVI-D se debe usar un cable con un conector DVI-

D en un extremo (monitor) y un conector HDMI en el otro extremo (BeagleBoard). Por supuesto también es

posible conectarla a un monitor con entrada HDMI mediante un cable HDMI.

25 Configuración y programación del DSP integrado en la plataforma BeagleBoard-xM

2.1.11 Conector microSD

En la tarjeta microSD irá el sistema operativo que arrancará la placa. Se utiliza un conector push-push para la

inserción y extracción de la tarjeta microSD. El conector está montado en el lado inferior de la placa.

2.1.12 Conector de audio entrada/salida

La placa dispone de dos conectores jack estándar de 3.5mm para proporcionar audio estéreo de entrada y

salida. En este proyecto se hará uso de ellos para obtener y reproducir las muestras de audio.

2.1.13 Pines de expansión

La placa trae 28 pines principales de expansión que permiten la conexión de varias tarjetas que podría ser

desarrollada por los usuarios o de otras fuentes para ampliar las funcionalidades de la tarjeta. Debido a la

multiplexación, cada pin puede proporcionar diferentes señales. Además de estos 28 pines, la placa permite

otras series de expansiones como por ejemplo:

- Un conector que permite añadir una cámara a la BeagleBoard-xM

- 4 pines para acceder a la interfaz de comunicación McBSP.

- Conectores de 20 pines para acceder al puerto MMC3 y las señales GPIO.

2.1.14 Botones

Existen dos botones en la placa, el botón reset que permite reiniciar la placa y el botón de usuario. El botón de

usuario puede utilizarse como botón de aplicación por el software si lo necesita. Al no incluir NAND esta

versión de la BeagleBoard, ya no será utilizará este botón para forzar el arranque desde la tarjeta SD.

2.1.15 Indicadores

Hay cinco indicadores LED verdes en la BeagleBoard-xM que pueden ser controlados por el usuario.

- Uno en el TPS65950 que se programa a través de la interfaz I2C

- Dos en el procesador controlado por los pines GPIO.

- Un LED de encendido.

- Uno para indicar que se aplica energía al HUB USB integrado.

También hay un LED rojo que indica si la potencia suministrada a la placa es superior a la permitida. Si este

LED se mantiene encendido, habrá que retirar el conector de alimentación y buscar una fuente de

alimentación correcta para evitar daños en la placa.

Configuración y puesta a punto

26

3 CONFIGURACIÓN Y PUESTA A PUNTO

a BeagleBoard-xM trae por defecto una tarjeta microSD de 4 GB que incluye un distribución de Linux

basada en Debian para sistemas embebidos llamada “Ångström”. Esta distribución es el resultado de la

unión de varios proyectos, OpenZaurus, OpenEmbedded y OpenSimpad.

Aun así es posible instalar cualquier otra distribución para sistemas embebido como Ubuntu, Windows CE o

Android si el usuario así lo desea. En este proyecto se ha probado a instalar los sistemas operativos antes

citados pero se ha decidido por usar Angstrom gracias al apoyo que ofrece a la comunidad que hay detrás a la

BeagleBoard, además de ser el software que instala el fabricante por defecto.

3.1 Instalación del sistema operativo

Como se ha comentado es posible instalar casi todo tipo de sistemas operativos diseñados para sistemas

embebidos. En este punto se mostrará como instalar la distribución Angstrom y Ubuntu de manera sencilla.

Pese a no ser necesario este paso puesto que en la microSD viene pre-instalado una versión de Angstrom, se

trata de conocer los pasos necesarios que habría que hacer en caso de querer cambiar el S.O. de la

BeagleBoard-xM.

En primer lugar, se necesita un PC con un sistema operativo Linux como el propio Ubuntu y una tarjeta

microSD de 4GB o más. El software necesario se encuentra en la web de las distintas distribuciones, en el caso

de Ubuntu sería [7]. Para la BeagleBoard por ejemplo la versión 12.04 sería:

http://cdimage.ubuntu.com/releases/12.04.3/release/ubuntu-12.04-preinstalled-desktop-armhf+omap.img.gz

Una vez descargado, solo será necesario tener la microSD conectada al PC e introducir los siguientes

comandos en la consola.

df -h

Con este comando se mostrará la ruta de los distintos dispositivos de almacenamiento que haya en el PC, en

este caso la ruta de la microSD es /dev/sdb1 como se muestra en la figura 3.1

Figura 3.1 – Comando df –h

L

27 Configuración y programación del DSP integrado en la plataforma BeagleBoard-xM

A continuación, escribiendo lo siguiente en el terminal la tarjeta se formateará y se instalará el archivo

descargado. Nótese que se ha escrito of=/dev/sdb debido a que esa es la ubicación de la microSD en el PC que

se ha utilizado como ejemplo, pudiendo variar según el PC que se use. Una vez termine, solo faltaría

conectarla a la BeagleBoard-xM para empezar a usar Ubuntu.

zcat ./ubuntu-12.04-preinstalled-desktop-armhf+omap4.img.gz |sudo dd bs=4M of=/dev/sdb ; sudo sync

En el caso de Angstrom sería igual de sencillo, pudiendo elegir entre distintas imágenes ya creadas del

repositorio o crear una propia mediante la web de la distribución en la pestaña “Online builder” [8]. Para ello

habría que utilizar los mismos comandos que para Ubuntu con una de las imágenes que se encuentra en la

siguiente url, como por ejemplo “Angstrom-TI-GNOME-image-eglibc-ipk-v2012.01-core-beagleboard-

2012.01.11.img.gz”:

http://downloads.angstrom-distribution.org/demo/beagleboard/

O bien, para aquellas imágenes con extensiones “tar.gz” o “tar.bz2” sería necesario aplicar estos otros

comandos. En primer lugar, habrá que descargarse un pequeño script o archivo con un pequeño programa

que formateará la microSD, siendo dev/sdX la ubicación de la microSD que se quiera formatear.

mkdir ~/angstrom-wrk

cd ~/angstrom-wrk

wget http://cgit.openembedded.org/cgit.cgi/openembedded/plain/contrib/angstrom/omap3-mkcard.sh

chmod +x omap3-mkcard.sh

sudo ./omap3-mkcard.sh /dev/sdX

sync

Si se escribe el comando “df –h” se podrá observar que se habrán creado dos particiones, /media/boot y

/media/Angstrom. A continuación, para instalar la imagen con extensión tar.bz2 por ejemplo, primero habrá

que descomprimir la imagen y luego copiar los archivos necesarios en la partición correcta.

tar -xvj [Nombre de la imagen Angstrom].tar.bz2

Dentro de la carpeta donde se haya descomprimido habrá una carpeta llamada boot. Los archivos que allí

se encuentren habrá que copiarlos a la partición “boot” mediante:

cp boot/MLO-* /media/boot/MLO

cp boot/uImage-* /media/boot/uImage

cp boot/u-boot-*.bin /media/boot/u-boot.bin

sync

El resto de los archivos se ubicarán en la otra partición.

sudo tar -xvj -C /media/Angstrom -f [Nombre de la imagen Angstrom].tar.bz2

sync

Configuración y puesta a punto

28

Una vez finalizado, la microSD estará lista para conectarla a la BeagleBoard-xM. También es posible guardar

en el PC el repositorio “OpenEmbedded” para crear una imagen valida de Angstrom compatible con la

BeagleBoard, además de otros tipos de software compatible con la tarjeta como “dsplink”, siendo esta otra

forma de conseguir tanto el software como los módulos necesarios sin usar los pasos que se verán más

adelante.

En la partición “boot” estarán aquellos archivos necesarios para el arranque del hardware. Estos son “Image”,

“u-boot.bin” y “MLO”. Una vez arranque será el sistema operativo quien tome el control de la tarjeta. En dicha

partición también habrá un archivo llamado “Env.txt”, en caso de que no esté habrá que crearlo.

En Env.txt se deberá introducir una serie de instrucciones para permitir el correcto funcionamiento del sistema

operativo, entre las que se encuentra la resolución de la pantalla o la zona de memoria que compartirán el DSP

y el procesador ARM si se quiere usar el DSP, por ejemplo, para las distintas versiones de la Beagleboard

habría que añadir a Env.txt “mem=99M@80000000 mem=128M@0x88000000” si tienen 256MB de ram,

“mem=99M@80000000” para aquellas con 128MB de ram y “mem=99M@80000000 mem=384M@0x88000000”

para las que tienen 512MB como es el caso de la BeagleBoard-xM. Para este proyecto el archivo Env.txt

contiene lo siguiente:

vram=24M

dvimode=”hd720 mem=99M@0x80000000 mem=384M@0x88000000 omapfb.vram=0:12M,1:8M,2:4M”

optargs=”consoleblank=0”

console=”tty0 console=ttyS2,115200n8”

uenvcmd=run loaduimage; run mmcboot

Figura 3.2 – Pantalla inicial del SO Angstrom.

29 Configuración y programación del DSP integrado en la plataforma BeagleBoard-xM

3.2 Montaje

En el embalaje de la BeagleBoard-xM viene tanto la placa como la microSD con el software pre-instalado, por tanto del montaje deberá encargarse el usuario, teniendo varias opciones disponibles como la posibilidad de acceder a la consola de la tarjeta mediante el cable serie y un PC, o utilizarla de manera independiente sin necesidad de un PC externo.

Esta última opción es la que se ha utilizado en el proyecto donde se ha precisado de un cable HDMI para conectarla a un monitor o TV compatible con HDMI, un adaptador DC de 5V y tanto un teclado como un ratón con conectores USB. Tras conectarlo todo y esperar unos minutos a que se cargue el SO deberíamos ver en pantalla lo que se muestra en la figura 3.2.

3.3 Toolchain

Para crear un ejecutable compatible con las arquitecturas ARM y DSP del DM3730 se hará uso de unas determinadas toolchains, se trata de un conjunto de herramientas o utilidades que se emplean para obtener aplicaciones para una plataforma concreta de hardware. Por ejemplo, para crear aplicaciones que funcionen en un sistema operativo Linux sobre una plataforma x86 se utiliza la GNU toolchain.

Como su nombre indica, una toolchain consiste en una cadena de herramientas software entre las que se encuentran los siguientes elementos:

- Editor de texto para editar el código fuente.

- Compilador encargado de transformar el código fuente (por ejemplo en lenguaje C) a lenguaje ensamblador.

- Ensamblador cuya misión es la de generar archivos objeto en código maquina a partir del código fuente generado por el compilador.

- Enlazador necesario para generar el ejecutable a partir de los archivos objetos y las librerías.

- Bibliotecas para proveer de una interfaz al sistema operativo

- Depurador usado para probar y eliminar errores.

La toolchain que se ha utilizado para crear ejecutables en ARM ha sido la que ofrece Angstrom en su web, mientras que para crear los ejecutables en el DSP se ha utilizado la toolchain de Texas Instruments para procesadores de la familia C6000 llamada “Code Generation Tools”, cuya instalación se detallará en el siguiente capítulo. En cuanto a la toolchain ARM, se puede descargar a través de la web de Angstrom en el siguiente enlace:

http://www.angstrom-distribution.org/toolchains

Una vez descargado el archivo llamado angstrom-2011.03-i686-linux-armv7a-linux-gnueabi-toolchain.tar.bz2 habrá que descomprimirlo en la carpeta raíz utilizando el terminal.

sudo tar –C -xjvf angstrom-2011.03-i686-linux-armv7a-linux-gnueabi-toolchain.tar.bz2

Normalmente cuando se compila un programa en un PC, éste se puede ejecutar en el propio PC, sin embargo las aplicaciones que se compilen con esta toolchain no será posible ejecutarla en el mismo PC. Esto es debido a que como ya se indicó antes, esta toolchain se utilizan para compilar un código para arquitecturas ARM, mientras que los PCs normalmente tienen otra arquitectura llamada x86 (Intel, AMD). Es por ello por lo que se les denomina cross-compiler (compilador cruzado), dado que el PC será la plataforma de desarrollo de la aplicación (HOST) mientras que el sistema embebido BeagleBoard-xM será la plataforma donde se ejecutará dicha aplicación (TARGET).

Configuración y puesta a punto

30

3.4 Entorno de desarrollo Eclipse

Para desarrollar las aplicaciones es posible hacer uso de un entorno de desarrollo como Eclipse. A pesar de que existe un entorno de desarrollo creado por Texas Instruments llamado Code Composer Studio y que está especialmente diseñado para trabajar cómodamente con hardware que hagan uso de su tecnología como la BeagleBoard, se descartó la idea de utilizarlo por ser de pago en oposición con Eclipse. Además el Code Composer Studio está basado en el propio Eclipse. A continuación se describirá los pasos necesarios para configurar y crear una aplicación simple como “hello_world” que podrá ser ejecutado en la BeagleBoard. Para ello se ha hecho uso del tutorial empleado en esta web [1].

3.4.1 Instalación

Tras instalar la toolchain, lo primero será instalar Eclipse, este se puede encontrar de forma gratuita en la siguiente url, donde aparecen distintos programas según el lenguaje que se quiera utilizar o el uso que se le quiera dar.

http://www.eclipse.org/downloads/

Si se quiere usar el lenguaje C/C++ habrá que descargar el archivo Eclipse IDE for C/C++ Developers, o bien descargar las herramientas para el desarrollo de aplicaciones C/C++ a través del propio programa desde Help Install New Software y descargar el paquete C/C++ Development Tools. Una vez instalado Eclipse, al ejecutarlo habrá que seleccionar la ubicación de la carpeta workspace donde se guardarán las aplicaciones creadas. Lo siguiente será crear un nuevo proyecto desde File New Project.

En la ventana de New Project habrá que seleccionar C/C++ y a continuación C Project. Haciendo click en Next aparecerá una ventana donde se pedirá que se introduzca el nombre del proyecto y para finalizar habrá que pulsar Finish.

Figura 3.3 – Pantalla del entorno de desarrollo Eclipse

31 Configuración y programación del DSP integrado en la plataforma BeagleBoard-xM

3.4.2 Configuración

Ahora será necesario configurar Eclipse para que al compilar utilice el compilador cruzado. Para ello desde la ventana Project Explorer y utilizando el botón derecho del ratón se abre una nueva ventana donde habrá que seleccionar Build Configurations -> Manage como se muestra en la figura 3.3.

Haciendo clic en New aparecerá una nueva ventana donde introducir la configuración para el compilador cruzado. Una vez puesto el nombre a esta nueva configuración como por ejemplo bb_debug, en Existing configuration habrá que seleccionar Debug. Ahora haciendo clic derecho en el nombre del proyecto (hello_world) que encuentra en Project Explorer, habrá que pinchar en Properties. Se abrirá una nueva ventana como se muestra en la figura 3.4.

Figura 3.4 – Ventana de propiedades de un proyecto creado en Eclipse

A continuación habrá que hacer los siguientes pasos:

- Seleccionar C/C++ Build Settings y en Configuration seleccionar bb_debug.

- Hacer clic en GCC C Compiler y poner en Command /usr/local/angstrom/arm/bin/arm-angstrom-linux-gnueabi-gcc o su dirección equivalente según donde se encuentre la toolchain.

- Bajo GCC C Compiler, pinchar en Includes. En Include paths (-l) hacer click en el icono de agregar nueva ruta e introducir /usr/local/angstrom/arm/arm-angstrom-linux-gnueabi/usr/include o su dirección equivalente según donde se encuentre la toolchain.

- Hacer clic en GCC C Linker y poner en Command /usr/local/angstrom/arm/bin/arm-angstrom-linux-gnueabi-gcc o su dirección equivalente según donde se encuentre la toolchain.

- Bajo GCC C Linker, pinchar en Libraries. En Library search path (-L) hacer click en el icono de agregar nueva ruta e introducir /usr/local/angstrom/arm/arm-angstrom-linux-gnueabi/lib o su dirección equivalente según donde se encuentre la toolchain.

- Hacer clic en GCC Asambler y poner en Command /usr/local/angstrom/arm/bin/arm-angstrom-linux-gnueabi-as o su dirección equivalente según donde se encuentre la toolchain.

Configuración y puesta a punto

32

Por último, haciendo clic derecho en el nombre del proyecto (hello_world), habrá que seleccionar Build Configurations Set Active y posteriormente bb_debug.

3.4.3 Compilando un código en C

Tras configurar correctamente el entorno de desarrollo para utilizar el compilador cruzado, solo hace falta crear una aplicación. Como ejemplo se propuso hacer un hello_world en lenguaje C. Para ello habrá que hacer click en File New Source y poner nombre al archivo, como por ejemplo hello_world.c, y escribir el código.

Tras guardar el proyecto, para compilarlo hay que hacer click en Project Build Project y esperar a que termine. Se creará un ejecutable llamado hello_world en la carpeta del proyecto /workspace/hello_world/bb_debug/ listo para ejecutar en la BeagleBoard-xM.

33 Configuración y programación del DSP integrado en la plataforma BeagleBoard-xM

4 COMUNICACIÓN CON EL DSP

l DSP que incorpora la BeagelBoard-xM está integrado en el mismo chip que el procesador de propósito

general (GPP - General Purpose Processor) ARM tal y como se comentó en capítulos anteriores. Dicho DSP

actúa de esclavo respecto al GPP de tal manera que recibiría los datos junto con la instrucción a realizar

y una vez terminado envía el resultado de nuevo al procesador principal. Para ello hacen uso de unos

registros internos o “mailboxes” que ambos conocen.

Con el fin de facilitar el manejo de estos registros Texas Instruments proporciona unas librerías que se

encargan de esa tarea. Las librerías pueden descargarse desde la web de Texas Instruments con el nombre de

o DSPLink.

4.1 DSPLink

DSP / BIOS ™ Link es un software que permite la comunicación entre el GPP y el DSP. Este software proporciona una interfaz de programación de aplicaciones (API) genérica que abstrae las características del enlace físico que conecta dicho GPP y DSP. Se elimina así la necesidad de desarrollar tal relación desde cero, permitiendo al usuario centrarse en el desarrollo de las aplicaciones. DSP / BIOS ™ será el sistema operativo que se ejecuta en el lado del DSP como puede observarse en la figura 4.1.

Figura 4.1 – Arquitectura de DSPLink

4.1.1 Funciones disponibles

DSPLink ofrece una serie de componentes para el desarrollo de aplicaciones. El funcionamiento de estos componentes debe conocerse previamente si se desea programa sobre DSPLink ya que cada uno tiene un propósito y no todos son necesarios según la aplicación que se desee crear. A continuación se describirá los componentes y su funcionamiento brevemente, pudiéndose ampliar esta información siempre que se desee consultando los manuales de usuario y programador que facilita Texas Instruments en los siguientes enlaces [10] [11].

E

Comunicación con el DSP

34

4.1.1.1 PROC

PROC es siempre necesario para todas las aplicaciones que usen DSPLink. Proporciona la funcionalidad básica para establecer la configuración, gestionar el arranque, el control y la comunicación con los otros procesadores del sistema.

4.1.1.2 NOTIFY

NOTIFY se usa para mensajería y transferencia en el caso de que:

- La información a traspasar entre procesadores sea de longitud 32 bits

- Se necesite prioridad en las notificaciones. Por ejemplo, un evento con baja prioridad puede usarse para enviar punteros a búfers, mientras que otro evento con prioridad más alta puede emplearse para el envío de comandos.

- Las notificaciones sean poco frecuentes. Si se envían múltiples notificaciones muy rápidamente para el mismo evento, cada intento permanece a la espera hasta que el evento previo ha sido atendido. Esto puede provocar un funcionamiento poco eficiente.

- Múltiples clientes necesiten registrarse para recibir el mismo evento de notificación. Cuando se recibe la notificación de evento, la misma notificación con una pequeña sobrecarga de datos se reenvía a todos los clientes registrados para esa misma notificación.

4.1.1.3 MSGQ

MSGQ se puede emplear para transferencia de mensajes y de datos si:

- La aplicación necesita un solo lector y múltiples escritores

- Se necesitan datos de longitudes superiores a 32 bits, que se enviarán en estructuras de mensaje definidas por el usuario

- Se necesitan mensajes de tamaño variable

- El lector y escritor manejan los mismos tamaños de buffer

- Se necesita intercambiar mensajes con frecuencia. En este caso los mensajes esperan en una cola y no es necesario esperar a que el evento anterior finalice.

- Se desea poder esperar cuando la cola está vacía. Este comportamiento es el natural del protocolo MSGQ y no es necesario añadir código desde la aplicación.

4.1.1.4 MPLIST

MPLIST puede usarse para la transferencia de mensajes y de datos en caso de que:

- La aplicación necesite múltiples lectores y escritores.

- La aplicación desee procesar los paquetes recibidos en otro orden del de llegada. Esto no es

posible con MSGQ ni con NOTIFY. Con NOTIFY, el lector puede alterar la lista compartida y

escoger cualquier buffer.

- Se desee marcar un buffer específico como de alta prioridad.

- Se desee flexibilidad a la hora de notificar los eventos de enviado y recibido.

- El lector y el escritor tengan los mismos tamaños de buffer.

- Los datos a intercambiar sean de longitud superior a 32 bits.

- Se requieran buffers de tamaño variable destinados a datos y mensajes.

- Se necesite enviar mensajes e información frecuentemente.

4.1.1.5 CHNL

CHNL permite transferir datos si:

- Se necesita un único lector y un único escritor.

- Los búfers de datos son de tamaño fijo.

35 Configuración y programación del DSP integrado en la plataforma BeagleBoard-xM

- Lector y escritor tienen el mismo tamaño de buffer.

- Es necesario utilizar drivers SIO para otros periféricos al mismo tiempo que la comunicación del

GPP con el DSP.

- Se requiere un protocolo sencillo para streaming de datos. Para estos casos CHNL proporciona

un protocolo sencillo de demanda-suministro de datos.

- Múltiples búfers pueden ser fácilmente encolados para un mayor rendimiento.

4.1.1.6 RingIO

RingIO puede emplearse para transferir mensajes y datos si:

- Sólo se necesita un único lector y un único escritor.

- Debe ser posible enviar y recibir datos, al igual que atributos/mensajes asociados a los datos.

- Lector y escritor necesitan seguir ejecutandose con independencia del otro. El tamaño del buffer

empleado por el escritor puede ser diferente del tamaño que usa el escritor.

- Lector y escritor quieren liberar menos memoria de la que reservaron inicialmente o quieren

solicitar más memoria sin liberar ninguna.

- Las aplicaciones tienen necesidades de notificación distintas. La aplicación puede minimizar las

interrupciones escogiendo el tipo de notificación más apropiado.

- Se desea tener la posibilidad de eliminar datos no utilizados del buffer.

- Se desea poder vaciar el contenido de un buffer entero. Esto puede ser interesante en el caso de

una reproducción de un fichero multimedia y se interrumpe para empezar a descodificar un

fichero nuevo.

4.1.2 Posibles escenarios

Para explicar el funcionamiento y uso de los anteriores componentes de DSPLink se describen tres posibles

escenarios para la comunicación del GPP con el DSP mediante DSPLink. Para cada escenario se verá una

solución diferente así como las componentes usadas.

4.1.2.1 Búfer estático entre GPP y DSP.

Figura 4.2 – Escenario de búfer estático

Comunicación con el DSP

36

En este escenario se emplea PROC para arrancar el DSP, el ejecutable del DSP estará en el sistema de ficheros del GPP. En tiempo de compilación se pueden reservar dos regiones de memoria a través del fichero dinámico de configuración (CFG_<PLATFORM>.c). En el lado del DSP, habrá que realizar una configuración similar en el fichero TCF para reservar la memoria. Una de las regiones de memoria podrá emplearse para las transferencias en el sentido del GPP al DSP, y la otra para en el sentido contrario, es decir, del DSP al GPP. Debido a que la memoria está reservada estáticamente, tanto el GPP como el DSP saben las direcciones de inicio y los tamaños de ambas memorias. NOTIFY podrá usarse para enviar mensajes de control de 32 bits.

4.1.2.2 Búfer dinámico entre GPP y DSP.

Figura 4.3 – Escenario de búfer dinámico

En este escenario se emplea de nuevo PROC para arrancar el DSP, y como en el anterior el ejecutable del DSP

estará en el sistema de ficheros del GPP. En este caso se abrirá un espacio denominado POOL con la

configuración de los búfers que compartirán el GPP y el DSP. Se reservan los espacios para los búfers del

POOL según necesiten el GPP y el DSP durante la fase de inicio. Si se ha reservado el búfer desde el GPP

mediante la función POOL_alloc (), la dirección de este búfer podrá traducirse al espacio de direcciones

del DSP usando la función POOL_translateAddr (). Para enviar esta información o cualquier otra podrá

emplearse NOTIFY. Si es al contrario el DSP puede traducir la dirección al espacio de direcciones del

GPP mediante la función POOL_translateAddr (). Una vez hecho esto los búfers ya pueden ser usados por

el GPP y el DSP para intercambiar información y datos. Se puede emplear el módulo NOTIFY para

informar a los procesadores de que hay datos disponibles en el búfer o que el búfer se ha vaciado y

liberado. En caso de que se necesite mecanismos de exclusión mutua para el acceso a los búfers que

comparten el GPP y el DSP puede usarse MPCS para proteger estos accesos.

37 Configuración y programación del DSP integrado en la plataforma BeagleBoard-xM

4.1.2.3 Múltiples Búfers compartidos entre GPP y DSP.

Figura 4.4 – Escenario para múltiples búfers

Como en los dos casos anteriores, se emplea PROC para arrancar el DSP. El ejecutable del lado del DSP

estará en el sistema de ficheros del GPP. Se utiliza POOL para la configuración del tamaño de los búfers

que compartirán los dos procesadores como se describió en el escenario anterior, pero en este caso si uno

de los procesadores necesita enviar múltiples búfers de una sola vez, deberá usar MSGQ o MPLIST en

vez de NOTIFY. Si además se quiere enviar información adicional asociada al búfer, por ejemplo

atributos del búfer, se puede definir una estructura de mensaje con estos atributos y usar el componente

MSGQ o MPLIST para transmitir este mensaje al otro procesador.

4.1.3 Instalación de DSPLink

4.1.3.1 Descarga e instalación del software necesario

En este punto se describirá como instalar en el PC (HOST) todo el software necesario para utilizar

DSPLink en la BeagleBoard. Para ello lo primero será descargar los paquetes necesarios desde la web de

Texas Instruments. Es posible que para descargar alguno de estos paquetes sea necesario tener una

cuenta dicha web. Estos paquetes serán:

- ti_cgt_c6000_6.1.1.17_setup_linux_x86.bin

- ti_xdctools_setuplinux_3_20_06_81.bin

- bios_setuplinux_5_41_07_24.bin

- dsplink_linux_1_65_00_03.tar.gz

Para cada paquete se ha usado la última versión disponible en el momento que se realizó este proyecto.

Una vez descargados, para instalarlos primero hay que hacer los binarios ejecutables:

Comunicación con el DSP

38

chmod +x ti_cgt_c6000_6.1.1.17_setup_linux_x86.bin

chmod +x ti_xdctools_setuplinux_3_20_06_81.bin

chmod +x bios_setuplinux_5_41_07_24.bin

Luego ejecutarlos e instalarlos. Es recomendable instalar todos en la misma carpeta para tenerlos

ubicados, por ejemplo en una carpeta llamada TI.

./ti_cgt_c6000_6.1.1.17_setup_linux_x86.bin

./ti_xdctools_setuplinux_3_20_06_81.bin

./bios_setuplinux_5_41_07_24.bin

Y por último hay que descomprimir aquellos paquetes que vienen comprimidos en la misma carpeta TI.

tar -xvf dsplink_linux_1_65_00_03.tar.gz

4.1.3.2 Configuración de DSPLink

Ahora se tratará de configurar DSPLink. Para ello primero hay que instalar las variables de entorno, en el

caso de este proyecto son:

export DSPLINK=/home/javi/ti/dsplink_linux_1_65_00_03/dsplink

export C6X_C_DIR="/home/javi/ti/TI_CGT_C6000_6.0.31/include:/home/javi/ti/TI_CGT_C6000_6.0.31/lib"

export XDC_INSTALL_DIR=/home/javi/ti/xdctools_3_10_05_61

Luego habrá que construir DSPLink para la BeagleBoard:

cd dsplink/config/bin

perl dsplinkcfg.pl --platform=OMAP3530 --nodsp=1 --dspcfg_0=OMAP3530SHMEM --dspos_0=DSPBIOS5XX --gppos=OMAPLSP --comps=ponslrmc

Nótese que en el comando perl como plataforma viene indicado OMAP3530 pese a que la BeagleBoard-

xM no usa este procesador como ya se ha indicado. Esto no supondrá un problema debido a que el

DM3730 está basado en el OMAP3530 y por tanto es compatible con las herramientas pensadas para el

OMAP3530.

Ahora será necesario modificar tres archivos para indicarle a DSPLink donde se encuentran el

compilador del DSP, librerías, BIOS, etc. Estos ficheros serán:

$(DSPLINK)/make/Linux/omap3530_2.6.mk

$(DSPLINK)/gpp/src/Rules.mk

$(DSPLINK)/make/DspBios/c64xxp_5.xx_linux.mk

39 Configuración y programación del DSP integrado en la plataforma BeagleBoard-xM

Para el fichero omap3530_2.6.mk hay que modificar las siguientes líneas indicando la ubicación de cada

herramienta:

BASE_BUILDOS := /home/javi/linux-omap-2.6/

BASE_TOOLCHAIN := /usr/local/angstrom/arm

BASE_CGTOOLS := $(BASE_TOOLCHAIN)/bin

OSINC_PLATFORM := $(BASE_TOOLCHAIN)/lib/gcc/arm-angstrom-linux-gnueabi/4.3.3/include

OSINC_TARGET := $(BASE_TOOLCHAIN)/arm-angstrom-linux-gnueabi/include/c++/4.3.3

COMPILER := $(BASE_CGTOOLS)/arm-angstrom-linux-gnueabi-gcc-

LD := $(BASE_CGTOOLS)/arm-angstrom-linux-gnueabi-ld

CROSS_COMPILE := $(BASE_CGTOOLS)/arm-angstrom-linux-gnueabi-

ARCHIVER := $(BASE_CGTOOLS)/arm-angstrom-linux-gnueabi-ar

LINKER := $(BASE_CGTOOLS)/arm-angstrom-linux-gnueabi-gcc

En el caso de Rules.mk:

KERNEL_DIR := /home/javi/linux-omap-2.6/

TOOL_PATH := /usr/local/angstrom/arm

CG_PREFIX = arm-angstrom-linux-gnueabi-

MAKE_OPTS = ARCH=arm CROSS_COMPILE=$(TOOL_PATH)/bin/arm-angstrom-linux-gnueabi-

Y por último para c64xxp_5.xx_linux.mk:

BASE_INSTALL := ${HOME}/ti

BASE_SABIOS := $(BASE_INSTALL)/bios_5_41_07_24

XDCTOOLS_DIR := $$(BASE_INSTALL)/xdctools_3_20_06_81

BASE_CGTOOLS := $(BASE_INSTALL)/TI_CGT_C6000_6.1.1.17

Para el kernel se ha empleado una versión compatible del kernel 2.6 que trae el sistema operativo

Angstrom instalado en la BeagleBoard-xM. Es posible descargarlo desde el terminal del PC HOST

mediante:

git clone git://git.kernel.org/pub/scm/linux/kernel/git/tmlind/linux-omap-2.6.git

Y para configurarlo para la plataforma BeagleBoard:

make CROSS_COMPILE=arm-angstrom-linux-gnueabi- ARCH=arm omap3_beagle_defconfig

Comunicación con el DSP

40

4.1.3.3 Creación de las librerías y del módulo dspinkk.ko

Una vez se ha configurado los respectivos ficheros, ya podemos compilar DSPLink para que cree el

driver dsplinkk.ko, así como las librerías. Para ello habrá que introducir los siguientes comandos.

En $(DSPLINK)/dsp:

$XDC_INSTALL_DIR/xdc clean

$XDC_INSTALL_DIR/xdc .interfaces

En $(DSPLINK)/gpp:

$XDC_INSTALL_DIR/xdc clean

$XDC_INSTALL_DIR/xdc .interfaces

En $(DSPLINK)/dsp/src:

make -s clean

make -s debug

make -s release

En $(DSPLINK)/dsp/src/samples:

make -s clean

make -s debug

make -s release

En $(DSPLINK)/gpp/src/api:

make -s clean

make -s debug

make -s release

En $(DSPLINK)/gpp/src:

make -s clean

make -s debug

make -s release

En $(DSPLINK)/gpp/src/samples:

41 Configuración y programación del DSP integrado en la plataforma BeagleBoard-xM

make -s clean

make -s debug

make -s release

Una vez terminado el proceso, se habrá creado el driver dsplinkk.ko en cualquiera de los siguientes

directorios:

$(DSPLINK)/gpp/export/BIN/Linux/OMAP3530/DEBUG

$(DSPLINK)/gpp/export/BIN/Linux/OMAP3530/RELEASE

Y las librerías tanto del lado del GPP como del lado del DSP:

$(DSPLINK)/dsp/export/BIN/DspBios/OMAP3530/OMAP3530_0/DEBUG

$(DSPLINK)/dsp/export/BIN/DspBios/OMAP3530/OMAP3530_0/RELEASE

$(DSPLINK)/gpp/export/BIN/Linux/OMAP3530/DEBUG

$(DSPLINK)/gpp/export/BIN/Linux/OMAP3530/RELEASE

4.1.3.4 Creación del módulo LPM

El módulo LPM (Local Power Management) se encarga de la gestión de energía en dispositivos ARM-DSP.

Para crearlo habrá que seguir unos pasos parecidos a los anteriores. Primero hay que descargar el paquete

software local_power_manager_1_23_01.tar.gz.Tras descomprimirlo, los archivos necesarios para crear el

modulo se encontrarán en el directorio:

/ local_power_manager_1_23_01/packages/ti/bios/power/modules/omap3530

Ahora habrá que modificar el Makefile que se encuentra dentro del directorio lpm:

LINUXKERNEL_INSTALL_DIR = /home/javi/linux-omap-2.6

MVTOOL_PREFIX = /usr/local/angstrom/arm /bin/ arm-angstrom-linux-gnueabi

DSPLINK_REPO = /home/javi/ti/dsplink_linux_1_65_00_03/dsplink

Tras ejecutar “make” el módulo lpm_omap3530.ko se creará en ese mismo directorio.

4.1.3.5 Creación del módulo CMEM

El módulo CMEM (Contiguous Memory Allocator) permite reservar espacios de memoria contiguos

fuera del espacio de memoria del sistema operativo y hacerlo accesible para el procesador. Gracias a ello

permite intercambiar grandes bloques de información entre los núcleos GPP y DSP de manera segura y

eficaz sin riesgo a que se fragmente dicho espacio o acceda al espacio de memoria reservado por el

sistema operativo.

Para crear dicho módulo habrá que descargarse el paquete linuxutils_2_23_01.tar.gz y modificar el archivo

Rules.make que se encuentra en el directorio:

/linuxutils_2_23_01/packages/ti/sdo/linuxutils/cmem/

Comunicación con el DSP

42

MVTOOL_PREFIX= /usr/local/angstrom/arm /bin/ arm-angstrom-linux-gnueabi

UCTOOL_PREFIX= /usr/local/angstrom/arm /bin/ arm-angstrom-linux-gnueabi-

LINUXKERNEL_INSTALL_DIR= /home/javi/linux-omap-2.6

Y tras ejecutar “make release” el modulo se creará en el directorio …/cmem/src/module/cmemk.ko.

4.1.3.6 Cargar los módulos creados en la plataforma BeagleBoard-xM

Una vez realizado todo lo anterior, el siguiente paso sería cargar los módulos o drivers creados en la

BeagleBoard. Estos módulos son los que permiten al kernel tener acceso a un determinado hardware, en

este caso el DSP. Lo primero será copiar los tres módulos anteriores en el siguiente directorio de la

plataforma objetivo BeagleBoard /lib/modules/2.6.29/kernel/drivers/dsp/

Para poder resetear el DSP hay que copiar los ejecutables lpmON y lmpOFF en el directorio /usr/bin/ de la

BeagleBoard. Estos se encuentran en los siguientes directorios dentro de local_power_manager_1_23_01:

/packages/ti/bios/power/test/bin/ti_platforms_evm3530/linux/debug/lpmON.x470uC

/packages/ti/bios/power/test/bin/ti_platforms_evm3530/linux/debug/lpmON.x470uC

Para que estos módulos funcionen correctamente es necesario haber añadido previamente en la variable de entorno bootargs “mem=99M@0x80000000 mem=384M@0x88000000”. Esto se puede hacer editando el archivo Env.txt como ya se comentó en el capítulo 3.1.

Ahora sólo falta cargar los módulos mediante el archivo loadmodules.sh. En el caso de usar CMEM habrá que indicarle donde empieza y acaba las regiones de memoria antes a usar por dicho módulo. Estos comandos hay que introducirlos en el script antes de que haga uso del comando insmod cmem.ko:

DSP_REGION_START_ADDR="0x86300000"

DSP_REGION_END_ADDR="0x88000000"

CMEMK_OPTS="phys_start=$DSP_REGION_START_ADDR phys_end=$DSP_REGION_END_ADDR allowOverlap=1"

Tras esto se ejecuta el archivo y mediante el comando lsmod se podrá ver si está cargado correctamente. La ejecución de loadmodules.sh o dicho de otra forma, la carga de los módulos anteriores, será necesaria siempre y cuando se quiera usar el DSP. Existe la posibilidad de que la BeagleBoard cargue los módulos al iniciar añadiendo el script de loadmodules.sh a init.d y usando el comando update-rc.d. Para ver si todo se ha hecho correctamente podemos ejecutar una de las aplicaciones de ejemplo que trae DSPLink, por ejemplo:

# ./messagegpp message.out 1000

========== Sample Application : MESSAGE ==========

Entered MESSAGE_Create ()

Leaving MESSAGE_Create ()

Entered MESSAGE_Execute ()

Transferring 1000 iterations took 0 seconds 161774 microseconds.

RoundTrip Time for 1 message is 161 microseconds.

Leaving MESSAGE_Execute ()

43 Configuración y programación del DSP integrado en la plataforma BeagleBoard-xM

Entered MESSAGE_Delete ()

Leaving MESSAGE_Delete ()

====================================================

4.2 C6Run

C6Run es una herramienta gratuita de desarrollo Open Source ofrecida por Texas Instruments. Esta herramienta permite al usuario utilizar de forma sencilla y sin problemas el DSP de sistemas con núcleos GPP+DSP. C6Run está pensado para sistemas que tengan procesadores ARM Linux y DSP de la familia C6000 como es el caso de la tarjeta que se está usando en este proyecto.

Su principal propósito es facilitar la carga de código en el DSP de forma transparente para el programador, para ello usa las librerías que incluye DSPLink sin necesidad de que el usuario tenga que programar las llamadas y paso de mensajes entre los dos núcleos. Para ello C6Run plantea dos posibles herramientas, C6RunLib y C6RunApp.

4.2.1 C6RunLib

C6RunLib se utiliza para construir una biblioteca que es vinculada a una aplicación ARM para facilitar el acceso al DSP cuando sea necesario, permitiendo al usuario mantener partes de la aplicación en el ARM y otras en el DSP.

Para ello hace uso de dos instrucciones, c6runlib-cc y c6runlib-ar. La primera es un compilador de código C y se usa para crear archivos objetos del DSP. La segunda es un archivador que toma los archivos objetos que crea el compilador y genera una biblioteca. Esta biblioteca es utilizada por la aplicación ARM para proporcionar acceso transparente al DSP a través de las interfaces de la biblioteca. La aplicación se ejecuta desde el núcleo ARM, sin embargo debajo de la aplicación el DSP se inicia, carga el código del programa y espera a llamadas por parte del procesador ARM como se muestra en la figura 4.5.

Figura 4.5 – Esquema de C6RunLib

Comunicación con el DSP

44

4.2.2 C6RunApp

C6RunApp funciona como compilador cruzado para el DSP. Esta herramienta se está formada por una instrucción llamada c6runapp-cc. Esta instrucción compila el código C para generar archivos objetos del DSP y los enlaza con la aplicación. Para hacer esta unión, la herramienta hace uso de una serie de pasos para crear un ejecutable en ARM a partir de los archivos objetos del DSP. Al igual que con C6RunLib, la aplicación se ejecuta desde el ARM pero debajo se realizan todos los procesos necesarios para iniciar y cargar el código en el DSP. Sin embargo, esta vez el código entero se ejecuta en el núcleo del DSP como se observa en la figura 4.6.

Figura 4.6 – Esquema de C6RunApp

4.2.3 Configuración

C6Run es un software desarrollado por Texas Instruments por tanto es lógico pensar que hará uso de las herramientas que antes se utilizaron para la creación del módulo DSPLink. Es por ello que será necesario configurar C6Run indicándole la ubicación de todos los componentes que necesita, estos son un compilador cruzado de ARM, TI C6000 Codegen Tools, DSP/BIOS, DSPLink, XDCtools y Local Power Manager.

Lo primero será descargar la herramienta En el momento que se realizó este proyecto se encontraron dificultades para descargarlo desde la web de Texas Instruments por lo que se empleó el archivo C6Run_m_yoder.tgz que contiene a su vez otro archivo de una versión de C6Run con el nombre de c6run_0_95_02_02_beagleboard.tar.gz

Esta vez habrá que modificar las variables de entorno que usa C6Run. Estas variables están en el archivo environment.sh.

: ${CODEGEN_INSTALL_DIR='/home/javi/ti/TI_CGT_C6000_7.0.4'}

: ${BIOS_INSTALL_DIR='/home/javi/ti/bios_5_41_09_34'}

: ${SYSBIOS_INSTALL_DIR='/home/javi/ti/bios_5_41_09_34'}

: ${ARM_TOOLCHAIN_PATH='/usr/local/angstrom/arm'}

: ${ARM_TOOLCHAIN_PREFIX='arm-angstrom-linux-gnueabi-'}

: ${C6RUN_TOOLCHAIN_PATH='/home/javi/ti/c6run_0_95_02_02_beagleboard'}

Tras hacer los cambios oportunos en enviroment.sh y ejecutar el comando “source environment.sh” ya se podrá usar make en alguno de los ejemplos de C6Run o compilar nuestro propio código C.

45

5 APLICACIÓN DE AUDIO

a idea principal de este capítulo era crear una pequeña aplicación que hiciera uso tanto del DSP como de

las interfaces de audio de entrada y salida que proporciona la tarjeta. Por tanto la aplicación consiste

básicamente en obtener una señal desde la interfaz de audio de entrada, procesarla en el DSP y

devolverla por la interfaz de audio de salida tras el procesado. Para ello se hace uso del código que se

encuentra en [12], el cual realiza gran parte de la tarea que se pretendía salvo el procesado de señal. El código

base empleado utiliza la librería de audio ALSA (Advanced Linux Sound Architecture), ésta simplifica el manejo

de las interfaces de audio que ofrece la BeagleBoard enormemente.

5.1 ALSA

Advanced Linux Sound Architecture (ALSA) consiste en un conjunto de controladores, biblioteca de interfaz de programación de aplicaciones (API) y varios programas de audio de utilidad para facilitar la configuración y manejo de dispositivos de sonido de un sistema Linux. ALSA está licenciado bajo GNU General Public License, siendo desarrollado para sistemas con núcleo Linux y destinado a sustituir a Open Sound System.

La API de ALSA se puede dividir en las principales interfaces:

- Interfaz de control: se trata de una interfaz de propósito general para la gestión de registros de tarjetas de sonido y consulta de los dispositivos disponibles.

- Interfaz de PCM: esta interfaz permite la gestión de la captura de audio digital y la reproducción. Es la interfaz empleada en la aplicación que se ha desarrollado en este proyecto ya que es el más utilizado para aplicaciones de audio digital.

- Interfaz de Raw MIDI: esta interfaz soporta MIDI (Musical Instrument Digital Interface), un estándar para instrumentos de música electrónicos. Esta API proporciona acceso a un bus MIDI en la tarjeta de sonido, trabajando directamente con los eventos MIDI y siendo el programador el encargado de gestionar el protocolo y el tiempo.

- Interfaz Timer: permite el acceso a los temporizadores de las tarjetas de sonido y se utiliza para la sincronización de los eventos de sonido.

- Interfaz Sequencer: se trata de una interfaz para la programación y síntesis de audio MIDI a mayor nivel del que ofrece la interfaz Raw MIDI.

- Interfaz Mixer: controla el acceso al dispositivo que encamina las señales de audio y los niveles de control de volumen.

A continuación se mencionará las principales funciones que ofrece la API que ofrece ALSA para la interfaz PCM. El pseudo-código empleado normalmente por cualquier programa que use esta interfaz es el siguiente:

Abrir interfaz

Configurar los parámetros del hardware (Modo de acceso, formato de datos, canales, frecuencia, etc)

Mientras hay datos para ser procesados:

Leer datos PCM

O escribir datos PCM

Cerrar interfaz

L

Aplicación de Audio

46

Y las principales funciones utilizadas por la interfaz PCM son:

- snd_pcm_open para abrir el dispositivo de reproducción de audio.

- snd_pcm_hw_params_any para obtener los parámetros de configuración de hardware.

- snd_pcm_hw_params_set_access para indicar el orden en el que se entregan los datos.

- snd_pcm_hw_params_set_format para indicar el formato de las muestras de audio.

- snd_pcm_hw_params_set_rate_near para indicar la frecuencia de muestreo.

- snd_pcm_hw_params_set_channels para indicar el número de canales de audio.

- snd_pcm_hw_params para enviar la información de configuración de hardware al driver.

- snd_pcm_prepare para preparar al dispositivo para la reproducción de audio.

- snd_pcm_readi y snd_pcm_writei para leer y enviar las muestras de audio.

- snd_pcm_close para finalizar y cerrar el dispositivo.

Para poder usar ALSA hay que instalar las librerías en el PC HOST necesarias para poder desarrollar la aplicación. Los paquetes software son ALSA-LIB y ALSA-UTILS, éstos se pueden descargar e instalar desde la web alsa-project.org o mediante el comando apt-get install. Recordar que en el código de la aplicación será necesario añadir esta librería mediante la cabecera #include <alsa/asoundlib.h>, y añadir al comando gcc correspondiente –lasound.

Si se quiere usar las aplicaciones de ALSA como aplay o arecord en la BeagleBoard se tendrá que instalar

en dicha plataforma mediante el siguiente comando y teniendo la placa conectada a internet:

opkg install alsa-utils-aplay alsa-utils-amixer

5.2 Código de la aplicación

Como ya se mencionó anteriormente, la aplicación que se ha desarrollado en este proyecto usa como base un código en lenguaje C [12] que se encarga de realizar las principales funciones respecto al manejo de las interfaces de audio con la librería ALSA. Este código se compone de los siguientes ficheros que se muestran en el anexo que acompaña esta memoria:

5.2.1 main.c

Main es el fichero principal de la aplicación y se encarga de:

- Crear un manejador de señales para capturar la señal Ctrl-C (también conocida como SIGINT, señal de interrupción). Cuando se detecta esta señal, la variable global audioEnv.quit cambia a true para indicar al subproceso de audio que salga del bucle principal y comience el desalojo o limpieza.

- Llamar a la función audio_thread_fxn () para entrar en la función de audio.

- Comprobar e informar del éxito o fracaso de la función de audio.

5.2.2 audio_thread.c

Este fichero contiene la función audio_thread_fxn () que se encarga principalmente de ejecutar el código necesario para grabar y reproducir el audio. En el loop principal de la función se ejecuta las diferentes sentencias para generar el audio mientras se espera a la variable global envPtr->quit cambie a true, es decir,

47 Configuración y programación del DSP integrado en la plataforma BeagleBoard-xM

que el usuario pulse Ctrl-C para llamar a la señal de interrupción. Algunas de las funciones usadas en el loop principal son:

- snd_pcm_readi () que se utiliza para leer los datos desde el controlador de entrada de audio ALSA. La i en el nombre de la función significa que los canales izquierdos y derecho se intercalan

- audio_process () que se encarga del procesado de audio.

- snd_pcm_writei () que se utiliza para enviar los datos procesados por el DSP al controlador de salida de audio ALSA. Al igual que snd_pcm_readi () la i indica que los canales izquierdo y derecho de audio se intercalan.

Además en audio_thread_fxn () se utiliza una máscara (initMask) para realizar un seguimiento de

cuántos recursos se han abierto y se inicializa. Cada bit de la máscara corresponde a un recurso.

5.2.3 audio_input_output.c

Este fichero contiene dos funciones que son usadas por la función anterior audio_thread_fxn ():

- audio_io_setup se utiliza para abrir y configurar tanto el controlador de audio de entrada como el de salida y se usa al incio de la función audio_thread_fxn ().

- audio_io_cleanup se utiliza para para cerrar ambos controladores de audio y se usa al final de la función audio_thread_fxn ().

5.2.4 audio_process.c

Este fichero se emplea principalmente para procesar las muestras de audio. El fichero original descargado en [12] consistía en un paso de muestras del búfer de entrada al búfer de salida sin ningún tipo de procesamiento. Por tanto se ha creado un pequeño código en C que implementa un filtro FIR (Respuesta Finita al Impulso) mediante una función de convolución tal y como se muestra en la siguiente ecuación:

( ) ∑ ( ) ( )

Debido a que el DSP de la BeagleBoard-xM no soporta los datos de tipo flotante, los coeficientes del filtro se han guardado en una variable distinta del tipo float. Además se han separado las muestras del canal izquierdo (muestras impares) y derecho (muestras pares) en diferentes variables para procesarlas por separado. Para crear los coeficientes se ha utilizado la función fir1 de Matlab. A continuación se muestra la función audio_process del fichero audio_process.c:

int audio_process(short *outputBuffer, short *inputBuffer, int samples) {

int i, j, k, m =0;

long tmp1, tmp2; // Buffers de 32 bits para la multiplicación de las dos variables de 16 bits

int N = 151; // Número de coeficientes del filtro

// Coeficientes filtro FIR band-pass Fs= 48 KHz t Fcorte1=800Hz Fcorte2=2000Hz

short coeffs [] = { -1 , -1 , 0 , 0 , 0 , -1 , -2 , -3 , -4 , -6 , -7 , -9 , -11 , -13 , -14 , -14 ,

-14 , -12 , -9 , -5 , 0 , 5 , 12 , 18 , 24 , 30 , 34 , 36 , 37 , 36 , 33 , 28 , 22 , 15 , 8 , 3 , -1 , -3 ,

-2 , 3 , 11 , 22 , 35 , 49 , 63 , 74 , 82 , 85 , 80 , 67 , 46 , 15 , -24 , -70 , -121 , -175 , -228 , -277 , -319

, -350 , -367 , -368 , -350 , -315 , -262 , -192 , -108 , -14 , 85 , 185 , 282 , 368 , 442 , 497 , 531 , 543 , 531 ,

497 , 442 , 368 , 282 , 185 , 85 , -14, -108 , -192 , -262 , -315 , -350 , -368 , -367 , -350 , -319 , -277, -228 , -175

, -121 , -70 , -24 , 15 , 46 , 67 , 80 , 85 , 82 , 74 , 63 , 49 , 35 , 22 , 11 , 3 , -2 , -3 , -1 , 3 , 8 ,

15 , 22 , 28 , 33 , 36 , 37 , 36 , 34 , 30 , 24 , 18 , 12 , 5 , 0 , -5 , -9 , -12 , -14 , -14 , -14 , -13 ,

-11 , -9 , -7 , -6 , -4 , -3 , -2 , -1 , 0 , 0 , 0 , -1 , -1 };

Aplicación de Audio

48

// Función de convolucion

for (k = 0; k < samples; k+=2)

{

tmp1 = 0;

tmp2 = 0;

for (i = 0; i < N; i++) // Recorre el vector de coeficientes del filtro

{

j = k - i; // Posición del vector de entrada par

m = k - i + 1 ; // Posición del vector de entrada impar

if ((j >= 0)&&(m>= 0)) // Se asegura que solo se procesen las muestras con j y m >= 0

{

tmp1 += coeffs[i] * inputBuffer[j];

tmp2 += coeffs[i] * inputBuffer[m];

}

}

// Se desplaza 15 posiciones a la derecha para tomar los valores más significativos

outputBuffer[k] = tmp1>>15; // Muestra par --> canal derecho

outputBuffer[k+1] = tmp2>>15; // Muestra impar --> canal izquierdo

}

return 0;

}

5.2.5 Makefile

Este fichero contiene las sentencias necesarias para compilar el programa desde C6Run. El Makefile hará uso de la herramienta C6RunLib, es decir, parte del código se ejecutará en el núcleo ARM y otra parte en el DSP, sin embargo se generarán dos ejecutables, uno donde todo el código se ejecuta en ARM y el otro con parte del código ejecutándose en el DSP. En este caso el código que se ejecutará en el DSP es el que contiene el fichero audio_process.c como se indica en estas líneas extraídas del propio Makefile:

# Lista de archivos que se ejecutarán en el procesador ARM

EXEC_SRCS := main.c audio_input_output.c audio_thread.c

EXEC_ARM_OBJS := $(EXEC_SRCS:%.c=gpp/%.o)

EXEC_DSP_OBJS := $(EXEC_SRCS:%.c=dsp/%.o)

# Lista de archivos que se ejecutarán en el DSP

LIB_SRCS := audio_process.c

LIB_ARM_OBJS := $(LIB_SRCS:%.c=gpp_lib/%.o)

LIB_DSP_OBJS := $(LIB_SRCS:%.c=dsp_lib/%.o)

49 Configuración y programación del DSP integrado en la plataforma BeagleBoard-xM

6 CONCLUSIONES

En este proyecto fin de carrera se ha configurado y programado la placa de desarrollo BeagleBoard-xM. En

concreto se ha trabajado principalmente con el procesador de doble núcleo DM3730 con la intención de

acceder al DSP de la familia C64+ que integra junto con un procesador de propósito general ARM Cortex-A8.

La idea era hacer funcional la placa, desde lo más básico como la alimentación para arrancarla, hasta conseguir

crear una aplicación que se ejecutara en el DSP. Por consiguiente el objetivo principal era crear un manual que

sirviera de referencia para futuros trabajos relacionados con esta placa.

Para ello en un inicio se ha estudiado y analizado las características de este tipo de hardware debido

principalmente a la inexperiencia con la placa BeagleBoard, llegando a instalar distintos sistemas operativos

con el fin de elegir el más adecuado. Más tarde fue necesario identificar los componentes que integra la placa,

en especial su procesador ya que iba a ser el objeto principal de estudio durante el proyecto. Gracias a ello se

identificaron las distintas arquitecturas que integra, así como las herramientas necesarias para compilar

software que pudiera ser ejecutado desde la BeagleBoard-xM.

Tras dar los primeros pasos con el hardware, el siguiente objetivo fue poder acceder al DSP. Se descubrió que

no era trivial y requería de cierta metodología para alcanzar tal propósito. De hecho la obtención de los

módulos DSPLink y CMEM ocupó gran parte del desarrollo de este proyecto. Tras ello, se procedió a

identificar y estudiar las funciones que ofrecía la API de DSPLink con el fin de comenzar con la programación

de una aplicación de audio que procesara las muestras en el DSP para que sirviera de ejemplo. Sin embargo

no fue del todo necesario familiarizarse con la API más allá de lo básico puesto que tiempo después se

descubrió de la existencia de un software capaz de abstraer más aun la comunicación de los núcleos ARM y

DSP llamado C6Run.

C6Run está diseñado con el propósito de evitar que el programador tenga que lidiar con las diferentes

funciones que DSPLink, reduciéndolo a tener que decidir que parte del código se quiere ejecutar en el DSP y

cual en el ARM. También se investigó respecto al audio en la BeagleBoard, para ello se hizo uso de las

aplicaciones que ofrece ALSA para la grabación y reproducción de audio. Una vez identificada la manera de

obtener el audio el siguiente paso fue estudiar cómo utilizar las librerías de ALSA, fue entonces cuando se

obtuvo el código que se encuentra en [12] y que además hacia uso de C6Run. Lo siguiente fue programar en C

un filtro en uno de esos ficheros, con el fin de que el DSP trabajara en el procesamiento de audio mientras el

núcleo ARM se encargaba del resto, como la inicialización de los dispositivos de audio así como de su manejo.

En definitiva durante la realización de este proyecto se ha aprendido los aspectos más importantes de un

sistema embebido de doble núcleo como BeagleBoard-xM, haciendo especial énfasis en todo lo relacionado

con la compilación y programación de aplicaciones a través de las diferentes toolchains y la comunicación entre

dos procesadores tan diferentes como el ARM y el DSP. Es gracias a ellos que la placa de desarrollo

BeagleBoard permite una gran eficiencia en la ejecución de algoritmos en tiempo real a través del DSP

mientras que el procesador de propósito general se encarga de otras tareas.

Debido a que este proyecto se deja como manual para la realización de futuros trabajos en la Escuela Técnica

Superior de Ingenieros, entre los futuros trabajos posibles se encuentran la opción de poder crear el código que

implemente los algoritmos para la detección no invasiva de un electrocardiograma fetal y la posibilidad de

añadirle a la BeagleBoard-xM una pantalla táctil LCD que podría ser usada para mostrar el

electrocardiograma.

Referencias

50

REFERENCIAS

[1] «Using Eclipse to Cross-compile Applications for Embedded Systems,» [En línea]. Available: http://www.lvr.com/eclipse1.htm.

[2] Fundación OPTI; Ministerio de industria, turismo y comercio, «Tendencias y aplicaciones de los Sistemas Embebidos en España,» Madrid, 2009.

[3] R. Martín Clemente y F. Muñoz Chavero, «Plataforma para la evaluación de algoritmos de detección del electrocardiograma fetal,» Sevilla.

[4] Ó. Herranz Alonso, Trabajo fin de Máster: Integracion MPLAYER – OPENSVC en el procesador multinúcleo OMAP3530.

[5] «Beagleboard-xM System Reference Manual,» [En línea]. Available: http://beagleboard.org/static/BBxMSRM_latest.pdf.

[6] «Beagleboard.org,» [En línea]. Available: http://beagleboard.org/.

[7] «Releases Ubuntu 12.01,» [En línea]. Available: http://cdimage.ubuntu.com/releases/12.04.3/release/.

[8] «Angstrom Distribution,» [En línea]. Available: http://www.angstrom-distribution.org/.

[9] «DSPLink Guia de uso,» [En línea]. Available: https://pixhawk.ethz.ch/_media/omap/userguide.pdf.

[10] «DSPLink Guia de Programador,» [En línea]. Available: https://pixhawk.ethz.ch/_media/omap/programmersguide.pdf.

[11] M. A. Yoder, «Using the DSP for Audio Processing,» [En línea]. Available: http://elinux.org/EBC_Exercise_09_Using_the_DSP_for_Audio_Processing.

[12] R. Viedma Ponce, Programación de un sistema Embedded, 2010.

[13] J. Tranter, «Introduction to Sound Programming with ALSA,» [En línea]. Available: http://www.linuxjournal.com/article/6735.

[14] «Setting up DSPLink Framework for GPP DSP Applications,» [En línea]. Available: https://github.com/alfayez/OMAP-DSP-Main-Wiki/wiki/Setting-up-DSPLink-Framework-for-GPP-DSP-Applications.

[15] «Installing DSPLink on a BeagleBoard Outside OpenEmbedded from Source,» [En línea]. Available: http://ossie.wireless.vt.edu/trac/wiki/BeagleBoard_DSPLink.

[16] «Installing Angstrom on BeagleBoard-xM,» [En línea]. Available: http://treyweaver.blogspot.com.es/2010/10/installing-angstrom-on-beagleboard-xm.html.

[17] «CMEM Overview,» [En línea]. Available: http://processors.wiki.ti.com/index.php/CMEM_Overview.

51 Configuración y programación del DSP integrado en la plataforma BeagleBoard-xM

[18] «C6Run Lib,» [En línea]. Available: http://processors.wiki.ti.com/index.php/C6RunLib_Documentation.

[19] «C6Run App,» [En línea]. Available: http://processors.wiki.ti.com/index.php/C6RunApp_Documentation.

[20] «C6Run,» [En línea]. Available: http://processors.wiki.ti.com/index.php/C6Run.

52

ÍNDICE DE FIGURAS

Figura 1.1 – BeagleBoard-xM 15

Figura 2.1 - Logo BeagleBoard.org 18

Figura 2.2 - Comparación entre las diferentes tarjetas de Beagleboard.org 19

Figura 2.3 - Vista superior de la BeagleBoard-xM 20

Figura 2.4 - Encapsulado tipo POP 21

Figura 2.5 - Diagrama de bloques del procesador DM3730 22

Figura 2.6 - Cable USB en Y 23

Figura 3.1 – Comando df –h 26

Figura 3.2 – Pantalla inicial del SO Angstrom. 28

Figura 3.3 – Pantalla del entorno de desarrollo Eclipse 30

Figura 3.4 – Ventana de propiedades de un proyecto creado en Eclipse 31

Figura 4.1 – Arquitectura de DSPLink 33

Figura 4.2 – Escenario de búfer estático 35

Figura 4.3 – Escenario de búfer dinámico 36

Figura 4.4 – Escenario para múltiples búfers 37

Figura 4.5 – Esquema de C6RunLib 43

Figura 4.6 – Esquema de C6RunApp 44

53 Configuración y programación del DSP integrado en la plataforma BeagleBoard-xM

ANEXO: CÓDIGO DEL PROGRAMA

main.c

// Standard Linux headers #include <stdio.h> // Always include this header #include <stdlib.h> // Always include this header #include <signal.h> // Defines signal-handling functions (i.e. trap Ctrl-C) // Application headers #include "debug.h" #include "audio_thread.h" // Global audio thread environment audio_thread_env audio_env = {0}; /* Store previous signal handler and call it */ void (*pSigPrev)(int sig); // Callback called when SIGINT is sent to the process (Ctrl-C) void signal_handler(int sig) { DBG( "Ctrl-C pressed, cleaning up and exiting..\n" ); audio_env.quit = 1; if( pSigPrev != NULL ) (*pSigPrev)( sig ); } //***************************************************************************** //* main //***************************************************************************** int main( int argc, char *argv[] ) { int status = EXIT_SUCCESS; void *audioThreadReturn; // Set the signal callback for Ctrl-C pSigPrev = signal(SIGINT, signal_handler); // Call audio thread function audioThreadReturn = audio_thread_fxn( (void *) &audio_env ); if( audioThreadReturn == AUDIO_THREAD_FAILURE ) { DBG( "Audio thread exited with FAILURE status\n" ); status = EXIT_FAILURE; } else DBG( "Audio thread exited with SUCCESS status\n" );

Anexo: Código del programa

54

exit( status );

}

audio_thread.c

//* Standard Linux headers ** #include <stdio.h> // Always include stdio.h #include <stdlib.h> // Always include stdlib.h #include <alsa/asoundlib.h> // ALSA includes #include <string.h> // For memcpy //* Application headers ** #include "debug.h" // DBG and ERR macros #include "audio_thread.h" // Audio thread definitions #include "audio_input_output.h" // Audio driver input and output functions #include "audio_process.h" // Timing routines #include <time.h> #if defined(_TMS320C6X) // Here's how to test for the DSP #elif defined(__GNUC__) // Test for the ARM #include <sys/time.h> #endif typedef unsigned long long timestamp_t; static timestamp_t get_timestamp () { #if defined(_TMS320C6X) // There is no gettimeofday in DSP RTS or DSP/BIOS return (timestamp_t) clock(); #elif defined(__GNUC__) struct timeval now; gettimeofday (&now, NULL); return now.tv_usec + (timestamp_t)now.tv_sec * 1000000; #endif } //* ALSA devices ** #define IN_SOUND_DEVICE "plughw:0,0" // Use for line in #define OUT_SOUND_DEVICE "plughw:0,0" //* The sample rate of the audio codec ** #define SAMPLE_RATE 48000 //* The gain (0-100) of the left channel ** #define LEFT_GAIN 10 //* The gain (0-100) of the right channel ** #define RIGHT_GAIN 10 //* Parameters for audio thread execution ** #define BLOCKSIZE 48000 //******************************************************************************* //* audio_thread_fxn ** //******************************************************************************* //* Input Parameters: ** //* void *envByRef -- a pointer to an audio_thread_env structure ** //* as defined in audio_thread.h **

55 Configuración y programación del DSP integrado en la plataforma BeagleBoard-xM

//* ** //* envByRef.quit -- when quit != 0, thread will cleanup and exit ** //* ** //* Return Value: ** //* void * -- AUDIO_THREAD_SUCCESS or AUDIO_THREAD_FAILURE as ** //* defined in audio_thread.h ** //******************************************************************************* void *audio_thread_fxn( void *envByRef ) { // Variables and definitions // ************************* // Thread parameters and return value audio_thread_env * envPtr = envByRef; // < see above > void * status = AUDIO_THREAD_SUCCESS; // < see above > // The levels of initialization for initMask #define INPUT_ALSA_INITIALIZED 0x1 #define INPUT_BUFFER_ALLOCATED 0x2 #define OUTPUT_ALSA_INITIALIZED 0x4 #define OUTPUT_BUFFER_ALLOCATED 0x8 unsigned int initMask = 0x0; // Used to only cleanup items that were init'd // Input and output driver variables snd_pcm_uframes_t exact_bufsize; snd_pcm_t *pcm_capture_handle, *pcm_output_handle; int blksize = BLOCKSIZE; // Raw input or output frame size char *inputBuffer = NULL; // Input buffer for driver to read into char *outputBuffer = NULL; // Output buffer for driver to read from // Thread Create Phase -- secure and initialize resources // ****************************************************** // Setup audio input device // ************************ // Open an ALSA device channel for audio input exact_bufsize = blksize/BYTESPERFRAME; if( audio_io_setup( &pcm_capture_handle, IN_SOUND_DEVICE, SAMPLE_RATE, SND_PCM_STREAM_CAPTURE, &exact_bufsize ) == AUDIO_FAILURE ) { ERR( "Audio_input_setup failed in audio_thread_fxn\n\n" ); status = AUDIO_THREAD_FAILURE; goto cleanup; } DBG( "exact_bufsize = %d \n", (int) exact_bufsize); // Record that input OSS device was opened in initialization bitmask initMask |= INPUT_ALSA_INITIALIZED; blksize = exact_bufsize*BYTESPERFRAME; // Create input buffer to read into from ALSA input device if( ( inputBuffer = malloc( blksize ) ) == NULL ) { ERR( "Failed to allocate memory for input block (%d)\n", blksize ); status = AUDIO_THREAD_FAILURE; goto cleanup ; }

Anexo: Código del programa

56

DBG( "Allocated input audio buffer of size %d to address %p\n", blksize, inputBuffer ); // Record that the input buffer was allocated in initialization bitmask initMask |= INPUT_BUFFER_ALLOCATED; // Create output buffer to write from into ALSA output device if( ( outputBuffer = malloc( blksize ) ) == NULL ) { ERR( "Failed to allocate memory for output block (%d)\n", blksize ); status = AUDIO_THREAD_FAILURE; goto cleanup ; } DBG( "Allocated output audio buffer of size %d to address %p\n", blksize, outputBuffer ); // Record that the output buffer was allocated in initialization bitmask initMask |= OUTPUT_BUFFER_ALLOCATED; // Initialize audio output device // ****************************** // Initialize the output ALSA device DBG( "pcm_output_handle before audio_output_setup = %d\n", (int) pcm_output_handle); DBG( "Requesting bufsize = %d\n", (int) exact_bufsize); if( audio_io_setup( &pcm_output_handle, OUT_SOUND_DEVICE, SAMPLE_RATE, SND_PCM_STREAM_PLAYBACK, &exact_bufsize) == AUDIO_FAILURE ) { ERR( "audio_output_setup failed in audio_thread_fxn\n" ); status = AUDIO_THREAD_FAILURE; goto cleanup ; } DBG( "pcm_output_handle after audio_output_setup = %d\n", (int) pcm_output_handle); DBG( "blksize = %d, exact_bufsize = %d\n", blksize, (int) exact_bufsize); // Record that input ALSA device was opened in initialization bitmask initMask |= OUTPUT_ALSA_INITIALIZED; // Thread Execute Phase -- perform I/O and processing // ************************************************** int err; int errcnt =0; timestamp_t t_start, t_read, t_proc, t_write, t_old=0; // Processing loop // Do a dummy call to the DSP to get it started. This takes a while on the first call // so we don't want to do it after starting the audio or a buffer will underflow. memset(outputBuffer, 0, blksize); // Clear the buffer printf( "Starting DSP..." ); t_start = get_timestamp(); // Do the dummy call audio_process((short *)outputBuffer, (short *)outputBuffer, blksize/2); t_proc = get_timestamp();

57 Configuración y programación del DSP integrado en la plataforma BeagleBoard-xM

printf("%f s\n", (t_proc-t_start)/1000000.0); DBG( "Entering audio_thread_fxn processing loop...\n" ); // Get things started by sending some silent buffers out. while( snd_pcm_readi(pcm_capture_handle, inputBuffer, exact_bufsize) < 0 ) { snd_pcm_prepare(pcm_capture_handle); ERR( "<<<<<<<<<<<<<<< Buffer Prime Overrun >>>>>>>>>>>>>>>\n"); ERR( "Error reading the data from file descriptor %d\n", (int) pcm_capture_handle ); } int i; memset(outputBuffer, 0, blksize); // Clear the buffer for(i=0; i<2; i++) { while ((err = snd_pcm_writei(pcm_output_handle, outputBuffer, exact_bufsize)) < 0) { snd_pcm_prepare(pcm_output_handle); ERR( "<<<Pre Buffer Underrun >>> err=%d, errcnt=%d\n", err, errcnt); } } // // The main loop // while( !envPtr->quit ) { // Read capture buffer from ALSA input device t_start = get_timestamp(); while( snd_pcm_readi(pcm_capture_handle, inputBuffer, exact_bufsize) < 0 ) { snd_pcm_prepare(pcm_capture_handle); ERR( "<<<<<<<<<<<<<<< Buffer Overrun >>>>>>>>>>>>>>>\n"); ERR( "Error reading the data from file descriptor %d\n", (int) pcm_capture_handle ); } t_read = get_timestamp(); // Audio process // I'm passing the data as short since we are processing 16-bit audio. // memcpy(outputBuffer, inputBuffer, blksize); audio_process((short *)outputBuffer, (short *)inputBuffer, blksize/2); t_proc = get_timestamp(); // Write output buffer into ALSA output device errcnt = 0; // The Beagle gets an underrun error the first time it trys to write, // so I ignore the first error and it appears to work fine. while ((err = snd_pcm_writei(pcm_output_handle, outputBuffer, exact_bufsize)) < 0) { snd_pcm_prepare(pcm_output_handle); ERR( "<<<<<<<<<<<<<<< Buffer Underrun >>>>>>>>>>>>>>> err=%d, errcnt=%d\n", err, errcnt); memset(outputBuffer, 0, blksize); // Clear the buffer snd_pcm_writei(pcm_output_handle, outputBuffer, exact_bufsize); } t_write= get_timestamp(); // DBG( "%d\t%d\t%d\t%d\n", t_start-t_old, t_read-t_start, t_proc-t_read, t_write-t_proc); t_old = t_start; } DBG( "Exited audio_thread_fxn processing loop\n" );

Anexo: Código del programa

58

// Thread Delete Phase -- free up resources allocated by this file // *************************************************************** cleanup: DBG( "Starting audio thread cleanup to return resources to system\n" ); // Close the audio drivers // *********************** // - Uses the initMask to only free resources that were allocated. // - Nothing to be done for mixer device, as it was closed after init. // Close input ALSA device if( initMask & INPUT_ALSA_INITIALIZED ) if( audio_io_cleanup( pcm_capture_handle ) != AUDIO_SUCCESS ) { ERR( "audio_input_cleanup() failed for file descriptor %d\n", (int) pcm_capture_handle ); status = AUDIO_THREAD_FAILURE; } // Close output ALSA device if( initMask & OUTPUT_ALSA_INITIALIZED ) if( audio_io_cleanup( pcm_output_handle ) != AUDIO_SUCCESS ) { ERR( "audio_output_cleanup() failed for file descriptor %d\n", (int)pcm_output_handle ); status = AUDIO_THREAD_FAILURE; } // Free allocated buffers // ********************** // Free input buffer if( initMask & INPUT_BUFFER_ALLOCATED ) { DBG( "Freeing audio input buffer at location %p\n", inputBuffer ); free( inputBuffer ); DBG( "Freed audio input buffer at location %p\n", inputBuffer ); } // Free output buffer if( initMask & OUTPUT_BUFFER_ALLOCATED ) { free( outputBuffer ); DBG( "Freed audio output buffer at location %p\n", outputBuffer ); } // Return from audio_thread_fxn function // ************************************* // Return the status at exit of the thread's execution DBG( "Audio thread cleanup complete. Exiting audio_thread_fxn\n" ); return status;

}

59 Configuración y programación del DSP integrado en la plataforma BeagleBoard-xM

audio_input_output.c

// Modfied for ALSA input/output 6-May-2011, Mark A. Yoder // Based on Basic PCM audio (http://www.suse.de/~mana/alsa090_howto.html#sect02)http://www.suse.de/~mana/alsa090_howto.html#sect03 //* Standard Linux headers ** #include <stdio.h> // Always include stdio.h #include <stdlib.h> // Always include stdlib.h #include <alsa/asoundlib.h> // ALSA includes //* Application headers ** #include "audio_input_output.h" // Audio i/o methods and types #include "debug.h" // Defines debug routines //******************************************************************************* //* audio_io_setup //******************************************************************************* //* Input parameters: ** //* snd_pcm_t **pcm_handle-- A pointer to a point to the ALSA device. ** //* char *soundDevice -- string value for ALSA driver device node, ** //* such as "plughw:0,0" ** //* int samplerate -- sample rate in Hertz, i.e. 44100 ** //* snd_pcm_stream_t stream-- Either SND_PCM_STREAM_CAPTURE to record or ** //* SND_PCM_STREAM_PLAYBACK to playback ** //* snd_pcm_uframes_t *exact_bufsize_handle ** //* -- Pointer to the desired buffersize. The value ** //* is updated to the size that was granted. ** //* ** //* Return value: ** //* int -- AUDIO_SUCCESS or AUDIO_FAILURE as per audio_input_output.h ** //* ** //******************************************************************************* int audio_io_setup(snd_pcm_t **pcm_handle, char *soundDevice, int sampleRate, snd_pcm_stream_t stream, snd_pcm_uframes_t *exact_bufsize_handle ) { /* This structure contains information about */ /* the hardware and can be used to specify the */ /* configuration to be used for the PCM stream. */ snd_pcm_hw_params_t *hwparams; /* The most important ALSA interfaces to the PCM devices are the "plughw" and the "hw" interface. If you use the "plughw" interface, you need not care much about the sound hardware. If your soundcard does not support the sample rate or sample format you specify, your data will be automatically converted. This also applies to the access type and the number of channels. With the "hw" interface, you have to check whether your hardware supports the configuration you would like to use. */ /* Name of the PCM device, like plughw:0,0 */ /* The first number is the number of the soundcard, */ /* the second number is the number of the device. */ char *pcm_name; // Then we initialize the variables and allocate a hwparams structure: /* Init pcm_name. Of course, later you */ /* will make this configurable ;-) */ pcm_name = strdup(soundDevice); /* Allocate the snd_pcm_hw_params_t structure on the stack. */

Anexo: Código del programa

60

snd_pcm_hw_params_alloca(&hwparams); // Now we can open the PCM device: /* Open PCM. The last parameter of this function is the mode. */ /* If this is set to 0, the standard mode is used. Possible */ /* other values are SND_PCM_NONBLOCK and SND_PCM_ASYNC. */ /* If SND_PCM_NONBLOCK is used, read / write access to the */ /* PCM device will return immediately. If SND_PCM_ASYNC is */ /* specified, SIGIO will be emitted whenever a period has */ /* been completely processed by the soundcard. */ DBG( "pcm_handle before snd_pcm_open = %d\n", (int) pcm_handle); if (snd_pcm_open(pcm_handle, pcm_name, stream, 0) < 0) { ERR( "Error opening PCM device %s\n", pcm_name); return AUDIO_FAILURE; } DBG( "pcm_handle after snd_pcm_open = %d\n", (int) pcm_handle); /* Before we can write PCM data to the soundcard, we have to specify access type, sample format, sample rate, number of channels, number of periods and period size. First, we initialize the hwparams structure with the full configuration space of the soundcard. */ /* Init hwparams with full configuration space */ if (snd_pcm_hw_params_any(*pcm_handle, hwparams) < 0) { ERR( "Cannot configure this PCM device.\n"); return AUDIO_FAILURE; } /* Information about possible configurations can be obtained with a set of functions named snd_pcm_hw_params_can_<capability> snd_pcm_hw_params_is_<property> snd_pcm_hw_params_get_<parameter> The availability of the most important parameters, namely access type, buffer size, number of channels, sample format, sample rate and number of periods, can be tested with a set of functions named snd_pcm_hw_params_test_<parameter> These query functions are especially important if the "hw" interface is used. The configuration space can be restricted to a certain configuration with a set of functions named snd_pcm_hw_params_set_<parameter> For this example, we assume that the soundcard can be configured for stereo playback of 16 Bit Little Endian data, sampled at 44100 Hz. Accordingly, we restrict the configuration space to match this configuration: */ int rate = sampleRate; /* Sample rate */ unsigned int exact_rate; /* Sample rate returned by */ /* snd_pcm_hw_params_set_rate_near */ // int dir; /* exact_rate == rate --> dir = 0 */ /* exact_rate < rate --> dir = -1 */ /* exact_rate > rate --> dir = 1 */ int periods = 4; /* Number of periods, See http://www.alsa-project.org/main/index.php/FramesPeriods */ // snd_pcm_uframes_t periodsize = 44100; /* Periodsize (bytes) */

61 Configuración y programación del DSP integrado en la plataforma BeagleBoard-xM

/* A frame is equivalent of one sample being played, irrespective of the number of channels or the number of bits. e.g. 1 frame of a Stereo 48khz 16bit PCM stream is 4 bytes. 1 frame of a 5.1 48khz 16bit PCM stream is 12 bytes. A period is the number of frames in between each hardware interrupt. The poll() will return once a period. The buffer is a ring buffer. The buffer size always has to be greater than one period size. Commonly this is 2*period size, but some hardware can do 8 periods per buffer. It is also possible for the buffer size to not be an integer multiple of the period size. Now, if the hardware has been set to 48000Hz , 2 periods, of 1024 frames each, making a buffer size of 2048 frames. The hardware will interrupt 2 times per buffer. ALSA will endeavor to keep the buffer as full as possible. Once the first period of samples has been played, the third period of samples is transfered into the space the first one occupied while the second period of samples is being played. (normal ring buffer behaviour). */ /* The access type specifies the way in which multichannel data is stored in the buffer. For INTERLEAVED access, each frame in the buffer contains the consecutive sample data for the channels. For 16 Bit stereo data, this means that the buffer contains alternating words of sample data for the left and right channel. For NONINTERLEAVED access, each period contains first all sample data for the first channel followed by the sample data for the second channel and so on. */ /* Set access type. This can be either */ /* SND_PCM_ACCESS_RW_INTERLEAVED or */ /* SND_PCM_ACCESS_RW_NONINTERLEAVED. */ /* There are also access types for MMAPed */ /* access, but this is beyond the scope */ /* of this introduction. */ if (snd_pcm_hw_params_set_access(*pcm_handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED) < 0) { ERR( "Error setting access.\n"); return AUDIO_FAILURE; } /* Set sample format */ if (snd_pcm_hw_params_set_format(*pcm_handle, hwparams, SND_PCM_FORMAT_S16_LE) < 0) { ERR( "Error setting format.\n"); return AUDIO_FAILURE; } /* Set sample rate. If the exact rate is not supported */ /* by the hardware, use nearest possible rate. */ exact_rate = rate; if (snd_pcm_hw_params_set_rate_near(*pcm_handle, hwparams, &exact_rate, 0u) < 0) { ERR( "Error setting rate.\n"); return AUDIO_FAILURE; } if (rate != exact_rate) { DBG( "The rate %d Hz is not supported by your hardware.\nUsing %d Hz instead.\n", rate, exact_rate); } else { DBG( "Using %d Hz sampling rate.\n", rate); }

Anexo: Código del programa

62

/* Set number of channels */ if (snd_pcm_hw_params_set_channels(*pcm_handle, hwparams, NUM_CHANNELS) < 0) { ERR( "Error setting channels.\n"); return AUDIO_FAILURE; } /* Set number of periods. Periods used to be called fragments. */ if (snd_pcm_hw_params_set_periods(*pcm_handle, hwparams, periods, 0) < 0) { ERR( "Error setting periods.\n"); return AUDIO_FAILURE; } /* The unit of the buffersize depends on the function. Sometimes it is given in bytes, sometimes the number of frames has to be specified. One frame is the sample data vector for all channels. For 16 Bit stereo data, one frame has a length of four bytes. */ /* Set buffer size (in frames). The resulting latency is given by */ /* latency = periodsize * periods / (rate * bytes_per_frame) */ // *exact_bufsize_handle = (periodsize * periods) >> 2; if (snd_pcm_hw_params_set_buffer_size_near(*pcm_handle, hwparams, exact_bufsize_handle) < 0) { ERR( "Error setting buffersize.\n"); return AUDIO_FAILURE; } DBG( "exact_bufsize = %d\n", (int) *exact_bufsize_handle); /* If your hardware does not support a buffersize of 2^n, you can use the function snd_pcm_hw_params_set_buffer_size_near. This works similar to snd_pcm_hw_params_set_rate_near. Now we apply the configuration to the PCM device pointed to by pcm_handle. This will also prepare the PCM device. */ /* Apply HW parameter settings to */ /* PCM device and prepare device */ if (snd_pcm_hw_params(*pcm_handle, hwparams) < 0) { ERR( "Error setting HW params.\n"); return AUDIO_FAILURE; } //* Return status ** DBG( "Opened %s\n", soundDevice); return AUDIO_SUCCESS; } //******************************************************************************* //* audio_io_cleanup //******************************************************************************* //* Input parameters: ** //* snd_pcm_t *pcm_handle -- Handle of ALSA device to be closed. ** //* ** //* Return value: ** //* int -- AUDIO_SUCCESS or AUDIO_FAILURE as per audio_input_output.h ** //* ** //******************************************************************************* int audio_io_cleanup(snd_pcm_t *pcm_handle) { /* If we want to stop playback, we can either use snd_pcm_drop or snd_pcm_drain. The first function will immediately stop the playback and drop pending frames. The latter function will stop after pending frames have been played.

63 Configuración y programación del DSP integrado en la plataforma BeagleBoard-xM

*/ /* Stop PCM device and drop pending frames */ // snd_pcm_drop(pcm_handle); /* Stop PCM device after pending frames have been played */ if(snd_pcm_drain(pcm_handle) != 0) { ERR( "Failed close on ALSA audio output device (file descriptor %d) \n", (int) pcm_handle ); return AUDIO_FAILURE; } DBG( "Closed audio output device (file descriptor %d)\n", (int) pcm_handle ); return AUDIO_SUCCESS;

}

Anexo: Código del programa

64

audio_process.c

//* Standard Linux headers **

#include <stdio.h> // Always include stdio.h

#include <stdlib.h> // Always include stdlib.h

#include <string.h> // Defines memcpy

//* Application headers **

#if defined(_TMS320C6X) // Here's how to test for the DSP

#elif defined(__GNUC__) // Test for the ARM

#include "debug.h" // DBG and ERR macros

#endif

#include "audio_process.h"

// Here's where we processing the audio

// Format is left and right interleaved.

int audio_process(short *outputBuffer, short *inputBuffer, int samples) {

int i, j, k, m =0;

long tmp1, tmp2; // Buffers de 32 bits para la multiplicación de las dos variables de 16 bits

int N = 151; // Número de coeficientes del filtro

// Coeficientes filtro FIR band-pass Fs= 48 KHz t Fcorte1=800Hz Fcorte2=2000Hz

short coeffs [] = { -1 , -1 , 0 , 0 , 0 , -1 , -2 , -3 , -4 , -6 , -7 , -9 , -11 , -13 , -14 , -14 ,

-14 , -12 , -9 , -5 , 0 , 5 , 12 , 18 , 24 , 30 , 34 , 36 , 37 , 36 , 33 , 28 , 22 , 15 , 8 , 3 , -1 , -3 ,

-2 , 3 , 11 , 22 , 35 , 49 , 63 , 74 , 82 , 85 , 80 , 67 , 46 , 15 , -24 , -70 , -121 , -175 , -228 , -277 , -319

, -350 , -367 , -368 , -350 , -315 , -262 , -192 , -108 , -14 , 85 , 185 , 282 , 368 , 442 , 497 , 531 , 543 , 531 ,

497 , 442 , 368 , 282 , 185 , 85 , -14, -108 , -192 , -262 , -315 , -350 , -368 , -367 , -350 , -319 , -277, -228 , -175

, -121 , -70 , -24 , 15 , 46 , 67 , 80 , 85 , 82 , 74 , 63 , 49 , 35 , 22 , 11 , 3 , -2 , -3 , -1 , 3 , 8 ,

15 , 22 , 28 , 33 , 36 , 37 , 36 , 34 , 30 , 24 , 18 , 12 , 5 , 0 , -5 , -9 , -12 , -14 , -14 , -14 , -13 ,

-11 , -9 , -7 , -6 , -4 , -3 , -2 , -1 , 0 , 0 , 0 , -1 , -1 };

// Función de convolucion

for (k = 0; k < samples; k+=2)

{

tmp1 = 0;

tmp2 = 0;

for (i = 0; i < N; i++) // Recorre el vector de coeficientes del filtro

{

j = k - i; // Posición del vector de entrada par

m = k - i + 1 ; // Posición del vector de entrada impar

if ((j >= 0)&&(m>= 0)) // Se asegura que solo se procesen las muestras de entrada con j y m >=0

{

tmp1 += coeffs[i] * inputBuffer[j];

tmp2 += coeffs[i] * inputBuffer[m];

}

}

// Se desplazan 15 posiciones a la derecha para tomar los valores más significativos

outputBuffer[k] = tmp1>>15; // Muestra par --> canal derecho

outputBuffer[k+1] = tmp2>>15; // Muestra impar --> canal izquierdo

}

return 0;

}

65 Configuración y programación del DSP integrado en la plataforma BeagleBoard-xM

Makefile

############################################################################# # Makefile # # # # Builds the audio thru source for ARM and DSP # ############################################################################# # # ############################################################################# # # # Copyright (C) 2010 Texas Instruments Incorporated # # http://www.ti.com/ # # # ############################################################################# # # ############################################################################# # # # Redistribution and use in source and binary forms, with or without # # modification, are permitted provided that the following conditions # # are met: # # # # Redistributions of source code must retain the above copyright # # notice, this list of conditions and the following disclaimer. # # # # Redistributions in binary form must reproduce the above copyright # # notice, this list of conditions and the following disclaimer in the # # documentation and/or other materials provided with the # # distribution. # # # # Neither the name of Texas Instruments Incorporated nor the names of # # its contributors may be used to endorse or promote products derived # # from this software without specific prior written permission. # # # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR # # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT # # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, # # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT # # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, # # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY # # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # # # ############################################################################# # ---------------------------------------------------------------------------- # Name of the ARM GCC cross compiler & archiver # ---------------------------------------------------------------------------- ARM_TOOLCHAIN_PREFIX ?= arm-angstrom-linux-gnueabi- ifdef ARM_TOOLCHAIN_PATH ARM_CC := $(ARM_TOOLCHAIN_PATH)/bin/$(ARM_TOOLCHAIN_PREFIX)gcc ARM_AR := $(ARM_TOOLCHAIN_PATH)/bin/$(ARM_TOOLCHAIN_PREFIX)ar else ARM_CC := $(ARM_TOOLCHAIN_PREFIX)gcc ARM_AR := $(ARM_CROSS_COMPILE)ar endif # Get any compiler flags from the environmentre

Anexo: Código del programa

66

ARM_CFLAGS = $(CFLAGS) ARM_CFLAGS += -std=gnu99 \ -Wdeclaration-after-statement -Wall -Wno-trigraphs \ -fno-strict-aliasing -fno-common -fno-omit-frame-pointer \ -D_DEBUG_ \ -c -O3 ARM_LDFLAGS = $(LDFLAGS) ARM_LDFLAGS+=-lm -lpthread -lasound ARM_ARFLAGS = rcs # ---------------------------------------------------------------------------- # Name of the DSP C6RUN compiler & archiver # TI C6RunLib Frontend (if path variable provided, use it, otherwise assume # the tools are in the path) # ---------------------------------------------------------------------------- C6RUN_TOOLCHAIN_PREFIX=c6runlib- ifdef C6RUN_TOOLCHAIN_PATH C6RUN_CC := $(C6RUN_TOOLCHAIN_PATH)/bin/$(C6RUN_TOOLCHAIN_PREFIX)cc C6RUN_AR := $(C6RUN_TOOLCHAIN_PATH)/bin/$(C6RUN_TOOLCHAIN_PREFIX)ar else C6RUN_CC := $(C6RUN_TOOLCHAIN_PREFIX)cc C6RUN_AR := $(C6RUN_TOOLCHAIN_PREFIX)ar endif C6RUN_CFLAGS = -c -O3 -D_DEBUG_ C6RUN_ARFLAGS = rcs --C6Run:replace_malloc # ---------------------------------------------------------------------------- # List of source files # ---------------------------------------------------------------------------- # List the files to run on the ARM here EXEC_SRCS := main.c audio_input_output.c audio_thread.c EXEC_ARM_OBJS := $(EXEC_SRCS:%.c=gpp/%.o) EXEC_DSP_OBJS := $(EXEC_SRCS:%.c=dsp/%.o) # List the files to run on the DSP here LIB_SRCS := audio_process.c LIB_ARM_OBJS := $(LIB_SRCS:%.c=gpp_lib/%.o) LIB_DSP_OBJS := $(LIB_SRCS:%.c=dsp_lib/%.o) # ---------------------------------------------------------------------------- # Makefile targets # ---------------------------------------------------------------------------- .PHONY : dsp_exec gpp_exec dsp_lib gpp_lib dsp_clean gpp_clean all clean all: gpp_exec dsp_exec clean: gpp_clean dsp_clean # ---------------------------------------------------------------------------- # Rules for build and ARM (gpp) only target # ---------------------------------------------------------------------------- gpp_exec: gpp/.created gpp_lib $(EXEC_ARM_OBJS) $(ARM_CC) $(ARM_LDFLAGS) $(CINCLUDES) -o audioThru_arm $(EXEC_ARM_OBJS) \ audioThru_arm.lib gpp_lib: gpp_lib/.created $(LIB_ARM_OBJS) $(ARM_AR) $(ARM_ARFLAGS) audioThru_arm.lib $(LIB_ARM_OBJS) gpp/%.o : %.c $(ARM_CC) $(ARM_CFLAGS) $(CINCLUDES) -o $@ $< gpp_lib/%.o : %.c

67 Configuración y programación del DSP integrado en la plataforma BeagleBoard-xM

$(ARM_CC) $(ARM_CFLAGS) $(CINCLUDES) -o $@ $< gpp/.created: @mkdir -p gpp @touch gpp/.created gpp_lib/.created: @mkdir -p gpp_lib @touch gpp_lib/.created gpp_clean: @rm -Rf audioThru_arm audioThru_arm.lib @rm -Rf gpp gpp_lib # ---------------------------------------------------------------------------- # Rules for build and ARM/DSP (dsp) target # ---------------------------------------------------------------------------- dsp_exec: dsp/.created dsp_lib $(EXEC_DSP_OBJS) $(ARM_CC) $(ARM_LDFLAGS) $(CINCLUDES) -o audioThru_dsp $(EXEC_DSP_OBJS) \ audioThru_dsp.lib @echo "==================" @echo "Built for:" @echo " ARM: $(EXEC_SRCS)" @echo " DSP: $(LIB_SRCS)" @echo "==================" dsp_lib: dsp_lib/.created $(LIB_DSP_OBJS) $(C6RUN_AR) $(C6RUN_ARFLAGS) audioThru_dsp.lib $(LIB_DSP_OBJS) dsp/%.o : %.c $(ARM_CC) $(ARM_CFLAGS) $(CINCLUDES) -o $@ $< dsp_lib/%.o : %.c $(C6RUN_CC) $(C6RUN_CFLAGS) $(CINCLUDES) -o $@ $< dsp/.created: @mkdir -p dsp @touch dsp/.created dsp_lib/.created: @mkdir -p dsp_lib @touch dsp_lib/.created dsp_clean: @rm -Rf audioThru_dsp audioThru_dsp.lib @rm -Rf dsp dsp_lib install: scp audioThru_arm audioThru_dsp root@beagle4:AudioThru/lab06d_audio_c6run/. # ***************************************************************************** # # Additional Debug Information # # ***************************************************************************** # Prints out build & variable definitions # ---------------------------------------- # - While not exhaustive, these commands print out a number of # variables created by gMake, or within this script # - Can be useful information when debugging script errors # - As described in the 2nd warning below, set DUMP=1 on the command # line to have this debug info printed out for you # - The $(warning ) gMake function is used for this rule; this allows

Anexo: Código del programa

68

# almost anything to be printed out - in our case, variables # --------------------------------------------------------------------- ifdef DUMP # $(warning To view build commands, invoke make with argument 'AT= ') $(warning To view build variables, invoke make with 'DUMP=1') $(warning ARM_CC: $(ARM_CC)) $(warning ARM_AR: $(ARM_AR)) $(warning ARM_CFLAGS: $(ARM_CFLAGS)) $(warning ARM_LDFLAGS: $(ARM_LDFLAGS)) $(warning ARM_ARFLAGS: $(ARM_ARFLAGS)) $(warning C6RUN_CC: $(C6RUN_CC)) $(warning C6RUN_AR: $(C6RUN_AR)) $(warning C6RUN_CFLAGS: $(C6RUN_CFLAGS)) $(warning C6RUN_ARFLAGS: $(C6RUN_ARFLAGS)) $(warning EXEC_DSP_OBJS: $(EXEC_DSP_OBJS))

endif