APLICACIONES AVANZADAS CON C18 ( II )
SD CARD/FAT
Autor: Suky
www.micros-designs.com.ar
2011
Autor: Suky
www.micros-designs.com.ar
2011
Licencia. Casanova Alejandro ([www.micros-designs.com.ar][inf.pic.suky@live.com.ar]) Algunos derechos reservados:
Obra liberada bajo licencia Creative Commons by-nc-sa. Reconocimiento - NoComercial - CompartirIgual (by-nc-sa): En cualquier explotación de la obra autorizada por la licencia haría falta reconocer la autor/a. La explotación de la obra queda limitada a usos no comerciales. La explotación autorizada incluye la creación de obras derivadas siempre que mantengan la misma licencia al ser divulgadas. Más información: http://es.creativecommons.org/licencia/
Autor: Suky
www.micros-designs.com.ar
2011
Introducción. En este artículo se pretende dar los pasos necesarios como para poder utilizar las librerías FAT implementadas por Microchip en un proyecto utilizando MPLAB C18. Al igual que para USB debemos tener instalado la aplicación Microchip Solution. También siguiendo la misma estructura que el artículo anterior debemos establecer cuál es el hardware con el cual se va a trabajar, en este caso el corazón es un PIC18F2620:
Creación del proyecto. Para el proyecto utilizando USB partimos de uno de los ejemplos que nos provee Microchip y a partir de él trabajamos sobre nuestro ejemplo en particular. En este caso lo vamos a realizar de manera distinta para dar una alternativa cuando se necesita utilizar varios stack en un mismo proyecto, de esa manera entenderemos cómo integrarlos. Si abrimos la carpeta Microchip Solutions v2010-10-19 nos vamos a encontrar con una gran cantidad de carpetas, pero en este caso debemos enfocarnos en dos (2), Microchip y MDD File System-SD Card (por ejemplo), este ultimo donde se encuentra ubicado el proyecto ejemplo. Dentro de Microchip nos encontramos con varias carpetas en donde cada una de ellas contiene los archivos fuentes de las librerías implementadas y una en particular llamada include con los archivos cabeceras. Ahora, dentro de la carpeta del proyecto, nos vamos a encontrar con el archivo fuente principal y archivos cabeceras necesarios para establecer el hardware que disponemos y la configuración a implementar en la librería a utilizar, por ejemplo en este caso existe el archivo FSconfig.h. Como se explico para implementar el USB Framework de Microchip, las librerías están conformadas de tal manera que existen un par de archivos que establecen el modo de funcionamiento y que en el proceso de compilación son accedidos de forma global. Ahora bien, las carpetas y archivos que debemos copiar son los siguientes:
Autor: Suky
www.micros-designs.com.ar
2011
..\Microchip\MDD File System
..\Microchip\PIC18 salloc ..\ Microchip\Include\MDD File System
..\Microchip\Include\PIC18 salloc .. \Microchip\Include ..\ MDD File System-SD Card\PIC18F
CF-Bit transaction CF-PMP Fs Phys Interface Template FSIO Internal Flash SD-SPI salloc CF-Bit transaction CF-PMP Fs Phys Interface Template FSIO Internal Flash SD-SPI TEMPLATEFILE salloc Compiler GenericTypeDefs HardwareProfile FSconfig
Y con ellos creamos la siguiente estructura de archivos para nuestros proyectos:
Donde, dentro de Proyecto SDCardFAT, creamos el proyecto con MPLAB IDE y nuestro main.c. Luego agregamos los archivos al proyecto, los mínimos necesarios para este caso son:
Autor: Suky
www.micros-designs.com.ar
2011
A partir de la estructura de archivos creada debemos establecer los Path necesarios para que el compilador sepa dónde buscar. Una forma de pensarlo es, “parados” en la ubicación de la carpeta del proyecto (donde se encuentra *.mpc), determinar la dirección que debemos tomar para encontrar el archivo cabecera que se incluye. De esta manera, resolviendo la dirección para que encuentre el archivo cabecera salloc.h, el Path sería: ..\Microchip\Include\PIC18 salloc De igual manera establecemos todos los que sean necesarios, en este caso resulta:
Autor: Suky
www.micros-designs.com.ar
2011
Adecuando el proyecto a nuestro hardware. Para ello debemos modificar o crear un nuevo archivo HardwareProfile.h, en él hay que definir la frecuencia del Clock del sistema, que tipo de interface utilizaremos para establecer comunicación con la memoria Sd Card y dependiendo de ello los pines a utilizar. Entre las interface tenemos:
USE_SD_INTERFACE_WITH_SPI. Utiliza el modulo SPI para la comunicación. USE_CF_INTERFACE_WITH_PMP. Utiliza el modulo PMP para la comunicación. USE_MANUAL_CF_INTERFACE. La comunicación se realizar por software.
Dependiendo de la elección depende el archivo que hay que incluir al proyecto, entre SD-SPI.c/.h, CFPMP.c/.h o CF-Bit transaction.c/.h. Por ejemplo para nuestro caso el archivo quedaría:
Autor: Suky
www.micros-designs.com.ar
2011
#ifndef _HARDWAREPROFILE_H_ #define _HARDWAREPROFILE_H_ // Define your clock speed here #define GetSystemClock() 10000000 // System clock frequency (Hz) Fosc=40MHz #define GetPeripheralClock() GetSystemClock() // Peripheral clock freq. #define GetInstructionClock() GetSystemClock() // Instruction clock freq. // Description: Macro used to enable the SD-SPI physical layer (SD-SPI.c and .h) #define USE_SD_INTERFACE_WITH_SPI #ifdef USE_SD_INTERFACE_WITH_SPI #define USE_PIC18 #define USE_SD_INTERFACE_WITH_SPI #define INPUT_PIN #define OUTPUT_PIN
1 0
// Chip Select Signal #define SD_CS #define SD_CS_TRIS
PORTCbits.RC0 TRISCbits.TRISC0
// Card detect signal #define SD_CD #define SD_CD_TRIS
PORTCbits.RC1 TRISCbits.TRISC1
// Write protect signal #define SD_WE PORTCbits.RC2 #define SD_WE_TRIS TRISCbits.TRISC2 // Registers for the SPI module you want to use #define SPICON1 SSPCON1 #define SPISTAT SSPSTAT #define SPIBUF SSPBUF #define SPISTAT_RBF SSPSTATbits.BF #define SPICON1bits SSPCON1bits #define SPISTATbits SSPSTATbits #define SPI_INTERRUPT_FLAG PIR1bits.SSPIF // Defines for the HPC Explorer board #define SPICLOCK TRISCbits.TRISC3 #define SPIIN TRISCbits.TRISC4 #define SPIOUT TRISCbits.TRISC5 // Latch pins for SCK/SDI/SDO lines #define SPICLOCKLAT LATCbits.LATC3 #define SPIINLAT LATCbits.LATC4 #define SPIOUTLAT LATCbits.LATC5 // Port pins for SCK/SDI/SDO lines #define SPICLOCKPORT PORTCbits.RC3 #define SPIINPORT PORTCbits.RC4 #define SPIOUTPORT PORTCbits.RC5 Autor: Suky
www.micros-designs.com.ar
2011
#define SPIENABLE
SSPCON1bits.SSPEN
// Will generate an error if the clock speed is too low to interface to the card #if (GetSystemClock() < 400000) #error System clock speed must exceed 400 kHz #endif #endif //************************************************************************************* #endif
Para trabajar con la memoria SD Card, la librería utiliza dos buffer de 512 bytes que debemos reservar para ello, como sabemos esto lo realizamos modificando el *.lkr del microcontrolador que utilizamos. En este caso queda: LIBPATH . FILES c018i.o FILES clib.lib FILES p18f2620.lib CODEPAGE CODEPAGE CODEPAGE CODEPAGE CODEPAGE CODEPAGE
NAME=vectors NAME=page NAME=idlocs NAME=config NAME=devid NAME=eedata
START=0x0 END=0x29 PROTECTED START=0x2A END=0xFFFF START=0x200000 END=0x200007 PROTECTED START=0x300000 END=0x30000D PROTECTED START=0x3FFFFE END=0x3FFFFF PROTECTED START=0xF00000 END=0xF003FF PROTECTED
ACCESSBANK NAME=accessram START=0x0 END=0x7F DATABANK NAME=gpr0 START=0x80 END=0xFF DATABANK NAME=gpr1 START=0x100 END=0x1FF DATABANK NAME=gpr2 START=0x200 END=0x2FF DATABANK NAME=gpr3 START=0x300 END=0x3FF DATABANK NAME=gpr4 START=0x400 END=0x4FF DATABANK NAME=gpr5 START=0x500 END=0x5FF DATABANK NAME=gpr6 START=0x600 END=0x6FF DATABANK NAME=buffer1 START=0x700 END=0x8FF PROTECTED DATABANK NAME=buffer2 START=0x900 END=0xAFF PROTECTED DATABANK NAME=gpr11 START=0xB00 END=0xBFF DATABANK NAME=gpr12 START=0xC00 END=0xDFF PROTECTED DATABANK NAME=gpr14 START=0xE00 END=0xEBF DATABANK NAME=sfr14 START=0xEC0 END=0xEFF PROTECTED DATABANK NAME=sfr15 START=0xF00 END=0xF7F PROTECTED ACCESSBANK NAME=accesssfr START=0xF80 END=0xFFF PROTECTED SECTION NAME=dataBuffer RAM=buffer1 SECTION NAME=FATBuffer RAM=buffer2 SECTION NAME=CONFIG ROM=config STACK SIZE=0x200 RAM=gpr12
Autor: Suky
www.micros-designs.com.ar
2011
Creamos 2 DATABANK de 512 bytes ubicados en 0x700 y 0x900, y con ello definimos 2 SECTION de nombre dataBuffer y FATBuffer. Hay que tener en cuenta las direcciones donde se encuentran, pues en el archivo FSconfig.h debemos establecerlas.
Configurando la implementación FAT Para determinar que alcance tendrá nuestro proyecto en el uso del sistema de archivos FAT debemos trabajar sobre FSconfig.h, en él podemos determinar por ejemplo, con cuantos archivos podremos trabajar al mismo tiempo, si trabajaremos con directorios, si utilizaremos funciones para búsqueda de archivos o directorios, si usaremos FAT32, etc. A continuación se detallan las opciones, tener en cuenta que su selección afectará directamente en el uso de la memoria RAM y ROM.
FS_MAX_FILES_OPEN: Cantidad máxima de archivos que se permite abrir para trabajar a la vez. Sólo es aplicable cuando la asignación de memoria dinámica no se utiliza (FS_DYNAMIC_MEM no está definido). MEDIA_SECTOR_SIZE: Define el tamaño del sector en el sistema de archivos FAT. ALLOW_FILESEARCH: Habilita el uso de funciones de búsqueda tales como FindFirst y FindNext. ALLOW_WRITES: Habilita las funciones que permite realizar escritura sobre el dispositivo. ALLOW_FORMATS: Habilita la función FSformat que permite realizar el formateo del dispositivo. ALLOW_DIRS: Permite trabajar con directorios habilitando las funciones FSmkdir y FSrmdir. ALLOW_PGMFUNCTIONS: Únicamente para C18, lo que permite utilizar funciones adicionales que permiten ingresar como argumento string en rom. ALLOW_FSFPRINTF: Habilita el uso de la función FSfprintf. SUPPORT_FAT32: Soporta dispositivos con FAT32. FS_DYNAMIC_MEM: Habilita la asignación de los objetos FSFILE de forma dinámica. Si no se crean en un arreglo estático.
Luego nos permite seleccionar el modo en el que trabajará para establecer la fecha y hora en los archivos, tenemos 3 opciones:
USEREALTIMECLOCK: Utiliza el modulo RTC del microcontrolador (No valido para PIC18) USERDEFINEDCLOCK: El usuario establece los valores, para ello se habilita la función SetClockVars. INCREMENTTIMESTAMP: Cuando no interesa los valores de fecha y hora del archivo se utiliza este caso.
También, como mencionamos anteriormente, encontramos la definición de la posición en donde se encuentra los buffer dentro de la memoria:
DATA_BUFFER_ADDRESS FAT_BUFFER_ADDRESS
Las funciones implementadas.
FindFirst Función de búsqueda inicial FindNext Función de búsqueda secuencial FSattrib Cambiar los atributos de un archivo
Autor: Suky
www.micros-designs.com.ar
2011
FSchdir Cambia el directorio actual de trabajo FSCreateMBR Crea un registro de inicio maestro FSerror Devolver un código de error para la última función FSfclose Actualización de la información del archivo y libera el objeto FSFILE FSfopen Abrir un archivo. FSformat Formatea un dispositivo. FSfprintf Para escribir cadenas con formato en un archivo. FSfread Leer datos de un archivo. FSfwrite Escribir datos en un archivo FSgetcwd Obtener el nombre del directorio de trabajo actual FSInit Función para inicializar el dispositivo. FSmkdir Para crear un directorio. FSremove Para borra un archivo. FSrename Para renombrar un archivo. FSrmdir Para borrar un directorio. SetClockVars Para establecer manualmente Fecha y Hora del archivo.
Para detalles de cada una de las funciones, revisar el Help que se puede encontrar en ..\Microchip Solutions v2010-10-19\Microchip\Help
Implementación. En mi caso para lograr trabajar con la SD Card realice algunas modificaciones en cómo se trabaja con las inicializaciones del módulo SPI cuando se inicia el dispositivo. Originalmente la librería no implementa el cambio de velocidades de SPI, sino que comienza con la máxima y eso no permite inicializar la memoria. Así que dentro el archivo fuente SD-SPI.c buscar la función OpenSPIM y realizar la siguiente modificación: #ifdef USE_ALTERNATIVE_CONFIG_SPI void OpenSPIM (unsigned char sync_mode){ switch(sync_mode){ case SYNC_MODE_FAST: OpenSPI(SPI_FOSC_4, MODE_11, SMPMID); break; case SYNC_MODE_MED: OpenSPI(SPI_FOSC_16, MODE_11, SMPMID); break; case SYNC_MODE_SLOW: OpenSPI(SPI_FOSC_64, MODE_11, SMPMID); break; } } #else #ifdef __18CXX void OpenSPIM (unsigned char sync_mode) #else void OpenSPIM( unsigned int sync_mode) Autor: Suky
www.micros-designs.com.ar
2011
#endif { SPISTAT = 0x0000;
// power on state
#ifndef __PIC32MX__ SPICON1 = 0x0000; SPICON1 |= sync_mode; #endif
// power on state // select serial mode
#ifdef __18CXX SPICON1 |= 0x80; SPISTATbits.CKE = 1; #else SPICON1bits.CKP = 1; SPICON1bits.CKE = 0; #endif SPICLOCK = 0; SPIOUT = 0; SPIIN = 1; SPIENABLE = 1;
// define SDO1 as output (master or slave) // define SDI1 as input (master or slave) // enable synchronous serial port
} #endif
Como verán utilizo las funciones propias de C18 para la configuración del módulo SPI, por lo que hay que agregar #include <spi.h> , además he creado una definición que hay que agregar a HardwareProfile.h para que seleccione esta opción, USE_ALTERNATIVE_CONFIG_SPI. Dentro del main se puede realizar algo como lo que sigue: #include <p18f2620.h> //****************************************************************************** #pragma config OSC=HSPLL #pragma config IESO=OFF #pragma config PWRT=ON #pragma config WDT=OFF #pragma config MCLRE=ON #pragma config XINST=OFF #pragma config DEBUG=OFF #pragma config FCMEN = OFF #pragma config LVP=OFF #pragma config BOREN=OFF #pragma config PBADEN = OFF //****************************************************************************** #include <delays.h> #include "FSIO.h" //****************************************************************************** char MyBuffer[100]="Creación de archivo mediante libreria de Microchip\r\nby Suky..."; char Fecha,Mes,Hora,Minuto,Segundo; int Anio; //****************************************************************************** Autor: Suky
www.micros-designs.com.ar
2011
void main(void){ FSFILE *MyFile; char Nombre[20], mode[3]; unsigned char err,k; char *Sc;
Delay10KTCYx(250); Delay10KTCYx(250); k=0; do{ Delay10KTCYx(50); err=FSInit(); k++; }while((k<10) && (err==FALSE)); if((k==10) && (err==FALSE)){ // Error... }else{ sprintf(&Nombre[0],"ARCHIVO.TXT"); // w+ Abre archivo para escritura, si existe sobre-escribe // a+ Abre archivo para escritura, si existe continua agregando datos al final. sprintf(&mode[0],"w+"); MyFile = FSfopen(Nombre,mode); for(Sc=&MyBuffer[0];*Sc!=0;Sc++); k=Sc-&MyBuffer[0]; Fecha=31;Mes=7;Anio=2011;Hora=15;Minuto=30;Segundo=45; SetClockVars(Anio,Mes,Fecha,Hora,Minuto,Segundo); // Actualizamos datos... FSfwrite(&MyBuffer[0], 1, k, MyFile); FSfclose(MyFile); } while(1); } El resultado de ello es:
Autor: Suky
www.micros-designs.com.ar
2011
Autor: Suky
www.micros-designs.com.ar
2011
Autor: Suky
www.micros-designs.com.ar
2011
Autor: Suky
www.micros-designs.com.ar
2011