Sie sind auf Seite 1von 13

Instituto Politécnico Nacional

Unidad Profesional Interdisciplinaria En Ingeniería


Y Tecnologías Avanzadas
Dispositivos Programables
M. en C. Juan Manuel Madrigal Bravo
PRÁCTICA 5:
Uso de la memoria externa con punteros para grabar
voz

Equipo 4
Integrantes:

Maza Hernández Sara


Medina González Aline

4TM1
UNIDAD PROFESIONAL INTERDISCIPLINARIA EN INGENIERIA
Y TECNOLGIAS AVANZADAS – IPN
PROCESADORES DIGITALES DE SEÑALES
Práctica No. 5
Uso de la memoria externa con punteros para grabar voz
Profr. M. en C. Juan Manuel Madrigal Bravo

Objetivo: Almacenamiento de datos en la memoria externa del DSP usando punteros.


ANTECEDENTES
Punteros en c
Un puntero es una variable que contiene como valor una dirección de memoria. Dicha dirección
corresponde a la dirección que ocupa otra variable en memoria. Se dice entonces que el puntero apunta
a dicha variable. La variable apuntada puede ser de cualquier tipo elemental, estructurado o incluso otro
puntero. Inicialmente un puntero no apunta a ningún sitio. En C el valor NULL se reserva para indicar que
el puntero está vacío.
Los punteros constituyen una parte fundamental del lenguaje C y son básicos para comprender toda la
potencia y flexibilidad que ofrece el lenguaje. Son especialmente importantes en la programación a bajo
nivel, donde se manipula directamente la memoria del ordenador. Algunas de las ventajas que aporta el
uso de punteros en C son:
 Constituyen la única forma de expresar algunas operaciones.
 Su uso produce código compacto y eficiente.
 Son imprescindibles para el paso de parámetros por referencia a funciones.
 Tienen una fuerte relación con el manejo eficiente de tablas y estructuras.
 Permiten realizar operaciones de asignación dinámica de memoria y manipular estructuras de
datos dinámicas.
Mapa de memoria del TMS320C6713
El DSK provee un mapa de memoria al cual puede acceder el DSP a través de las unidades .D1 y .D2. La figura
siguiente ilustra tal mapa.

1
UNIDAD PROFESIONAL INTERDISCIPLINARIA EN INGENIERIA
Y TECNOLGIAS AVANZADAS – IPN
PROCESADORES DIGITALES DE SEÑALES
Práctica No. 5
Uso de la memoria externa con punteros para grabar voz
Profr. M. en C. Juan Manuel Madrigal Bravo

Recordemos que el C6713 consiste en cuatro partes principales:


o El núcleo (C67x DSP Core).
o La memoria cache L1 formada por dos bancos.
o 4 kBytes de memoria para programa (L1P cache).
o 4 kBytes de memoria de datos (L1D cache).
o La memoria cache L2 de 256KBytes para código y datos y dividida en dos bancos para permitir
dos lecturas o dos escrituras o lectura-escritura a la vez.
o Un banco de 192KBytes: típicamente usada
para código.
o Otro banco de 64KBytes: típicamente
usada para datos.
o Periféricos.
o EMIF.
o McASP.
o McBSP.
o I2C.
o GPIO.

Las ocho unidades operativas o ALU son denominadas con mnemónicos que denotan su función
principal, es decir: .L1, .S1, .M1, .D1 y .L2, .S2, .M2, .D2

Cada unidad operativa tiene dos registros de entrada en donde se copian los operandos y un registro
de salida en donde se almacena el resultado tal como muestra la figura de la derecha
Hay cuatro unidades operativas (.L1, .S1, .M1, .D1) o ALU que toman sus operandos en el banco de
registros A.

La ruta de datos consta de los elementos siguientes:

• Registros: Hay dos bancos de registros. El banco A y el banco B descritos


anteriormente.
• Unidades operativas: Cuatro unidades operativas (.L1, .S1, .M1, .D1) conectadas al
banco A de registros y cuatro unidades operativas (.L2, .S2, .M2, .D2) conectadas al
banco B de registros.
• Los buses
• Hay dos caminos de direccionamiento de datos DA1 (Data Address1) y DA2 (Data
Address2) que llevan direcciones en memoria de datos.
• Hay dos caminos de lectura de datos desde memoria (LD1) y (LD2) controlados por
las unidades .D1 y .D2 respectivamente.
• Hay dos caminos de escritura de datos a memoria (ST1 y ST2) controlados por las
unidades .D1 y .D2 respectivamente.
• Mediante los caminos 1X y 2X, las unidades operativas pueden tomar y operar sobre
los registros del banco opuesto.

