|
|
Circuito auxiliar para Leer y escribir tarjetas
MMC (MultiMedia Card)
|
|

|
Descripción:
|
|
|
|
|
Circuito:
|
- El hardware que estoy utilizando es el
que corresponde al esquema que podéis ver mas abajo:
|
|
|
|
 |
|
|
-
El diseño de este
hardware lo he realizado dándome algunas miles de vueltas por la Web,
por el Foro TODOPIC y por el CCS C Forum. Pero quizás el que mas me ha
influido es el que aparece en la página
Captain Universe realizado con un PIC 16F876A (antiguo y buen
amigo este PIC) que yo he adaptado a mi 18F2550 de la iACV1.
|
|
|
|

|
- La fuente de 3.3 está
construida alrededor de un LT1585CT3.3 que los amables señores de
Linear tuvieron a
bien enviarme como sample el pasado mes de Noviembre de 2006. Los
dos condensadores de 10 uF son los que el Datasheet recomienda
como necesarios para el buen funcionamiento del regulador.
|
- Las señales SPI a manejar son
DI (Data Input) DO (Data Output) CK (Clock) y
CS (Slave Select Input) todas ellas de 3.3V
|
- Como DO es la única que va
desde la MMC hacia el PIC y éste reconoce cualquier señal por
encima de unos 2.0V como un HIGH no tenemos que hacerle nada para
conectarlo, pero las demás tienen el sentido contrario, desde el PIC
hacia la MMC, por lo que deben reducir su voltaje de 5V a
3.3V. Por ello construimos un
divisor
de tensión alrededor de las resistencias R1 y R4 para CK,
R2 y R5 para DI y R3 y R6 para CS. Los
valores de 1K8 y 3K3 utilizados hacen que los 5V de
la señal del PIC pasen a ser nuestros 5*3300/(3300+1800)=3.24V.
|
Circuito Impreso:
|
|
|
|

|
- Con esto el Hardware está descrito, y
como os comenté mas arriba no he llegado a fabricar el PCB sino que lo
he montado sobre una placa de taladros, pero siguiendo el mismo esquema,
y ¡funciona! (podéis verla mas abajo)
|
Implementación
provisional para pruebas:
|
|
|
|
 |
|
|
|
 |
|
|
|
 |
