Este apunte público tratará muchos conceptos y haré referencias a información extra para mantenerlo corto. Comenzaré con la razón por la que necesité hacer este programa. Requería construir un pulso para caracterizar un sistema (identificación de sistemas) a partir de su la respuesta. Un impulso o Delta de Dirac es una distribución que tiene la peculiaridad de tener un espectro que abarca todas las frecuencias. En teoría, si queremos saber cual será la respuesta de un sistema a todas las frecuencias entonces debemos aplicar como entrada una señal impulsiva. En la práctica hay algunos problemas. Es imposible construir un impulso ideal y a demás los sistemas físicos como los sensores están siempre limitados a una banda de frecuencias. Peor aún, al digitalizar la señal de un sensor analógico se restringe a un más el ancho de banda útil. Es por eso que en algunos casos en mejor utilizar una función Sinc (o seno cardinal) como entrada de caracterización ya que permite definir bastante bien el ancho de banda de trabajo. En mi caso particular, necesito una señal Sinc con un periodo de lóbulo principal de 1/(3.8kHz) o 263.16 us y con los bordes suavizados por una gaussiana. El periodo del lóbulo principal se mide entre sus cruces por 0. Su gráfica en el tiempo y su espectro se muestra a continuación:
Se puede notar que he establecido mi ancho de banda de trabajo de 0 a 3.8kHz. Ahora lo que procede es escribir un programa en un microcontrolador que me de un PWM que codifique mi señal Sinc. Por restricciones de espacio, mi aplicación requiere de un microcontrolador muy pequeño por lo que elegí el PIC16F15313 que tiene solo 8 pines. Justo los que requería. En México pueden comprarlos en AG Electrónica. El circuito usado es el siguiente:miércoles, 3 de marzo de 2021
Conversión Digital-Analógica por PWM filtrado en PIC16F15313
lunes, 15 de febrero de 2021
Módulo RTCC en PIC24
En la entrada anterior comentaba que necesitaba una interrupción con reloj secundario para verificar que mi configuración de cristal era correcta. Lo que en realidad quería hacer es de lo que quiero hablar en esta entrada. He combinado la librería de consola serial de Chan con una librería terminé de escribir a partir de los programas de ejemplo de la página de Microchip. Es una aplicación sencilla en la que se puede leer y escribir el valor del RTCC vía puerto serial. Los detalles los pueden encontrar en este repositorio de Github. No olviden ponerme una estrella.
jueves, 11 de febrero de 2021
Interrupción por TMR1 con reloj secundario (SOSC) en PIC24
martes, 11 de agosto de 2020
Chan's FatFs en PIC24: Librería para lectura/escritura en memorias SD
FatFs es un módulo de sistema de archivos FAT32/16 para microcontroladores. Está escrito en ANSI C y es altamente portable entre una gran variedad de dispositivos. Si bien su documentación es muy detallada, al ser muy genérica es fácil perderse a la hora de hacer una implementación en un microcontrolador en particular. En esta entrada trataré de explicar lo mejor posible como portarla a la familia PIC24. Lo primero que hay que entender es como están estructurados sus 5 archivos:
Los únicos archivos del módulo que hay que editar son diskio.c y ffconf.h. La portabilidad radica en terminar de escribir las siguientes funciones de comunicación SPI:- BYTE xchg_spi (BYTE dat)
- void xmit_spi_multi (const BYTE* buff, UINT cnt)
- void rcvr_spi_multi (BYTE* buff, UINT cnt )
- void FCKL_SLOW(void)
- void FCKL_FAST(void)
definir los macros:
- CS_LOW()
- CS_HIGH()
- MMC_CD
- MMC_WP
y crear una rutina de interrupción por timer de 1 KHz que incrementa una variable de conteo de tiempo: volatile UINT Timer. Esta interrupción sirve para el manejo de timeouts. En los archivos del ejemplo podrán encontrar comentarios detallados sobre el funcionamiento de estas funciones. Pondré un enlace al final.
Para simplificar esta primer versión del programa de ejemplo he desactivado la opción de reloj de tiempo real modificando la linea 237 de ffconf.h: FF_FS_NORTC = 1. Cuando está opción esta desactivada se requiere crear una función adicional que maneje el tiempo del sistema de archivos (lo haremos en otra entrada usando el módulo RTC del PIC24FJXXGB002).
En esta entrada ya he explicado como configurar el reloj de sistema y en esta otra como configurar el modulo SPI y el Periferial Pin Select.
Configuración de SCK
La primer cosa que hay hacer es estar seguros de que se pueda elegir entre dos frecuencias diferentes para el reloj del módulo SPI. Una baja que se encuentre entre 100 y 400 KHz y una alta que se la de operación (hay limites para esta frecuencia que explicaré más adelante). En la página 23 del documento Section 23. Serial Peripheral Interface encontramos la siguiente información:
Los módulos de la familia PIC24 tienen dos prescalers. En este ejemplo lo que haré será dejar fijo el prescaler primario a 16:1 y alternar con el secundario entre 8:1 para el reloj con FCLK_SLOW() para tener 125 KHz y 2:1 con FCLK_FAST() para tener 500 KHz. Para verificar experimentalmente que la frecuencia sea correcta pueden usar el modo de disparo único de un osciloscopio (aquí hay un tutorial para configurar ese modo). Buena parte de las fallas con la implementación de la librería FatFs tienen que ver con una frecuencia baja incorrecta.
Conexión con el modulo SD
La segunda falla de implementación más común tiene que ver con la conexión física con los módulos SD. He visto en varios foros, y también me pasó, que los dispositivos de 3.3 V fallan con algunos módulos microSD de este tipo pero que funcionan perfectamente cuando construyen sus propios circuitos de conexión a la memoria SD. En mi caso sólo me ha funcionado cn PIC24 con un módulo SD de tamaño estándar (como este) y con jumper flotando conectado a SCK. Desde PIC18 a 5V no he tenido problemas.
La tercer falla más común es con la frecuencia máxima. Comentan en los foros que algunos módulos prefabricados no están optimizados para trabajar a máxima frecuencia de SDK. Sus circuitos tienen un pasa-bajas que solo permite frecuencias de entre 1-2 MHz. Si están desarrollando una aplicación comercial es mejor que integren su propio circuito de conexión con un socket microSD.
Edit: ¡Alcance hacerla funcionar hasta la frecuencia máxima de SCK para el GB002 que es de 8MHz!
Otro detalle más. El simulador Proteus solo funciona con memorias virtuales en formato FAT16 en algunas instalaciones. Al menos a mi sólo me he funcionado así. En físico no he tenido problemas con FAT32.
Nivel de optimización
Esta librería ocupa bastante espacio. Un microcontrolador de 32K de memoria de programa es apenas suficiente (pero funciona). Idealmente deberían usar de al menos 64K. Si llega a marcar un error al compilar pueden intentar subir el nivel de optimización del compilador a 2 de la siguiente forma:
![]() |
Click para agrandar |
Código principal
Si todo lo anterior está en orden el siguiente ejemplo de escritura debe funcionar sin problemas con este circuito (el código es para GB002, el circuito en Proteus tiene un GA002 pero el conexionado es el mismo):
domingo, 5 de abril de 2020
Comunicación SPI para PIC24FJXXGA004 en XC16
El circuito simulado en Proteus es el siguiente:
![]() |
(Click para agrandar) |
jueves, 16 de enero de 2020
Escribir datos en sistema FAT32 con un PIC18F4550
Deben agregar el archivo __Lib_FAT32.h de cabecera a header files de su proyecto o solo copiándolo en el directorio donde se encuentre su archivo fuente .c.
Teniendo todo instalado, deben conectar el modulo SD al PIC de la siguiente manera:
- MISO ------ SDI (RB0)
- MOSI ------ SDO (RC7)
- SCK -------- SCK (RB1)
- CS----------- RC2
Para el manejo de múltiples archivos y directorios recomiendo revisar el ejemplo que viene en la documentación de la librería.
lunes, 13 de enero de 2020
Apuntes de transistores BJT (cheatsheets)
- Capítulo 6: Transistores de unión bipolares
- Capítulo 7: Fundamentos de los transistores
- Capítulo 8: Polarización de los transistores
- Capítulo 9: Modelos de alterna
- Capitulo 10: Amplificadores de tensión
martes, 19 de marzo de 2019
CIAA
martes, 12 de marzo de 2019
Máquina de Estados Finitos en C [PIC18F45K50]
En una gran cantidad de problemas a resolver mediante un sistema embebido es necesario llevar a cabo un proceso estrictamente secuencial. En estos casos es muy útil y elegante estructurar nuestros programas como una máquina de estados. Quizá muchos de ustedes estén tentados a usar una estructura case para elegir un segmento de código cuando se cumple una condición. Si el numero de estados es pequeño, quizá se una opción fácil. Desafortunadamente el uso de case's es muy ineficiente cuando la máquina de estados y su tabla de transiciones es muy compleja. La implementación que se mostrará en esta entrada parecerá un tanto rebuscada pero tiene la ventaja de tener buen despeño a la hora de escalarla a numero grande de estados.
El diagrama de estados de la FSM de este ejemplo es el siguiente:
![]() |
Diagrama hecho en LaTeX con TIKz |
Movámonos al programa. Primero, debemos definir un tipo enumerado para codificar nuestro conjunto de estados:
//-- Definición de tipo de estados
typedef enum {
Estado_0, // Estado inicial
Estado_1,
Estado_2,
Estado_3,
Estado_4,
No_de_Edos
} ESTADOS;
Creamos con esto una variable enumerada global que usaremos para almacenar el estado actual de la máquina:
//-- Variable global de estado
ESTADOS Estado_Actual = Estado_0;
El siguiente paso es definir una estructura que nos permitirá construir un objeto para nuestra FSM:
//-- Estructura de Maquina de Estados (FSM))
typedef struct {
ESTADOS Estado; // Estado miembro del conjunto enumerado ESTADOS
void (*func)(int); // Acciones asociadas al estado
} FSM;
Con lo anterior podemos ahora crear una instancia que sera nuestra FSM:
//-- Prototipos de funciones de estado
void Codigo_EDO_0(int);
void Codigo_EDO_1(int);
void Codigo_EDO_2(int);
void Codigo_EDO_3(int);
void Codigo_EDO_4(int);
//-- Creación de la estructura global de la FSM
FSM Maquina_de_Estados[] = {
{Estado_0,Codigo_EDO_0},
{Estado_1,Codigo_EDO_1},
{Estado_2,Codigo_EDO_2},
{Estado_3,Codigo_EDO_3},
{Estado_4,Codigo_EDO_4},
};
Es importante que los prototipos de las funciones asociadas a cada estado aparezcan antes de la creación de la estructura (estas funciones serán definidas más adelante en el código). El segmento de código principal queda reducido elegantemente de la siguiente manera:
void main(void) {
int sw = 0;
setup();
//-- FSM ---
while(1){
sw = PORTBbits.RB0;
(*Maquina_de_Estados[Estado_Actual].func)(sw);
}
return;
}
Código completo:
Circuito utilizado:
viernes, 22 de febrero de 2019
Iniciando con el PIC18F45K50 / 25K50 en XC8
1. Configuración del reloj
El esquema de reloj es distinto al de su antecesor [pag. 29]. Usando un cristal de 16 MHz, este es el camino que debe estar habitado para conseguir los 48 MHz:
![]() |
Click para agrandar |
#pragma config PLLSEL = PLL3X
#pragma config CFGPLLEN = OFF // ver Tabla 3-3
#pragma config CPUDIV = NOCLKDIV
#pragma config FOSC = HSM
#pragma config PCLKEN = ON
Los pines RB0 y RD0 son usados por el módulo ADC por lo que deben desactivarse para ellos. En el caso del puerto B, esto puede hacerse al generar la cabecera de fuses con la linea:
#pragma config PBADEN = OFF
Para el caso de RDO deberá hacerse en el código principal escribiendo en el registro ANSELD [la tabla con todos los registros de función especial está en la página 84 de la datasheet] :
3 Código completo en C
Como regla general siempre se debe leer en puerto y escribir en latch:
miércoles, 9 de enero de 2019
Cómo usar un MOSFET de potencia como interruptor
Podemos ahora poner en práctica esta consideración y simular un circuito de conmutación de una carga usando un IRF150. Este MOSFET puede aguantar un voltaje Vds de hasta 100V y una corriente Id de hasta 38A, pero usaremos una fuente de 30V solo como ejemplo. Elegiremos un voltaje Vgs de 15V para garantizar la corriente de saturación:
Vemos que este circuito funciona correctamente. Este modo se conoce como Low-Side. ¿Pero que ocurrirá si requerimos que la carga a conmutar deba estar por debajo del MOSFET [High-Side]? Si hacemos la simulación de este nuevo caso notaremos un problema:
Lo que se observa en este caso es que el voltaje entre las terminales G y D supera el voltaje de umbral pero no es lo suficientemente grande para garantizar la corriente de saturación. Esto es un problema muy común a la hora de construir inversores para convertir CD en CA. Este problema se resuelve utilizado un driver de boostrap como pueden ser el IR2001 o el IR2010. La siguiente simulación ejemplifica la manera correcta de conmutar un MOSFET con la carga por debajo:
Es importante señalar que este modo de conmutación no funciona de manera indefinida debido a la descarga del capacitor. Pero en aplicaciones de PWM funciona perfectamente siempre y cuando se elija un valor de capacitancia que mantenga encendido al MOSFET durante todo el ciclo de trabajo. En la práctica la conmutación de potencia suele realizarse desde un microcontrolador, así que recomiendo checar los modelos de drivers de conmutación que maneja Microchip tanto para Low-Side como High-Side y utilizar opto-acopladores ya que el voltaje de encendido supera los 10V en la mayoría de los MOSFET's de potencia.
miércoles, 12 de septiembre de 2018
Instalar MPLAB X en Debian 9 (64 bits)
$ sudo dpkg --add-architecture i386
Luego instalar librerias de compatibilidad para i386:
$ sudo apt-get update
$ sudo apt-get upgrade
$ sudo apt-get install libc6:i386 libx11-6:i386 libxext6:i386 libstdc++6:i386 libexpat1:i386
Finalmente se ejecuta el instalador descargado de aquí:
$ sudo ./MPLABX-v5.05-linux-installer.sh
Si la instalación se realiza correctamente podemos iniciar MPLAB X buscándolo en las aplicaciones:
NOTA: Deben tener ya instalado Java Runtime Enviroment en su sistema. Aquí hay una guía de instalación en español.
jueves, 28 de junio de 2018
Guía bibliografica para aprender ingeniería electrónica
Como requisito general es necesario al menos haber tomado los cursos de Calculo diferencial, Cálculo integral, álgebra lineal y ecuaciones diferenciales. Si se empieza desde 0 o se quiere repasar, recomiendo tomar los cursos anteriores en Khan Academy. Recomiendo aprender a usar simuladores de circuitos como Proteus, Multisim o LTspice. Aunque si quieren de paso entrar al mundo Linux y herramientas de simulación de código abierto, recomiendo instalar Fedora que es una distribución con bastantes herramientas para ingeniería electrónica en sus repositorios (Qucs, Oregano, Ngspice y gEDA).
Electrónica analógica
Quizá para muchos esta sea la única sección de interés, así que de ser el caso pueden prescindir de las demás secciones. Aquí se cubren todos los fundamentos de esta área. (Estoy dejando fuera temas más especializados como electrónica de potencia, MOSFETS y antenas y circuitos de alta frecuencia).
Esta sección parece la más corta, pero la considero de dificultad un poco más elevada que las anteriores. Es necesario haber estudiado las secciones de electrónica analógica y digital para continuar con ella. Recomiendo instalar y aprender a utilizar Octave, que es el clon de código abierto de Matlab (la sintaxis es prácticamente idéntica).
martes, 26 de junio de 2018
Hoja de apuntes de VHDL (cheatsheet))
domingo, 23 de octubre de 2016
Repositorio de tesis abierto de la PUCP
viernes, 4 de diciembre de 2015
Implementación de un controlador PID discreto en un PIC18F2550
Para controlar esta planta utilizaremos el siguiente controlador discreto a partir de la transformación backward Euler:
Dónde:
Obteniendo transformada inversa, la salida de control descrita como ecuación de diferencias nos queda:
Estos coeficientes pueden encontrarse manualmente siguiendo el procedimiento descrito aquí, o ejecutando éste programa de Matlab: [PID_Proteus.m]. Teniendo estos valores podemos realizar una verificación de la ecuación en Simulink:
Algo muy importante que se debe notar es que en esta simulación se está considerando la limitación física de la saturación de la salida del controlador real. Sin esta limitación la respuesta del controlador sería más rápida y con un sobreimpulso mucho menor. Sabiendo ahora que nuestra ecuación de diferencias es correcta podemos proceder a escribir el programa en el PIC en lenguaje C con el compilador MikroC. El programa completo se adjuntará más adelante. La función de control principal queda descrita como:
void pid(void) // Función para el controlador
{
e2=e1; e1=e0; u2=u1; u1=u0; // update de variables
y = ADC_Read(0); // Lectura analógica por AN0
yd = (double) y; // Conversión a double
vin = (yd/1023*5);
y = ADC_Read(1); // Lectura analógica por AN1
yd = (double) y; // Conversión a double
reff = (yd/1023*5);
e0 = reff - vin; // Error
u0 = ke0*e0 + ke1*e1 + ke2*e2 - ku1*u1 - ku2*u2; // Ecuación de diferencias
salida = (int) floor(((u0+5)/10)*1023);
if (salida > 1023) salida = 1023; // Saturación de DAC
if (salida <= 0) salida = 0;
DAC_Output(salida); // Enviar dato
}
Es muy importante que ésta función sea ejecutada dentro de una rutina de interrupción de manera que se tenga control del tiempo de muestreo Ts en exactamente 0.01 segundos para que el controlador funcione correctamente. Para la salida analógica del controlador se esta utilizando un DAC LTC1660 [2][3]. Compilando el programa y simulando en Proteus:
Nota: El relay en la simulación lo único que hace es evitar que la salida bipolar del DAC envíe un voltaje de saturación negativo al inicio [ver este programa].
jueves, 17 de septiembre de 2015
Filtro de Notch de 60 Hz
Para más detalles sobre este tipo de filtros pueden consultar éste artículo.
domingo, 13 de septiembre de 2015
Circuito para electrocardiografía (ECG/EKG)
En este video utilizan un circuito con ganancia de 100 con buenos resultados (el cual no funcionó en mi caso), lo que me hace sospechar que existen varios factores que afectan el voltaje de entrada. Posiblemente este circuito no funcionará en condiciones diferentes por lo que recomiendo experimentar con diferentes valores de ganancia.
Un segundo circuito que también funciona muy bien es una modificación del que pueden encontrar en The Biosignal How-To:
miércoles, 15 de julio de 2015
Comunicación SPI con un DAC en VHDL
De la hoja de especificaciones, tenemos el siguiente diagrama de tiempos:
Los periodos que nos interesan son t5, que es el periodo mínimo entre datos ( el tiempo mínimo que el FPGA debe esperar para enviar el siguiente dato de manera que el DAC pueda reaccionar) y t3 y t4 que nos indican que SCK debe tener un duty cycle de 50% con un periodo T = t3+t4. En la página 4 de la hoja podemos encontrar que los tiempos mínimos requeridos son: t5 = 100 ns y una frecuencia para SCK de 10 Mhz. Los periodos t1 y t2 nos indican una especificación igual de importante. Indican que el flanco de subida de SCK debe ocurrir justo a la mitad del bit enviado. Entendiendo estas restricciones, podemos ahora comenzar a escribir nuestro programa. Nuestra entidad deberá tener 2 entradas: clk y un reset, y 3 salidas: SCK, CD y datos:
La implementación estará formada por los siguientes bloques elementales:
- Divisor de frecuencia (50 a 10 MHz)
- Divisor de frecuencia para reloj de CS
- Memoria ROM
- Registro PISO (Parallel Input Serial Output)
- Generador de reloj SCK
Memoria ROM
Los datos almacenados por esta memoria deben tener la estructura especificada por el fabricante (pag. 8), que en este caso es la siguiente:
Para este ejemplo debemos enviar la mitad del voltaje de referencia al canal A y actualizar su salida, por lo que los valores para el código de control deben ser "1001" (ver tabla de la pag. 9). Se crean entonces las siguientes señales que serán usadas en la memoria ROM:
type rom is array(0 to 2) of std_logic_vector(15 downto 0);
constant control: std_logic_vector(3 downto 0):="1001";
constant dc: std_logic_vector(1 downto 0):= "00"; -- Bits don't care constant myrom: rom
:=( control&"0111111111"&dc,
control&"0111111111"&dc,
control&"0111111111"&dc);
La razón de implementar una memoria ROM como un arreglo de varios elementos para un ejemplo tan simple es para que pueda ser modificada fácilmente para hacer cosas más interesantes como enviar una función triangular o cosenoidal (en cuyo caso habrá que incrementar el tamaño del array a entre 50 o 100 elementos). Otro detalle que debo mencionar es que, como se verá en el programa completo, el incremento de la dirección se hace con el reloj CS. Esto se hace a modo de tener el bit-rate máximo. Se puede agregar un nuevo divisor a una frecuencia más baja para cambiar el dato si así lo desean.
Registro PISO
Este registro serializará los datos recibidos de la salida de la memoria ROM y los enviará de forma síncrona en cada flanco de bajada* del reloj secundario de 10 MHz. La serialización únicamente se efectuará después de recibir un flanco de subida del reloj CS.
*Esto de modo que se cumpla la especificación de los tiempos t1 y t2, así SCK deberá estar en fase con el reloj secundario.
Generador de reloj SCK
Este reloj deberá tener una frecuencia de 10 MHz pero requiere cumplir una condición: debe activarse durante el siguiente flanco de subida del reloj secundario (10 MHz) después del flanco de bajada del pulso CS. Esto se logra mediante una implementación if síncrona normal. Sin embargo, dado que no es posible implementar físicamente una instrucción en flanco de bajada inmediatamente después de un flanco de subida ("bad synchronous description") se recuré a un truco combinacional para generar el reloj SCK que puede verse en el programa completo.
Teniendo el programa listo, así luce en simulación con ISim:
Programa completo
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_ARITH.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;
entity DAC_SPI is
port(
clk : in std_logic; -- 50 MHz
reset : in std_logic;
CS : out std_logic;
SCK : out std_logic; -- 10 MHz
datos : out std_logic); -- Salida serial
end entity;
architecture rtl of DAC_SPI is
-- Señales
-- Divisor
signal count: integer :=1;
signal clk_10: std_logic:='0';
-- ROM
signal address: integer range 0 to 2;
type rom is array(0 to 2) of std_logic_vector(15 downto 0);
constant control: std_logic_vector(3 downto 0):="1001"; -- Cargar y actualizar canal A
constant dc: std_logic_vector(1 downto 0):= "00"; -- Bits don't care
constant myrom: rom
:=( control&"0111111111"&dc,
control&"0111111111"&dc,
control&"0111111111"&dc);
signal rom_out: std_logic_vector(15 downto 0):=(others=>'0');
signal clk_cs: std_logic:='0';
-- PISO
signal temp: std_logic_vector(15 downto 0):= (others =>'0');
signal t: std_logic;
-- Otros
signal a: integer range 0 to 18 :=1;
signal sck_t: std_logic;
--
begin
-- Divisor de frecuencia (10 MHz)
process(clk) begin
if(clk'event and clk='1') then
count <=count+1;
if(count = 5) then -- dónde count = frec de reloj / frec deseada
clk_10 <= not clk_10;
count <=1;
end if;
end if;
end process;
--
-- PISO
process (clk_10,rom_out,clk_cs)begin
if (CLK_10'event and CLK_10='0') then
if (clk_cs='1') then
temp(15 downto 0) <= rom_out(15 downto 0);
else
t <= temp(15);
temp(15 downto 1) <= temp(14 downto 0);
temp(0) <= '0';
end if;
end if;
end process;
datos <= t;
--
-- SCK
process(clk_10,clk_cs) begin
if (clk_10'event and clk_10 = '1') then
if(clk_cs='0')then
SCK_t <= '1';
else
SCK_t <= '0';
end if;
end if;
end process;
SCK <= (sck_t) and (clk_10) and not(clk_cs);
--
-- Divisor de frecuencia para CLK_CS
process(clk_10) begin
if(clk_10'event and clk_10='1') then
a <=a+1;
if(a = 17) then
clk_cs <= '1';
a <=0;
else
clk_cs <= '0';
end if;
end if;
end process;
--
-- ROM
process(clk_cs,reset) begin
if reset = '1' then
address <= 0;
elsif( clk_cs'event and clk_cs = '1' ) then
if address < 2 then
address <= address + 1;
else
address <= 0;
end if;
rom_out <= myrom(address);
end if;
end process;
-- CS
CS <= clk_cs;
--
end rtl;
lunes, 13 de julio de 2015
Simulando circuitos con ngspice
Es necesario crear un directorio en donde estén guardados los archivos .mod (SPICE models) que contienen los modelos de simulación de los dispositivos electrónicos que van a utilizarse. Estos archivos no están incluidos en la instalación por defecto de ngspice, pero son proveídos por los mismos fabricantes de componentes. Estos modelos deben ser enlazados a los componentes desde gschem.
Instalación en Debian/Ubuntu/Linux Mint:
$ sudo apt-get install ngspice
Para instalar gschem y gnetlist instalamos el paquede gEDA:
$ apt-get update && apt-get install geda pcb gerbv
Abrimos gschem:
$ gschem
, buscamos "añadir componente" en la barra de herramientas (su ícono es una compuerta and) y usamos los siguientes componentes:
SPICE simulation elements > vsin-1.sym
Diodes (generic) > diode-1.sym
Basic devices > resistor.sym
Power rails > gnd-1.sym
La interfaz de gschem es bastante intuitiva. Para girar 90° un componente sólo hay que seleccionarlo y presionar las teclas E y R (una después de la otra). Una vez terminado el circuito se deben configurar los componentes para poder generar un netlist que pueda ser simulado correctamente por ngspice. Dando doble click en el diodo se abrirá una ventana dónde debemos añadir una propiedad value cuyo valor será 1N4001 y damos click en "añadir":
Hacemos lo mismo con la fuente de AC. En este caso, value ya aparecerá en la tabla por lo que solo debemos modificar su valor directamente escribiendo "sin 0 5 60Hz". Para agregar un valor a la resistencia, le damos click derecho a su símbolo y buscamos "añadir propiedad", se abrirá una ventana dónde en "nombre" escribimos "value" y en "valor" escribimos su resistencia en Ohms (100 para este ejemplo), en la última opción seleccionamos "Mostrar solo valor". Después de esto ahora sólo hace falta enlazar el archivo de modelo de SPICE al símbolo del diodo. Para esto regresamos a "agregar componente" y buscamos SPICE simulation elements > spice-model-1.sym. Para este modelo en particular las propiedades deben ser las siguientes:
Observen que en file he escrito la ruta al archivo de modelo para el diodo 1N4007 (pueden descargar un modelo de ese diodo aquí, cambiando la extensión de .txt a .mod) . Guardamos el esquema con el nombre diodo.sch. El esquema terminado debe verse algo así:
Para generar el netlist escribimos:
$ gnetlist -g spice-sdb -o diodo.net diodo.sch
[NOTA: consultar sintaxis y opciones de gnetlist]
Ejecutamos con ngspice:
$ ngspice diodo.net
Ya dentro de la consola de ngspice escribimos:
tran 100us 100ms #dónde se indica 100us de step simulando de 0 a 100ms
plot v(2)
Se abrirá una ventana con la gráfica del voltaje en la resistencia:
NOTA: Deben tomar siempre en cuenta el nombre del modelo que está declarado dentro del archivo .mod. El modelo del 1N4007 que estoy usando es diferente al que pueden descargar en diodes.com. Si usan ese archivo, deben asigar valores para la propiedad value de DI_1N4007 en vez de 1N4007 (o simplemente cambiar el nombre en el script del modelo). Este es el contenido del archivo de diodes.com, señalo el lugar donde va el nombre del modelo:
*SRC=1N4007;DI_1N4007;Diodes;Si; 1.00kV 1.00A 3.00us Diodes, Inc. diode
.MODEL DI_1N4007 D ( IS=76.9p RS=42.0m BV=1.00k IBV=5.00u
+ CJO=26.5p M=0.333 N=1.45 TT=4.32u )