2
UNIDAD PROFESIONAL INTERDISCIPLINARIA EN INGENIERIA
Y TECNOLGIAS AVANZADAS – IPN
PROCESADORES DIGITALES DE SEÑALES
Práctica No. 5
Uso de la memoria externa con punteros para grabar voz
Profr. M. en C. Juan Manuel Madrigal Bravo

L1

o Realiza operaciones lógicas.


o Realiza operaciones aritméticas (suma y resta) en punto fijo.
o Realiza operaciones aritméticas (suma y resta) en punto flotante.

S1

o Realiza operaciones de manipulación de bits.


o Realiza operaciones de corrimiento de bits.
o Realiza operaciones de salto.
o Generación de constantes.
o Realiza operaciones aritméticas (suma y resta) en punto fijo.
o Realiza operaciones aritméticas (suma y resta) en punto flotante.

D1

o Realiza operaciones de lectura de datos (load).


o Realiza operaciones de escritura de datos (store).
o Realiza operaciones aritméticas (suma y resta) en punto fijo.

M1

o Realiza operaciones de multiplicación en punto fijo.


o Realiza operaciones de multiplicación en punto flotante.
o Calcula el recíproco.
o Hay cuatro unidades operativas (L2, S2, M2, D2) o ALU que toman sus operandos en el
banco de registros B. Sus funciones son idénticas a las de las unidades 1.

3
UNIDAD PROFESIONAL INTERDISCIPLINARIA EN INGENIERIA
Y TECNOLGIAS AVANZADAS – IPN
PROCESADORES DIGITALES DE SEÑALES
Práctica No. 5
Uso de la memoria externa con punteros para grabar voz
Profr. M. en C. Juan Manuel Madrigal Bravo

o Mediante dos buses cruzados X1 y X2 (se verán a continuación), las


unidades operativas pueden tomar y operar sobre los registros del
banco opuesto.
o Debido a que cada unidad tiene su propio par de registros de entrada y
un registro de salida, las 8 unidades pueden ser usadas en paralelo en
cada ciclo.
o Las unidades .L1, .L2, .D1, .D2 tienen una extensión de 8 bits en su
puerto para operaciones de 40 bits.

Memoria RAM
La memoria RAM (Random Access Memory) es la encargada de almacenar las instrucciones que ejecuta
la unidad central de procesamiento. es conocida como memoria volátil lo cual quiere decir que los
datos no se guardan de manera permanente, es por ello, que cuando deja de existir una fuente de
energía en el dispositivo la información se pierde. Asimismo, la memoria RAM puede ser reescrita y
leída constantemente.
Existen 2 tipos básicos de memoria RAM; RAM dinámica (DRAM) y RAM estática (SRAM), ambas
utilizan diferentes tecnologías para almacenar los datos.

Memoria SRAM
(Static random access memory - Memoria de acceso aleatorio estática) Es un tipo de memoria
RAM. Estas memorias retienen su contenido el tiempo que reciben energía, es una memoria
volátil y preserva los datos sólo cuando recibe energía).
Es un tipo de memoria que es más rápida y más, tiene un tiempo de acceso de 10
nanosegundos, además, su ciclo es mucho más corto que el de las DRAM porque no necesitan
una pausa entre accesos. Desafortunadamente estas son mucho más caras de producir que
las DRAM; debido a su alto costo las memorias SRAM sólo son usadas en pequeñas memorias
caché.

Memoria DRAM
DRAM (Dynamic Random Access Memory) es un tipo de memoria dinámica de acceso
aleatorio que se usa principalmente en los módulos de memoria RAM y en otros dispositivos,
como memoria principal del sistema. Se denomina dinámica, ya que para mantener
almacenado un dato, se requiere revisar el mismo y recargarlo, cada cierto período, en un
ciclo de refresco. Su principal ventaja es la posibilidad de construir memorias con una gran
densidad de posiciones y que todavía funcionen a una velocidad alta: en la actualidad se
fabrican integrados con millones de posiciones y velocidades de acceso medidos en millones
de bit por segundo. Es una memoria volátil, es decir cuando no hay alimentación eléctrica, la
memoria no guarda la información. Fue inventada a finales de los sesenta y es una de las
memorias más usadas en la actualidad.