|
|
Firmware inicial para
pruebas:
|
- La comunicación entre el PIC y la
MMC Card se realiza mediante el protocolo Síncrono SPI. Como
el PIC 18F2550 dispone de un modo de funcionamiento de la USART
específico para el SPI parecería lógico usarlo y en paz, pero el
hardware de la placa iACV1
tiene la USART dedicada a sus comunicaciones con el módulo Ethernet
Tibbo EM202 así que
lo que he decidido es emular la comunicación SPI por software. No
ocupa mucho y funciona correctamente.
|
- Todo el protocolo está construido
alrededor del Driver de CCS C "mmc_spi.c" que podéis encontrar en
el directorio Drivers de la instalación de dicho
compilador.
|
- Lo único importante a tener en cuenta
al usar este driver es configurar los defines que dicen qué pines vamos
a utilizar para cada una de las funciones SPI (DO, DI, CK y CS) "antes"
del include del driver <mmc_spi.c> ya que en caso contrario estos
defines no tendran efecto al ser compilados "después" que el
código del driver.
|
- En mi caso concreto he optado por usar
los primeros pines del PORTB (que además son los que tengo
disponibles en las clemas de la iACV1):
|
#define MMC_CS PIN_B3
#define MMC_CLK PIN_B2
#define MMC_DI PIN_B0
#define MMC_DO PIN_B1
|
- Os pongo la cabecera con las funciones
disponibles en el driver CCS C:
|
////////////////////// Driver for
Multimedia Card ///////////////////////
//// ////
//// mmc_init() - Reset and Initialize the MMC. Returns zero if OK ////
//// ////
//// mmc_modify_byte(address, val) - Modify the byte at address to ////
//// change it's value to val. Will read/write the ////
//// entire 512 byte block but only change this ////
//// specific byte. Returns zero if OK. ////
//// ////
//// mmc_modify_block(address, size, *ptr) - Modifies the bytes ////
//// to change their value to whats stored at *ptr. ////
//// Will read/write the entire 512 byte block(s) but ////
//// only change the values defined by ptr and size. ////
//// Returns zero if OK. ////
//// ////
//// mmc_write_block(address, size, *ptr) - Writes a 512 byte ////
//// block to the MMC. If size is less than 512 then ////
//// unspecified data will be written as 0. Returns ////
//// zero if OK. ////
//// ////
//// mmc_read_byte(address,*ptr) - Reads the byte specified at ////
//// address. Result is saved to ptr. Returns zero ////
//// if OK. ////
//// ////
//// mmc_read_block(address, size, *ptr) - Reads the bytes ////
//// specified at address. Result is saved to ptr. ////
//// Returns zero if OK. ////
//// NOTE: You might get an address error if you try ////
//// to read over a page size. For example, trying ////
//// to read a block size of 512 starting at address ////
//// 0x100 may cause an error because you are reading ////
//// two blocks. ////
//// ////
//// mmc_erase(address, blocks) - Erases the block specified at ////
//// address. Will erase the entire 512 byte block. ////
//// If you wish to erase more blocks after specified ////
//// block use the blocks parameter to specifiy how ////
//// many extra blocks to erase. Returns zero if OK. ////
//// ////
//// ~~~~~~~ MULTI-READ FUNCTIONS ~~~~~~~~ ////
//// ////
//// mmc_read_enable(address, size) - Start multi-reads at ////
//// specified address. Size is the size of each ////
//// individual read. Returns zero if OK. ////
//// ////
//// mmc_read_mult_block(*ptr) - Reads data from the MMC, and saves ////
//// to ptr. The number of bytes read is defined ////
//// by mmc_read_enable(). You must call ////
//// mmc_read_enable() before you can call this. ////
//// Returns zero if OK. ////
//// ////
//// mmc_read_disable(void) - Stop a multi-read. ////
//// Returns zero if OK. ////
//// MAY BE BROKEN. ////
//// ////
/////////////////////////////////////////////////////////////////////////
//// (C) Copyright 1996,2001 Custom Computer Services ////
//// This source code may only be used by licensed users of the CCS ////
//// C compiler. This source code may only be distributed to other ////
//// licensed users of the CCS C compiler. No other use, ////
//// reproduction or distribution is permitted without written ////
//// permission. Derivative programs created using this software ////
//// in object code form are not restricted in any way. ////
///////////////////////////////////////////////////////////////////////// |
|
Descargar rr_mmc_spi.c
|
- Con este driver en uso he construido
un Firmware inicial que solo inicializa la MMC Card y que lee
bloques de información sobre un buffer de 512 bytes de
largo.
|
- Las lecturas se realizan
secuencialmente desde la address 0 en adelante en saltos de 512 bytes.
Tened en cuenta que estoy usando:
- 1º.- Un driver directo, sin
utilizar información sobre formateo lógico como puede ser un FAT16
o un FAT32.
- 2º.- La MMC Card que estoy
usando estaba ya en uso en una cámara digital o un móvil por lo
que la información que contiene está formateada y no sé cuál puede
ser.
|
- El firmware versión v.0.0.0 es
(Le he quitado lo relativo a hacer funcionar el Led, el Buzzer y el Rele
del que dispone el hardware iACV1) :
|
////////////////////////////////////////////////////////////////////////////////////
//
// MMC Card Test ...
// by RedPic
////////////////////////////////////////////////////////////////////////////////////
#include <18f2550.h>
#fuses
HS,MCLR,NOWDT,NOPROTECT,NOPUT,NOBROWNOUT,NOPBADEN,NOLVP,NOCPD,NODEBUG,NOWRT,NOVREGEN
#use delay(clock=20000000)
#define EM202_MD PIN_A0
#define EM202_RST PIN_A1
#define EM202_CTS PIN_A2
#define EM202_RTS PIN_A3
#define EM202_DTR PIN_A4
#define EM202_DSR PIN_A5
#define EM202_RX PIN_C6
#define EM202_TX PIN_C7
#define LED PIN_C0
#define BUZZER PIN_C1
#define RELE PIN_C2
#use rs232(baud=19200, xmit=EM202_RX, rcv=EM202_TX)
char cRec=0x00; // Último caracter recibido
via serie
char Command=0x00; // Comando a procesar
int8 MMCBuffer[512];
int32 address=0;
#define MMC_CS PIN_B3
#define MMC_CLK PIN_B2
#define MMC_DI PIN_B0
#define MMC_DO PIN_B1
#include "rr_mmc_spi.c"
////////////////////////////////////////////////////////////////////////////////////
//
// Funciones ...
//
////////////////////////////////////////////////////////////////////////////////////
void Cursor(char c){
printf("%c\r\n>",c);
}
void Presenta_Hardware(void){
printf("\r\n\n");
printf("MMC MultiMedia Card Driver Test\r\n");
printf("Hardware iACCESS CONTROL V1 v.0.0.0\r\n\n");
printf("Commands when available:\r\n\n");
printf("[X] Reset EM202 Ethernet Module\r\n");
printf("[M] Init MMC Card\r\n");
printf("[F] Read MMC Card Block First\r\n");
printf("[R] Read MMC Card Block Actual\r\n");
printf("[ ] Read MMC Card Block Next\r\n\n");
Cursor(0x00);
}
void Reset_EM202(void){
OUTPUT_HIGH(EM202_MD);
OUTPUT_HIGH(EM202_RST);
delay_ms(110);
OUTPUT_LOW(EM202_RST);
delay_ms(110);
}
////////////////////////////////////////////////////////////////////////////////////
//
// Interrupción por Recepción Serie RS232
//
////////////////////////////////////////////////////////////////////////////////////
#int_rda
void handle_rda_int(){
if(kbhit()){ // Si hay algo pdte de recibir
...
cRec=getc(); // lo recibo sobre cRec ...
if(cRec!=0x00){ // Si es distinto de \0 ...
Command=ToUpper(cRec); // cargo cRec sobre Command
para procesarlo
} // pasándolo a Mayúsculas para
no confundir.
}
}
////////////////////////////////////////////////////////////////////////////////////
//
// Main
//
////////////////////////////////////////////////////////////////////////////////////
void main() {
int16 f=0;
int16 size=512;
int8 col=0;
disable_interrupts(global);
disable_interrupts(int_timer1);
disable_interrupts(int_rda);
disable_interrupts(int_ext);
disable_interrupts(int_ext1);
disable_interrupts(int_ext2);
setup_adc_ports(NO_ANALOGS);
setup_adc(ADC_OFF);
setup_spi(FALSE);
setup_counters(RTCC_INTERNAL,RTCC_DIV_2);
setup_timer_0(RTCC_OFF);
setup_timer_1(T1_INTERNAL | T1_DIV_BY_1);
setup_timer_2(T2_DISABLED,0,1);
setup_timer_3(T3_DISABLED);
setup_comparator(NC_NC_NC_NC);
setup_vref(FALSE);
port_b_pullups(false);
set_tris_a(0b00001000);
set_tris_c(0b10000000);
enable_interrupts(global);
enable_interrupts(int_rda);
Reset_EM202();
address=0;
do {
if(Command!=0x00){ // Si he recibido un comando
vía Serie ...
if(Command=='?'){ // Si el comando es '?' ...
Presenta_Hardware();
}
if(Command=='X'){ // Reset EM202
Cursor(Command);
Reset_EM202();
}
if(Command=='M'){ // Inicializa MMC Card
Cursor(Command);
if(mmc_init()==0)
printf("MMC init ok");
else
printf("MMC init fault");
Cursor(0x00);
}
if(Command=='F'){ // Read First Block MMC Card
address=0;
Command='R';
}
if(Command==' '){ // Read Next Block MMC Card
address+=512;
Command='R';
}
if(Command=='R'){ // Read Block MMC Card
Cursor(Command);
for(f=0;f<=511;f++) MMCBuffer[f]=0;
size=511;
col=0;
if(mmc_read_block(address, size,&MMCBuffer[0])==0){
printf("\r\n>MMC read ok from Address %LX to %LX\r\n",address,address+size);
for(f=0;f<=511;f++){
printf("%X ",MMCBuffer[f]);
if(++col==16){
col=0;
printf("\r\n");
}
}
}
else
printf("\n\rread fault");
Cursor(0x00);
}
Command=0x00; // Indico que ya he procesado
el comando.
}
} while (TRUE);
}
|
- Y como ejemplo de su funcionamiento os
pego de nuevo la imagen en la que encontré una referencia a la FAT16
con que parece ser está formateada la MMC Card que estoy usando:
|
|
 |