TODOPIC
Otros Microcontroladores / Dispositivos programables => Lógica Programable => Mensaje iniciado por: splasma2 en 03 de Enero de 2012, 08:34:13
-
Feliz Año 2012 a todos....
Para empezar el "ultimo año del planeta" se me ha ocurrido hacer algo con una placa FPGA Altera CycloneII + 16Mb de SDRAM que compre hace tiempo en eBay.
Después de comprobar que usar esta placa para sintetizar pequeños/medianos circuitos lógicos era un desperdicio, me pusé a jugar con el soft core NiosII de Altera y sus perifericos.
Al final con la ayuda del magnifico kit ( freeware) de Altera conseguí "meter" una CPU NiosII con su correpondiente controlador de SDRAM , controlador serie, timer, etc...en la FPGA y correr un programa C compilado desde Eclipse... :mrgreen:
Y lo siguiente que me he propuesto es hacer un periferico HW mapeado directamente en el espacio de direcciones de la CPU, que permita gestionar una matriz de LEDs por HW. Si todo va bien al final tendre un sistema con una CPU NiosII que puede comunicarse via serie con el PC; y que dispone de varios controladores HW de matriz de LEDS integrados, pensando en el control de un cubo-LED a alta velocidad ... :shock:
Ya os ire contando...
-
Para empezar el "ultimo año del planeta"
:D
Después de comprobar que usar esta placa para sintetizar pequeños/medianos circuitos lógicos era un desperdicio, me pusé a jugar con el soft core NiosII de Altera y sus perifericos.
Al final con la ayuda del magnifico kit ( freeware) de Altera conseguí "meter" una CPU NiosII con su correpondiente controlador de SDRAM , controlador serie, timer, etc...en la FPGA y correr un programa C compilado desde Eclipse... :mrgreen:
Y lo siguiente que me he propuesto es hacer un periferico HW mapeado directamente en el espacio de direcciones de la CPU, que permita gestionar una matriz de LEDs por HW. Si todo va bien al final tendre un sistema con una CPU NiosII que puede comunicarse via serie con el PC; y que dispone de varios controladores HW de matriz de LEDS integrados, pensando en el control de un cubo-LED a alta velocidad ... :shock:
Ya os ire contando...
Muy interesante... Me comentaron que hay un par de CPU open source, que info tienes al respecto? Tengo que conseguirme un kit de esos para jugar, uno más a la lista :mrgreen:
-
En opencores.org puedes encontrar unas cuantas soft CPU "free".
Pero si quieres montarte un System On a Programmable Chip (SOPC) serio , te aconsejo que uses el kit de Altera ( en mi caso es la FPGA que uso...) , que viene con CPUs ( de tres niveles de compeljidad) y muchos perifericos que se pueden conectar facilmente a la CPU mediante un bus de Altera ( Avalon). Ademas viene con un entorno Ecplise para desarrollar programas en C/C++ para el SOPC que fabriques.
Con ese kit y la documentación asociada , que es mucha... yo consegui instalar en la FPGA un SOPC y compilar y ejecutar un miniprograma en poco más de una hora, el famoso "Hello world..."
Animo y suerte...
-
Muchas gracias por la data ;-)
Saludos!
-
Este es el esquema de bloques :
(http://img193.imageshack.us/img193/2045/ctrlhwmatriz.gif) (http://imageshack.us/photo/my-images/193/ctrlhwmatriz.gif/)
Uploaded with ImageShack.us (http://imageshack.us)
-
Buenas, os pongo el codigo VHDL del componente que controla una matriz 2D de LEDs, resumiendo es un componente con puertos para conectarse a la CPU NiosII usando el bus Avalon (Addr,DataRd,DataWR,Wr,Rd,CS,Clk ,nReset) y los puertos de salida de control de la matriz 2D LED ( LedRowPut,LedColOut). Instanciando varios componentes de este tipo podremos controlar la matriz 3D ( cubo).
El problema es que consume muchos recursos de la FPGA ya que la matriz la sintetiza con registros, estoy viendo como usar la memoria interna que llevan los Cyclone de Altera para reducir el uso de registros al minimo.
LIBRARY ieee;
USE ieee.std_logic_1164.all;
USE ieee.std_logic_arith.all;
USE ieee.std_logic_signed.all;
--USE ieee.numeric_std.all;
---------------------------------------------------
--------------------------------------------------
-- LED 2D Matrix driver
-- COL : num. columnas ( 5 cols.).
-- ROW : num. filas ( 5 red + 5 green = 10 rows. )
-- Freq refresco : 100 Hz ( 10 ms )
-- Valores LED : 64
-- Freq. PWM : 64 * ROW @ 10 ms -> ROW(10) => 64000 hz.
--------------------------------------------------
--------------------------------------------------
ENTITY shifter_LED IS
GENERIC(
COL_NUMBER : in natural := 8; -- Max 16
ROW_NUMBER : in natural := 16; -- Max 16
CLK_DIVIDER : in natural := 780 -- 50 Mhz / 780 -> 64000 Hz
);
PORT (
-- Avalon interface
Clk : IN STD_LOGIC;
nReset : IN STD_LOGIC;
CS : IN STD_LOGIC;
Addr : IN STD_LOGIC_VECTOR(1 downto 0);
Wr : IN STD_LOGIC;
DataWr : IN STD_LOGIC_VECTOR(15 downto 0);
Rd : IN STD_LOGIC;
DataRd : OUT STD_LOGIC_VECTOR(15 downto 0);
--MatrixPWMClk : IN std_logic;
-- LED Outputs ( 5 x 5 x 2 colors)
LedRowOut : OUT STD_LOGIC_VECTOR(ROW_NUMBER-1 downto 0);
LedColOut : OUT STD_LOGIC_VECTOR(COL_NUMBER-1 downto 0)
) ;
END shifter_LED;
ARCHITECTURE rtl OF shifter_LED IS
CONSTANT COL_BITS : integer := 3; -- 2^COL_BITS <= COL_NUMBER
CONSTANT ROW_BITS : integer := 4; -- 2^ROW_BITS <= ROW_NUMBER
-- Matrix types
subtype t_LED_value is integer range 0 to 127;
CONSTANT VAL_BITS : integer := 7; -- 2^VAL_BITS < t_LED_value'high
type t_LED_matrix is array (0 to ROW_NUMBER-1,0 to COL_NUMBER-1) of t_LED_value;
-- LED Matrix
signal matrix : t_LED_matrix;
-- Registers
signal control_reg: STD_LOGIC_VECTOR ( 7 DOWNTO 0);
--signal data_reg : STD_LOGIC_VECTOR (15 DOWNTO 0);
signal addr_reg : STD_LOGIC_VECTOR (15 DOWNTO 0);
signal MatrixPWMClk : std_logic;
SIGNAL led_row_out: STD_LOGIC_VECTOR (ROW_NUMBER-1 DOWNTO 0);
SIGNAL scanner : UNSIGNED(COL_NUMBER-1 DOWNTO 0);
BEGIN
LedRowOut <= led_row_out;
LedColOut <= STD_LOGIC_VECTOR(scanner);
process (clk,nReset)
variable row : integer range 0 to ROW_NUMBER-1;
variable col : integer range 0 to COL_NUMBER-1;
begin
if (nReset = '0') then
matrix <= (others => (others => 0));
control_reg <= (others => '0');
col := 0;
row := 0;
elsif rising_edge(Clk) then
if CS = '1' and Wr = '1' then
case Addr is
-- Control register
when "00" =>
control_reg <= DataWr(7 DOWNTO 0);
-- Address register
when "01" =>
addr_reg <= DataWr;
-- WARN: No hay chequeo de rangos...
col := conv_integer( unsigned(addr_reg ( 8+COL_BITS-1 DOWNTO 8 )));
row := conv_integer( unsigned(addr_reg ( ROW_BITS-1 DOWNTO 0 )));
-- Data register
when "10" =>
-- WARN: No hay chequeo de rangos...
matrix(row,col) <= conv_integer( unsigned(DataWr( VAL_BITS-1 DOWNTO 0 )));
-- Auto-incremento Row->Col
if (row = ROW_NUMBER-1)
then
row := 0;
if (col = COL_NUMBER-1)
then
col := 0;
else
col := col + 1;
end if;
else
row := row + 1;
end if;
addr_reg( 7 DOWNTO 0 ) <= STD_LOGIC_VECTOR(conv_unsigned(row,8));
addr_reg( 15 DOWNTO 8 ) <= STD_LOGIC_VECTOR(conv_unsigned(col,8));
when others => null;
end case;
end if;
end if;
end process;
-- Generate internal Clock
process_Clock:
process(Clk, nReset)
variable cntClock : integer range 0 to CLK_DIVIDER+1;
begin
if (nReset = '0') then
MatrixPWMClk <= '0';
cntClock := 0;
elsif rising_edge(Clk) then
if(cntClock > CLK_DIVIDER) then
MatrixPWMClk <= not MatrixPWMClk;
cntClock := 0;
else
cntClock := cntClock +1 ;
end if;
end if;
end process process_Clock;
-- Shift data
process_GeneratePWM:
process(MatrixPWMClk, nReset)
variable cntCol : integer range 0 to COL_NUMBER := 0;
variable valPWM : t_LED_value := 0;
begin
if (nReset = '0') then
led_row_out <= (others => '0');
scanner <= conv_unsigned(1,COL_NUMBER);
cntCol := 0;
valPWM := 1;
elsif rising_edge(MatrixPWMClk) then
-- Incrementamos valor del PWM
-- Si llegamos al maximo reiniciamos
if (valPWM = t_LED_value'high)
then
valPWM := 1;
-- Siguiente columna
cntCol := cntCol +1;
if (cntCol < COL_NUMBER) then
scanner(COL_NUMBER-1 downto 1) <= scanner(COL_NUMBER-2 downto 0);
scanner(0) <= scanner(COL_NUMBER-1);
else
scanner <= conv_unsigned(1,COL_NUMBER);
cntCol := 0;
end if;
else
valPWM := valPWM + 1;
end if;
-- Activamos salida LED solo si el valor es mayor que valPWM actual.
for row in 0 to ROW_NUMBER-1
loop
if ( matrix(row,cntCol) >= valPWM)
then
led_row_out(row) <= '1';
else
led_row_out(row) <= '0';
end if;
end loop;
end if;
end process process_GeneratePWM;
-- Asynchronous Read
process_Read:
process(Addr,control_reg,addr_reg,CS,Rd,matrix)
--variable row : integer range 0 to ROW_NUMBER-1;
--variable col : integer range 0 to COL_NUMBER-1;
begin
--if CS = '1' and Rd = '1' then
case Addr is
when "00" => DataRd <= "00000000" & control_reg;
when "01" => DataRd <= addr_reg;
--when "10" =>
-- WARN: No hay chequeo de rangos...
--col := conv_integer( unsigned(addr_reg ( 8+COL_BITS-1 DOWNTO 8 )));
--row := conv_integer( unsigned(addr_reg ( ROW_BITS-1 DOWNTO 0 )));
--DataRd <= STD_LOGIC_VECTOR(conv_unsigned(matrix(row,col),16));
when others => DataRd <= (others => '1');
end case;
--end if;
end process process_Read ;
END rtl;
-
Felicitaciones por el proyecto splasma ((:-)) lo seguiré con mucho interés. Desde hace unas semanas semanas se me encargó construir una controladora ATA con uno de estos bichos y llegué a la misma conclusión de usar un procesador embebido en el fpga en vez de reinventar la rueda construyendo cada módulo desde cero.
Me queda una duda que se me puedes aclarar, una vez que creaste el módulo compatible con el bus avalon y lo "importaste" en el Qsys (suponiendo que usas Qsys) y sintetizaste el proyecto, que parámetros manejas posteriormente desde el eclipse?? o bien, que funciones se crean en el system.h para controlar tu módulo???
Una vez mas, felicitaciones :)
-
buenas noches muy interesante sus aportes, acabamos de adquirir un kit de altera que es un nios ii cyclone iii y la idea es hacer procesamiento de video
para hacer un vehiculo autonomo usando una camara, pero para empezar se quiere usar ultrasonidos como sensor. la duda que tenemos es que este kit cuenta
con pocos conectores ps solo cuenta con el serial, me gustaria saber si se puede hacer sabiendo que se debe manejar los sensores ultrasonicos y los motores por el puertos serial
-
Fausto, puedes dar mas detalles de tu kit?? me parece extraño que el único método I/O de la placa sea un puerto serial. Ademas, que tipo de interfaz presentan tus sensores?? es decir, que tipo de datos entregan, hay algunos que entregan datos ascii via rs232 y otros una variedad de pulsos (entre muchas maneras mas).
Otra cosa, no es que el FPGA en cuestion sea un NIOS II, sino que este integrado soporta un procesador embebido en el Cyclone III, de hecho puedes usar otros procesadores como el de un PIC o un ARM entre otros, es cosa de mirar opencores para hacerse una idea.
Saludos.
-
gracias por responder mira los datos del kit
LCD daughtercard
Color LCD touch-screen display
800 x 480 resolution
24-bit CD-quality Audio CODEC with line-in, line-out, and microphone-in jacks
10/100 Ethernet physical layer/media access control (PHY/MAC)
Connectors
VGA output
Composite TV-in
Audio-out, audio-in, and microphone-in
4-bit Secure digital (SD) card
Serial connector (RS-232 DB9 port)
PS/2
Ethernet connector (RJ-45)
8-pin debug I/O
Size:125*100 mm
The Cyclone III FPGA Starter Kit
Cyclone III EP3C25F324 FPGA
http://www.terasic.com.tw/cgi-bin/page/archive.pl?Language=English&CategoryNo=56&No=372 y aqui esta la imagen del kit
a los sensores son los srf05 son ultrasonidos y los motores son cc de 24v a 5a
y pues le agradezc cualquier ayuda la idea es ir haciendo estas practicas y ir subiendo el nivel hasta llegar a procesar video
ya que este kit me lo dieron para hacer pruebas
-
Está bien buena la placa eh? :mrgreen: En la placa veo un puerto llamado GPIO Header (General Purpose Input Output) creo q este debería ser inicialmente tu punto de partida para manejar los motores y sensores.
Por lo que vi en http://www.superrobotica.com/S320111.htm deberias dedicar dos pines de la placa al sensor y crear algún tipo de maquina de estados que envíe el pulso inicial y lea el ancho de pulso para ser convertido en distancia, en cuanto al motor, seria algo parecido pero ten cuidado con la adaptación de voltajes y la corriente que consumen los motores, un puente H o algún buffer seria necesario ahí.
Saludos.
-
si claro este kit es muy bueno me llego la semana pasada y pues la idea es hacer practicas aprovechando la pantalla tactil que tiene y claro tambien me gustaria ir mostrando en el foro mis avances para eso tengo 6 meses con este kit por eso mi interes de hacer practicas y poderlas compartir
entonces me dices que ademas del puerto serial hay otro puerto? que se puede usar.. para mi objetivo
por la parte de del motor pues tengo la parte de control aparte con un puente h y pues creo que se uede aislar con optoacopladores para evitar problemas con el kit
y veo que en la sd que tiene el kit vienen ejemplos para el uso del programa nios II
esa es otra cosa de este kit ya todo se cargar a la sd.
ya que veo que manejas tan bien esto cual programa me recomendaria para empezar el quartus II o el nios II
veo q tienen herramientas como sopc builder
-
http://www.altera.com/literature/ds/ds_nios2_3c25_lcd.pdf mira este link aca esta la distribucion de los puerto
y los pines de la fpga
-
Maldición, se me borró todo lo que escribí :5]
Te decia que de manejarme en esto nada, tomé el tema porque hace semana y media me pidieron hacer una controladora ATA para un disco duro y hasta ahora ni idea como :oops: y para esto me dieron 2 meses 1/2 :?
Sobre NIOSII o QUARTUS, hasta donde yo se el NIOS II EDS es un compilador (y otras cosas mas) que trabaja sobre la IDE de Eclipse donde puedes programar en un lenguaje de alto nivel como C el procesador (y sus perifericos) que hayas programado y sintetizado en el Quartus II, ya sea mediante la herramienta Qsys o bien Sopc builder.
Te recomiendo darle una mirada a algunos de estos videos tutoriales, especialmente a los que hacen referencia al NIOSII:
http://www.altera.com/education/training/curriculum/embedded_sw/trn-embedded_sw.html
http://www.altera.com/education/training/curriculum/embedded_hw/trn-embedded_hw.html
Además en youtube, vi un video del mismo tipo que hace estas placas dar un pequeño tutorial sobre como construir una solución con niosii se llama algo asi como "My first nios II"
-
Hola, me da gusto saber que esto de las FPGA ya está abarcando más usuarios.
Yo estuve trabajando con Altium y su sintetizador VHDL pero es una cosa del demonio... funciona cuando quiere, sintetiza lo que quiere, el micro TSK3000A es sumamente espacioso (65% de elementos lógicos de una Cyclone de 12000), y el compilador en C repleto de bugs y nada respetuoso del ANSI C. Simplemente horrible.
Un amigo me enseñó a usar el Nios II con el SOPC de Quartus. Esta joya de procesador sólo consumió el 25% de la FPGA y el ambiente Eclipse y todas las librerías que trae lo hacen tan fácil de usar como nada.
Splasma2, no soy experto en VHDL pero hay forma de decirle a Quartus que use la RAM on-chip de la FPGA, de hecho puedes verlo en el MegaWizard de Quartus... ahí hay generadores de RAM de donde puedes sacar el código para usarla. Ahorita no tengo mi código ni Quartus a la mano, pero en cuanto lo tenga te lo puedo mostrar.
Para practicar, un amigo me consiguió este kit con un Cyclone IV :mrgreen:
http://www.terasic.com.tw/cgi-bin/page/archive.pl?Language=English&CategoryNo=139&No=593
(http://www.freeimagehosting.net/newuploads/rlm53.jpg)
-
Consulta rápida, que capacidad mínima debe tener un FPGA para implementar Nios II... Estaba viendo unas placas en Ebay, me acorde del tema y entré a dudar si será útil. La placa tiene un Cyclone II EP2C8, o sea 8k LEs.
Saludos!
-
Hola Suky, depende de la FPGA, pero con 8k LE estás del otro lado...
http://www.altera.com/literature/ds/ds_nios2_perf.pdf
También te piden RAM on-chip, pero el Hello World optimizado lo he corrido con solo 4k en una Cyclone y no hubo problemas.
-
Gracias! Ya me pedí la plaquita, así que ahora a esperar :)
Saludos!
-
Gracias! Ya me pedí la plaquita, así que ahora a esperar :)
Saludos!
¿Cuál fue a final de cuentas?
-
Estoy usando esa misma placa para mi proyecto Santiago :mrgreen: , la verdad es que estoy sorprendido por el precio, buscando por ebay y aliexpress no encontré alguna que se le igualara en razón de calidad/precio.
Alguien mas ha hecho algún proyecto con el nios ii??? yo hasta ahora he logrado integrarle una uart y comunicarla con un ft232 que tenia por ahí, por el momento estoy tratando de manejar el uart mediante interrupciones pero no lo he logrado, solo las interrupciones de un puerto de entrada. Cuando tenga algo de código concreto lo compartiré con ustedes.
Saludos!
-
Lo más que he hecho con ella y Nios II es un pwm con JTAG UART jejeje
En el Cyclone I eché a andar VGA, pero en esta plaquita necesito hacer el R2R para lograrlo también :?
-
amigo migsantiago claro es q con las fpga se puede hacer una infinidad de cosas, me gustaria q compartieras un pco como es el uso de nios ii para poder hacer la comunicacion serial kit con otros componentes y poder ya mostrar ejemplos q tenemos con los cmpañeros , yo soy relativamente nuevo en esto pero con muchas gans de aprender y poder sacarle provecho al kit q tengo y tambien en el foro mostrar ejemplos
-
amigo migsantiago claro es q con las fpga se puede hacer una infinidad de cosas, me gustaria q compartieras un pco como es el uso de nios ii para poder hacer la comunicacion serial kit con otros componentes y poder ya mostrar ejemplos q tenemos con los cmpañeros , yo soy relativamente nuevo en esto pero con muchas gans de aprender y poder sacarle provecho al kit q tengo y tambien en el foro mostrar ejemplos
Hola, hay muchos tutoriales allá afuera para echar a andar Nios.
Éste te sirve para crear el módulo VHDL con Nios, RAM, JTAG UART y puertos IO...
http://www.4shared.com/office/sSMNVzLh/tut_sopc_introduction.html
Síguelo hasta la página 14.
Luego, para programar el firmware de Nios, sigue este tutorial a partir de la página 36.
http://www.4shared.com/office/Ri9M-ovB/tt_nios2_hardware_tutorial.html
Te sugiero que uses el Hello World compacto para que el código quepa en la RAM de 4kB que sugieren usar. O si quieres usa más RAM.
-
Les dejo el archivo QSF que vincula los pines de la FPGA ya nombrados con nuestro proyecto en la DE0-Nano. Está corregido, ya no arroja el error de que confunde la terminal DCLK del EPCS y permite que Quartus sintetice correctamente.
Error (169187): Following feature(s) of I/O pin ~ALTERA_DCLK~ has invalid setting(s) in the configuration scheme ACTIVE_SERIAL when the pin is placed at pin location H1 Info (169189): I/O feature 'Current Strength' has an invalid setting. The setting should be Default.
-
gracias por los link voy a mirarlos, en la SD encontre ejemplos para nios II
http://www.terasic.com.tw/cgi-bin/page/archive.pl?Language=English&CategoryNo=56&No=372 esta es el kit q tenemos
este es un ejemplo
falta es mirar como pasarlo lo q tenemos a la SD
*****************************************************************************
* File: sd_card.c
*
* This file contains functions for performing general tasks associated
* with the sd card.
*
****************************************************************************/
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include "includes.h"
#include "elca_fat.h"
#include "sd_card.h"
#include "os_utils.h"
// Message boxes for communication with the SD Card task.
OS_EVENT* As_SDCardComMbox;
OS_EVENT* As_SDCardRespMbox;
/*****************************************************************************
* Function: SDChdirLongName
*
* Purpose: Changes directories in the SD Card to a directory with the long
* filename "dirname[]"
*
* Returns: 0 - Success
* -1 - Failure
****************************************************************************/
int SDChdirLongName( char dirname[] )
{
int found_dir = 0;
int ret_code = 0;
char fixed_shortname[16];
// Clear the shortname and longname since the elca_findx functions dont do it for us.
memset( ffblk.ff_longname, 0x0, _MAX_NAME );
memset( ffblk.ff_name, 0x0, 12 );
// Look for any directories who's long or short names match ours
if( elca_findfirst() != 0 ) //Find first file
{
do
{
// Reformat the short filename from the weird way El Camino does it.
SDStringToLower( ffblk.ff_name, fixed_shortname );
if( memchr( fixed_shortname, '.', strlen( fixed_shortname ) ))
{
*((char*)strrchr( fixed_shortname, '.' )) = '\0';
}
if (( ffblk.ff_attr == ATTR_DIRECTORY ) && ( ffblk.ff_name[0] != '.' ))
{
if(( !strcmp( fixed_shortname, dirname )) ||
( !strcmp( ffblk.ff_longname, dirname )))
{
found_dir = 1;
break;
}
}
// Clear the shortname and longname since the elca_findx functions dont do it for us.
memset( ffblk.ff_longname, 0x0, _MAX_NAME );
memset( ffblk.ff_name, 0x0, 12 );
} while( elca_findnext() != 0 ); //Find next file or directory
}
if( found_dir )
{
ret_code = elca_chdir( ffblk.ff_name );
}
else
{
ret_code = -1;
}
return( ret_code );
}
/*****************************************************************************
* Function: SDOpenLongName
*
* Purpose: Opens a file on the SD Card with the long
* filename "filename[]"
*
* Returns: file_handle > 0 - Success
* -1 - Failure
****************************************************************************/
char SDOpenLongName( char filename[], unsigned char attr )
{
int found_file = 0;
char ret_code;
char fixed_shortname[16];
// Look for any directories who's long or short names match ours
if( elca_findfirst() != 0 ) //Find first file
{
do
{
// Reformat the short filename from the weird way El Camino does it.
SDStringToLower( ffblk.ff_name, fixed_shortname );
if (( ffblk.ff_attr == ATTR_FILE ) && ( ffblk.ff_name[0] != '.' ))
{
if(( !strcmp( fixed_shortname, filename )) ||
( !strcmp( ffblk.ff_longname, filename )))
{
found_file = 1;
break;
}
}
} while( elca_findnext() != 0 ); //Find next file or directory
}
if( found_file )
{
ret_code = elca_fopen( ffblk.ff_name, attr );
}
else
{
ret_code = -1;
}
return( ret_code );
}
/*****************************************************************************
* Function: SDStringToLower
*
* Purpose: Converts a string to lower case, and removes any spaces from it.
* The space-removal is neccessary because the El Camino FAT
* fat filesystem code returns short filenames with spaces between
* the filename and the "." if the filename is fewer than 8
* characters
*
* Returns: 0
****************************************************************************/
int SDStringToLower( char src_string[], char dest_string[] )
{
int src_index = 0;
int dest_index = 0;
while( src_string[src_index] != '\0' )
{
if( src_string[src_index] != ' ' )
{
if(( src_string[src_index] >= 'A' ) &&
( src_string[src_index] <= 'Z' ))
{
dest_string[dest_index] = src_string[src_index] + 32;
}
else
{
dest_string[dest_index] = src_string[src_index];
}
dest_index++;
}
src_index++;
}
dest_string[dest_index] = '\0';
return( 0 );
}
/*****************************************************************************
* Function: SDls
*
* Purpose: Parses the contents of the SD directory dir_listing->dirpath
* and returns it in the structure "dir_listing"
*
* Returns: 0 - success
* -1 - failure
****************************************************************************/
int SDls( sdcard_dir_listing* dir_listing )
{
sdcard_com_message sdcard_com_message;
sdcard_resp_message* sdcard_resp_message;
INT8U err;
sdcard_com_message.command = SDCARD_LISTING;
strcpy( sdcard_com_message.filepath, dir_listing->dirpath );
sdcard_com_message.data = (void*)dir_listing;
while( OSMboxPost( As_SDCardComMbox, &sdcard_com_message ) != OS_NO_ERR );
sdcard_resp_message = OSMboxPend( As_SDCardRespMbox, 0, &err );
if( err || sdcard_resp_message->error || dir_listing->error )
{
return( -1 );
}
else
{
return( 0 );
}
}
/*****************************************************************************
* Function: SDChdirAbsPath
*
* Purpose: Changes to an absolute path directory. Supports both long
* and short names. Can also put a filename on the end of the path
* However if you pass in a directory only (no file on end), the
* path must end with a /.
*
* Returns: Number of directory levels descended to reach target directory
*
****************************************************************************/
int SDChdirAbsPath( char abspath[] )
{
int num_levels;
char temppathstaticarray[256];
char* temppath = &(temppathstaticarray[0]);
char tempdir[256];
char* slashptr;
strcpy( temppath, abspath );
for( num_levels = 0; ; num_levels++ )
{
slashptr = strchr( temppath, '/' );
if( !slashptr )
{
// There was no slash in the remaining path, so lets make sure what remains
// is a directory by trying to cd to it.
if( SDChdirLongName( temppath ) == ELCA_F_OK )
{
num_levels++;
}
// If what's left is not a directory, we should return 0 to indicate failure
// But first, we need to walk back up whatever directories we've descended.
else
{
while( num_levels > 0 )
{
elca_chdir( ".." );
num_levels--;
}
}
break;
}
else
{
// Clear tempdir before we copy anything into it since it may contain
// stale data
memset( tempdir, 0x0, 256 );
strncpy( tempdir, temppath, slashptr - temppath );
if( SDChdirLongName( tempdir ) != ELCA_F_OK )
break;
temppath = slashptr + 1;
}
}
return( num_levels );
}
void SDCardTask( void* pdata )
{
int num_levels;
int i;
INT8U err;
char* filename;
char* slashptr;
char tempname[256];
sdcard_com_message* sdcard_com_message;
sdcard_resp_message sdcard_resp_message;
As_SDCardComMbox = OSMboxCreate((void *)0);
As_SDCardRespMbox = OSMboxCreate((void *)0);
// Mount the SD Card. Make 100 attempts before giving up.
for( i = 0; i < 100; i++ )
{
if( elca_fat_mount( PERIPHERAL_SUBSYSTEM_EL_CAMINO_SD_CARD_CONTROLLER_NAME ) >= 0 )
break;
}
if( i == 100 )
{
// OSPrintf("ERROR: Failed to mount %s\n", PERIPHERAL_SUBSYSTEM_EL_CAMINO_SD_CARD_CONTROLLER_NAME );
}
while (1)
{
// Wait for a message asking for SD Card action
sdcard_com_message = OSMboxPend( As_SDCardComMbox, 0, &err );
if ( err == OS_NO_ERR )
{
// Task implementation of elca_fopen
if( sdcard_com_message->command == SDCARD_OPEN )
{
slashptr = strrchr( sdcard_com_message->filepath, '/' );
filename = slashptr + 1;
*slashptr = 0x0;
num_levels = SDChdirAbsPath( sdcard_com_message->filepath );
sdcard_resp_message.file_handle = (char) SDOpenLongName( filename, sdcard_com_message->flag );
if( sdcard_resp_message.file_handle < 0 )
{
sdcard_resp_message.error = SDCARD_ERROR;
}
else
{
sdcard_resp_message.error = 0;
}
// Walk back down the dir tree for next time since el camino doesnt let you
// change back to the root.
for( ; num_levels > 0; num_levels-- )
{
elca_chdir( ".." );
}
}
// Task implementation of elca_filelength
else if( sdcard_com_message->command == SDCARD_FILELENGTH )
{
if( sdcard_com_message->file_handle >= 0 )
{
sdcard_resp_message.num_bytes = elca_filelength( sdcard_com_message->file_handle );
sdcard_resp_message.error = 0;
}
else
{
sdcard_resp_message.error = SDCARD_ERROR;
}
}
// Task implementation of elca_fread
else if( sdcard_com_message->command == SDCARD_READ )
{
if( sdcard_com_message->file_handle >= 0 )
{
sdcard_resp_message.num_bytes = elca_fread( sdcard_com_message->data,
sdcard_com_message->num_bytes,
sdcard_com_message->file_handle );
sdcard_resp_message.error = 0;
}
else
{
sdcard_resp_message.error = SDCARD_ERROR;
}
}
// Task implementation of elca_fclose
else if( sdcard_com_message->command == SDCARD_CLOSE )
{
// El Camino provides no error detection capability for closing a file, so
// we'll just do it blindly.
elca_fclose( sdcard_com_message->file_handle );
}
else if( sdcard_com_message->command == SDCARD_LISTING )
{
sdcard_dir_listing* dir_listing = (sdcard_dir_listing*)sdcard_com_message->data;
dir_listing->num_found = 0;
num_levels = SDChdirAbsPath( sdcard_com_message->filepath );
if( num_levels > 0 )
{
// El Camino does not clean the name fields between "finds", so we do it manually.
memset( ffblk.ff_longname, 0x0, _MAX_NAME );
// Find all the sub-dirs in the app root dir
if( elca_findfirst() != 0 ) //Find first file
{
i = 0;
do
{
// Save off our directory name, because it gets overwritten when we
// look at the files contained within it.
if( ffblk.ff_longname[0] != 0 )
{
strcpy( tempname, ffblk.ff_longname );
}
// If the name was a short filename only, El Camino does not copy it to the
// longname structure element, so we need to go get the short name and format
// it properly.
else
{
// Deal with the strange way El Camino formats the short filename.
SDStringToLower( ffblk.ff_name, tempname );
// Remove the '.' from the end of the name if it's a dir.
if(( memchr( tempname, '.', _MAX_NAME )) &&
( ffblk.ff_attr == ATTR_DIRECTORY ))
{
*((char*)strrchr( tempname, '.' )) = '\0';
}
}
strcpy( dir_listing->filenames, tempname );
i++;
// El Camino does not clean the name fields between "finds", so we do it manually.
memset( ffblk.ff_longname, 0x0, _MAX_NAME );
} while ( elca_findnext() != 0 ); //Find next file or directory
}
// Walk back down the dir tree for next time since el camino doesnt let you
// change back to the root.
for( ; num_levels > 0; num_levels-- )
{
elca_chdir( ".." );
}
dir_listing->num_found = i;
dir_listing->error = 0;
sdcard_resp_message.error = 0;
}
else
{
sdcard_resp_message.error = SDCARD_ERROR;
}
}
while( OSMboxPost( As_SDCardRespMbox, &sdcard_resp_message ) != OS_NO_ERR );
}
}
}
char SDOpen( char fullfilename[], unsigned char flag )
{
sdcard_com_message sdcard_com_message;
sdcard_resp_message* sdcard_resp_message;
INT8U err;
sdcard_com_message.command = SDCARD_OPEN;
sdcard_com_message.flag = flag;
strcpy( sdcard_com_message.filepath, fullfilename );
while( OSMboxPost( As_SDCardComMbox, &sdcard_com_message ) != OS_NO_ERR );
sdcard_resp_message = OSMboxPend( As_SDCardRespMbox, 0, &err );
if( err || sdcard_resp_message->error )
{
return( -1 );
}
else
{
return( sdcard_resp_message->file_handle );
}
}
int SDFilelength( char filehandle )
{
sdcard_com_message sdcard_com_message;
sdcard_resp_message* sdcard_resp_message;
INT8U err;
sdcard_com_message.command = SDCARD_FILELENGTH;
sdcard_com_message.file_handle = filehandle;
while( OSMboxPost( As_SDCardComMbox, &sdcard_com_message ) != OS_NO_ERR );
sdcard_resp_message = OSMboxPend( As_SDCardRespMbox, 0, &err );
if( err || sdcard_resp_message->error )
{
return( -1 );
}
else
{
return( sdcard_resp_message->num_bytes );
}
}
unsigned int SDRead( char* buffer, unsigned int bytecount, char filehandle )
{
sdcard_com_message sdcard_com_message;
sdcard_resp_message* sdcard_resp_message;
INT8U err;
sdcard_com_message.command = SDCARD_READ;
sdcard_com_message.file_handle = filehandle;
sdcard_com_message.data = buffer;
sdcard_com_message.num_bytes = bytecount;
while( OSMboxPost( As_SDCardComMbox, &sdcard_com_message ) != OS_NO_ERR );
sdcard_resp_message = OSMboxPend( As_SDCardRespMbox, 0, &err );
if( err || sdcard_resp_message->error )
{
return( 0 );
}
else
{
return( sdcard_resp_message->num_bytes );
}
}
void SDClose( char filehandle )
{
sdcard_com_message sdcard_com_message;
sdcard_resp_message* sdcard_resp_message;
INT8U err;
sdcard_com_message.command = SDCARD_CLOSE;
sdcard_com_message.file_handle = filehandle;
while( OSMboxPost( As_SDCardComMbox, &sdcard_com_message ) != OS_NO_ERR );
sdcard_resp_message = OSMboxPend( As_SDCardRespMbox, 0, &err );
// There is no error detection for closing a file, so we do nothing here.
}
-
gracias por los link voy a mirarlos, en la SD encontre ejemplos para nios II
http://www.terasic.com.tw/cgi-bin/page/archive.pl?Language=English&CategoryNo=56&No=372 esta es el kit q tenemos
Ah ese kit lo teníamos en mi anterior trabajo, pero mi jefe nunca lo usó, siempre lo tuvo arrumbado... :x
-
si, hombre una pregunta se debe sacar las licencias ps por el quartus II y por la librerias
me imagino es q aca tenemos uno el de prueba que dura 30 dias y en su concepto personal q tal es el kit
-
Yo uso Quartus II 11.1 y no hace falta licencia para compilar para Cyclone IV.
Para los que sí hace falta licencia es para la Cyclone I por ejemplo. También si se usa Quartus II 8.0, pero la licencia es gratis dándose de alta en altera.com.
El kit DE0-Nano es muy bueno, sobre todo para los principiantes que queremos entender las cosas desde cero.