Memoria SBSRAM
Son las siglas de Synchronous Burst SRAM, funciona a (200 MHz), acceso sin restricciones de
páginas latencia pipeline de 2 ciclosTécnica de Poleo para acceso a periféricos

4
UNIDAD PROFESIONAL INTERDISCIPLINARIA EN INGENIERIA
Y TECNOLGIAS AVANZADAS – IPN
PROCESADORES DIGITALES DE SEÑALES
Práctica No. 5
Uso de la memoria externa con punteros para grabar voz
Profr. M. en C. Juan Manuel Madrigal Bravo

Técnica de Poleo para acceso a periféricos

Las técnicas por poleo para acceso a periféricos consisten en rutinas las cuales utilizan
apuntadores para guardar la información de los buffers. En este caso se preguntará si cierto
periférico tiene datos que entregar, de ser así lo aceptará, en caso contrario se irá a otro
periférico, y así sucesivamente. En el caso de la práctica las rutinas de acceso a periféricos por
poleo se encuentran en el archivo vectors_poll.asm

Material y equipo
1 kit de desarrollo DSKC6713
CCS
Micrófono
Audífonos

Desarrollo.
1. Crear un proyecto con nombre: DSP05_MEM_EXT_PUNTERO.pjt.
2. Agregue al proyecto desde zsupport el archivo de comandos del enlazador: c6713dsk.cmd (este
archivo forma parte de [3]). En el CCS 7.4 este archivo debe copiarse a la carpeta del proyecto y colocar
la ruta usando la secuencia Propiedades→ General → Linker Command File.

/*C6713dsk.cmd Linker command file*/

MEMORY
{
IVECS: org = 0h, len = 0x220
IRAM: org = 0x00000220, len = 0x0002FDE0
SRAM_EXT: org = 0x80000000, len = 0x01000000
FLASH: org = 0x90000000, len = 0x00020000
}

SECTIONS
{
.EXTRAM :> SRAM_EXT
.vecs :> IVECS /*Created in vectors file*/
.text :> IRAM /*Created by C Compiler*/
.bss :> IRAM
.cinit :> IRAM
.stack :> IRAM
.sysmem :> IRAM
.const :> IRAM
.switch :> IRAM
.far :> IRAM
.cio :> IRAM
.csldata :> IRAM
}

5
UNIDAD PROFESIONAL INTERDISCIPLINARIA EN INGENIERIA
Y TECNOLGIAS AVANZADAS – IPN
PROCESADORES DIGITALES DE SEÑALES
Práctica No. 5
Uso de la memoria externa con punteros para grabar voz
Profr. M. en C. Juan Manuel Madrigal Bravo

3. Agregar al proyecto desde zsupport el archivo: C6713dskinit.c con el CCS 3.1 en el cual se
encuentra el soporte para las funciones: input_sample, output_sample, comm_intr, etc. (este archivo
forma parte de [3]). En el CCS 7.4 este archivo debe copiarse a la carpeta del proyecto.

4. Agregar el archivo: vectors_poll.asm (en lugar de vectors_intr.asm) con el CCS 3.1 en el cual están
contenidos las rutinas de acceso a periféricos por poleo y desactivación de las interrupciones (este archivo
forma parte de [3]). En el CCS 7.4 este archivo debe copiarse a la carpeta del proyecto.

5. Agregue las librerías .lib: csl6713.lib, dsk6713bsl.lib, rts6700.lib

En la versión 3.1 del CCS


C:\CCStudio_v3.1\C6000\csl\lib\csl6713.lib
C:\CCStudio_v3.1\C6000\dsk6713\lib\dsk6713bsl.lib
C:\CCStudio_v3.1\C6000\cgtools\lib\rts6700.lib

En la versión 7.x del CCS agregue las siguientes rutas siguiendo la secuencia: Propiedades→ Build →
C6000 Linker → File Search Path → Include Library File
C:\ti\C6xCSL\lib_3x
C:\ti\DSK6713\c6000
C:\ti\ccs710\ccsv7\tools\compiler\c6000_7.4.23\lib

6. Agregar las rutas de las bibliotecas .h:


C:\ti\C6xCSL\include
C:\ti\DSK6713\c6000\dsk6713\include
C:\ti\ccs710\ccsv7\tools\compiler\c6000_7.4.23\include

7. Solo para el CCS 7.4 copiar el archivo C6713dskinit.h a la carpeta del proyecto.

8. Probar el siguiente código para crear un bucle transparente pero ahora utilizando la técnica de poleo
en vez de la técnica de interrupciones para el acceso a periféricos. (Este código forma parte de [3]).
(Calificación de 5.0)

//bucle_poll.c
#include "DSK6713_AIC23.h" //(Colocar la ruta en la versión 3.1)
Uint32 fs=DSK6713_AIC23_FREQ_8KHZ; //set sampling rate
void main()
{
short sample_data;
comm_poll(); //init DSK, codec, McBSP
while(1) //infinite loop
{
sample_data = input_sample(); //input sample
output_sample(sample_data); //output sample
}

6
UNIDAD PROFESIONAL INTERDISCIPLINARIA EN INGENIERIA
Y TECNOLGIAS AVANZADAS – IPN
PROCESADORES DIGITALES DE SEÑALES
Práctica No. 5
Uso de la memoria externa con punteros para grabar voz
Profr. M. en C. Juan Manuel Madrigal Bravo

9. Cargue el siguiente código C y retire el anterior.

// DSP05_MEM_EXT_PUNTEROS.c

#include "dsk6713_aic23.h” //Archivo de soporte del DSK (Colocar la ruta en la versión


3.1)

Uint32 fs=DSK6713_AIC23_FREQ_8KHZ; //Frecuencia de muestreo


#define N 24000 //Búffer
long i; short var, salida;
short* x_ptr= (short*) 0x80000000

void main()
{
comm_poll(); //DSK, CODEC y McBSP
DSK6713_DIP_init();
DSK6713_LED_init();
while(1) //Bucle infinito
{
if(DSK6713_DIP_get(0) == 0) //Verificar si el switch No. 0 está presionado
{
DSK6713_LED_on(0); //Encender LED No. 0
for (i = 0; i<N; i++)
{*(x_ptr+i) = input_sample();} //Lectura de una muestra de entrada
DSK6713_LED_off(0); //Apagar el LED No. 0 cuando el BÚFFER esté lleno
break;
}
};

var=0;
while(1)
{
if((DSK6713_DIP_get(1)==0)&&(var==0)) //Verificar si SW No. 1 está presionado y var=0
{
DSK6713_LED_on(1); //encender el LED No. 1
for (i = 0; i<N; i++)
{salida=*(x_ptr+i);
output_sample(salida); } //Reproducción
var=1;
DSK6713_LED_off(1); //Apagar el LED#1 cuando se termine
}
if(DSK6713_DIP_get(1)==1) var=0; //Cambiar el estado de la bandera
};
}

7
UNIDAD PROFESIONAL INTERDISCIPLINARIA EN INGENIERIA
Y TECNOLGIAS AVANZADAS – IPN
PROCESADORES DIGITALES DE SEÑALES
Práctica No. 5
Uso de la memoria externa con punteros para grabar voz
Profr. M. en C. Juan Manuel Madrigal Bravo

10. Compile el programa.

11. Cargue el archivo .out en el DSP.

12. Conecte un micrófono y un audífono.

13. Ejecute el programa.

14. Presione el switch 0 y hable por el micrófono por algunos segundos. Verifique que el led 0 se encienda
para indicar que la voz está siendo grabada y almacenada en un buffer. Cuando el led 0 se apaga, significa
que terminó el tiempo de grabación.

15. Presione el switch 1 y verifique que la señal de voz (almacenada en la memoria externa) se reproduzca.
Verifique que el led 1 se encienda. Desconecte el switch 1 para detener la reproducción.

16. Modifique el programa para que permita grabar y reproducir n veces sin necesidad de volver a
compilar y cargar el programa en la memoria interna del DSP.

(Calificación 7.0)

17. Realice dos particiones de memoria de 4 MB.


18. Agregue la característica de poder seleccionar con el dipswitch lo siguiente:
Dip0: Grabado en la primera partición (5segundos de voz)
Dip1: Reproducción directa
Dip2: Grabado en la segunda partición (5segundos de voz)
Dip3: Reproducción directa con cuatro ecos
(Calificación 9.5)

19. Repita el paso 15 pero ahora reemplazando input_sample, output_sample, comm_poll por sus
funciones de bajo nivel:
(Calificación 10.0)

// DSP08_MEM_EXT_PUNTEROS.c Uint32 fs=DSK6713_AIC23_FREQ_8KHZ;


#include "DSK6713_AIC23.h" //(Colocar la ruta //Frecuencia de muestreo
en la versión 3.1) #define N 40000 //Búffer

#include "DSK6713_dip.h" //(Colocar la ruta void comm_poll();


en la versión 3.1) void output_sample(int);
Uint32 input_sample();
#include "DSK6713_led.h" //(Colocar la ruta long i;
en la versión 3.1)
short var, salida;
short* x_ptr= (short*) 0x80000000;

8
UNIDAD PROFESIONAL INTERDISCIPLINARIA EN INGENIERIA
Y TECNOLGIAS AVANZADAS – IPN
PROCESADORES DIGITALES DE SEÑALES
Práctica No. 5
Uso de la memoria externa con punteros para grabar voz
Profr. M. en C. Juan Manuel Madrigal Bravo

short* x_ptr2= (short*) 0x80800000; DSK6713_LED_off(1);


void main(){ //Apagar el LED#0 cuando se termine

comm_poll(); //DSK, }
CODEC y if(DSK6713_DIP_get(1)==1) var=0;
McBSP DSK6713_DIP_init(); //Cambiar el estado de la bandera

DSK6713_LED_init();

while(1){
if(DSK6713_DIP_get(0) == 0) //Verificar si el //segunda pare
switch No. 3 está presionado if(DSK6713_DIP_get(2) == 0)
{ //Verificar si el switch No. 3 está presionado

DSK6713_LED_on(0); //Encender LED {


No. 3 DSK6713_LED_on(2);
//Encender LED No. 3

for (i = 0; i<N; i++){ for (i = 0; i<N; i++)

*(x_ptr+i) = input_sample(); {*(x_ptr2+i) = input_sample();}


//Lectura de una muestra de entrada
} //Lectura de una muestra
de entrada DSK6713_LED_off(2);
//Apagar el LED No. 3 cuando el BÚFFER esté
lleno
//break;
DSK6713_LED_off(0); }
//Apagar el LED No. 3 cuando el BÚFFER esté
lleno var=0;

//break; if((DSK6713_DIP_get(3)==0)&&(var==0))
//Verificar si SW No. 0 está presionado y var=0
}
{
var=0;
DSK6713_LED_on(3);
if((DSK6713_DIP_get(1)==0)&&(var==0)) //Apagar el LED No. 0
//Verificar si SW No. 0 está presionado y var=0
for (i = N; i>0; i--)
{salida=*(x_ptr2+i);
{
output_sample(salida); }
DSK6713_LED_on(1); //Reproducción
//Apagar el LED No. 0
var=1;
DSK6713_LED_off(3);
for (i = 0; i<N; i++){ //Apagar el LED#0 cuando se termine
salida=*(x_ptr+i); }
output_sample(salida); if(DSK6713_DIP_get(3)==1) var=0;
} //Reproducción //Cambiar el estado de la bandera
var=1; };
}

9
UNIDAD PROFESIONAL INTERDISCIPLINARIA EN INGENIERIA
Y TECNOLGIAS AVANZADAS – IPN
PROCESADORES DIGITALES DE SEÑALES
Práctica No. 5
Uso de la memoria externa con punteros para grabar voz
Profr. M. en C. Juan Manuel Madrigal Bravo

Cuestionario
1. ¿Qué ventajas tiene el uso de punteros?
 Constituyen la única forma de expresar algunas operaciones.
 Su uso produce código compacto y eficiente.
 Son imprescindibles para el paso de parámetros por referencia a funciones.
 Tienen una fuerte relación con el manejo eficiente de tablas y estructuras.
 Permiten realizar operaciones de asignación dinámica de memoria y manipular estructuras de
datos dinámicas.
 Se pueden tener apuntadores a cualquier tipo de variable.
 Son útiles para pasarle parámetros a las funciones de tal modo que les permiten modificar y
regresar valores a la rutina que las llama.

2. Calcule el máximo tiempo que se puede grabar en cada partición de memoria, considerando una
FS=8000 muestras/seg y cada muestra codificada con 8 bits.
 PARA IVECS:
capacidad 544 bytes. # de muestras = 544 muestras.
Tiempo máx. = 0.068 segundos.
 PARA IRAM:
capacidad 196064 bytes. # de muestras =196 064 muestras.
Tiempo máx. = 24.508 segundos.
 PARA SRAM_EXT:
capacidad 16 777 216 bytes. # de muestras =16 777 216 muestras
Tiempo máx. = 2097.152 segundos.
 PARA FLASH:
capacidad 131072 bytes. #de muestras = 131 072 muestras
Tiempo máx. = 16.384 segundos.
3. ¿De qué valor se debe seleccionar N de tal forma que se puedan grabar exactamente 1 hr de voz?
Depende del valor que consideremos como frecuencia de muestreo, sin consideramos una
frecuencia de muestreo de 8 KHz se debe tener una N de 28 800 000 de longitud para grabar
una hora exacta de audio.

10
UNIDAD PROFESIONAL INTERDISCIPLINARIA EN INGENIERIA
Y TECNOLGIAS AVANZADAS – IPN
PROCESADORES DIGITALES DE SEÑALES
Práctica No. 5
Uso de la memoria externa con punteros para grabar voz
Profr. M. en C. Juan Manuel Madrigal Bravo

4. ¿Qué capacidad de memoria RAM requiere almacenar 10 segundos de voz a una frecuencia de
muestreo de 16 000 muestras por segundo? Asuma que cada posición de memoria es de 8 bits y cada
muestra se codifica con 8 bits.
#𝑚𝑢𝑒𝑠𝑡𝑟𝑎𝑠
𝑇𝑖𝑒𝑚𝑝𝑜 =
𝐹𝑠
#𝑚𝑢𝑒𝑠𝑡𝑟𝑎𝑠 = 𝑇𝑖𝑒𝑚𝑝𝑜 ∗ 𝐹_𝑠 = 10 𝑠 ∗ 16000 𝑚𝑢𝑒𝑠𝑡𝑟𝑎𝑠/𝑠 = 160 000 𝑚𝑢𝑒𝑠𝑡𝑟𝑎𝑠
𝐶𝑎𝑝𝑎𝑐𝑖𝑑𝑎𝑑 𝑑𝑒 𝑅𝐴𝑀 = 160 000 𝑏𝑦𝑡𝑒𝑠 = 156.24 𝐾𝑏

5. ¿Qué capacidad tiene en la memoria (KB): IVECS, IRAM, SRAM_EXT y FLASH según al archivo del
enlazador de comandos? cmd?
PARA IVECS: hexadecimal 0x220 decimal  544 bytes capacidad  .53125 Kb
PARA IRAM: hexadecimal  0x0002FDE0 decimal  196064 bytes capacidad  191.4687 Kb
PARA SRAM_EXT: hexadecimal  0x01000000 decimal  16 777 216 bytes capacidad  16 384
Kb
PARA FLASH: hexadecimal  0x00020000 decimal  131072 bytes capacidad  128 Kb

Observaciones y conclusiones (Individuales y escritas a mano con pluma)

Bibliografía

[1] Code Composer Studio IDE Getting Started Guide, User's Guide. SPRU509f.

[2] F. J. Barrero García, S. L. Toral Marín, M. Ruiz González, Procesadores Digitales de Señal de altas
prestaciones de Texas Instruments, Mc Graw-Hill, 2005.

[3] R. Chassaing, Digital Signal Processing and Applications with the C6713 and C6416 DSK, Wiley-
Interscience, 2005.

[4] S. A. Tretter, “Communication System Design Using DSP Algorithms, with Laboratory Experiments for
the TMS320C6713TM DSK”, Springer 2008.

11
UNIDAD PROFESIONAL INTERDISCIPLINARIA EN INGENIERIA
Y TECNOLGIAS AVANZADAS – IPN
PROCESADORES DIGITALES DE SEÑALES
Práctica No. 5
Uso de la memoria externa con punteros para grabar voz
Profr. M. en C. Juan Manuel Madrigal Bravo

Conclusión

12

Das könnte Ihnen auch gefallen