View Full Version : Giao tiếp card MMC ?
doianhve
22-06-2007, 09:46 AM
Xin chào các cao thủ.Tôi đang nghiên cứu giao tiếp card MMC thông qua chuẩn truyền SPI mà thấy khó ghê.Ai có tài liệu hay kinh nghiệm gì share tôi với.Thanks.
falleaf
22-06-2007, 11:40 AM
Card đó tên tuổi là gì? SPI thì cơ bản phải xem nó mắc dây như thế nào, và nó cho phép chuẩn như thế nào. Còn mọi thứ thì oki thôi, nên phải có cái datasheet về cái card thì mới biết được.
Chúc vui
doianhve
22-06-2007, 12:45 PM
Xin chào mội người.Tôi dùng thẻ MMC64MB của Samung.Giao Tiếp SPI.Data Sheet thi tìm trên mạng .Nhiều lắm.
doianhve
22-06-2007, 12:59 PM
Để cho việc thảo luận sôi nổi tôi xin đưa ra kết quả sơ bộ cho mọ người tham khảo.Đây là mã code tôi dùng để xử lý Card.Xin nói qua là code dùng một phần thư viện có sẵn LCD.c của CCS để kiểm tra dữ liệu.Tôi dùng Proteus nhưng chưa mô phỏng được.bạn cần mạch thật.
Cần chú ý:
+LCD sử dụng bit:
// D0 enable
// D1 rs
// D2 rw
// D4 D4
// D5 D5
// D6 D6
// D7 D7
+MMC nối dúng chuẩn SPI có sẵn trên PIC và chon Pin_C2 làm chân CE
Mọi nguoi Down ve và cho ý kiến nhé.Tôi dùng code của Microchip và đã sửa lỗi chạy thử.
doianhve
22-06-2007, 01:00 PM
-----file chinh-----------
#include <E:\Read_Card\16F877.h> // da doi thu tu PortD de phu hop mach in
#fuses HS,NOWDT,NOPROTECT,NOLVP
#use delay(clock=20000000)
#use rs232(baud=9600, xmit=PIN_A3, rcv=PIN_A2) // Jumpers: 11 to 17, 12 to 18
#include <E:\Read_Card\lcd_driver.c>
#include <E:\Read_Card\spi.c>
void main() {
int Kiem_Tra;
kiem_tra=1;
lcd_init();
//setup_spi(SPI_MASTER | SPI_H_TO_L | SPI_CLK_DIV_16);
//F la khoi xoa man hinh va ghi tu dong 1
//n la xuong dong
while(true)
{
kiem_tra=mmc_init();
lcd_putc("\fChan doi qua 456\n");
if (!kiem_tra)
{
lcd_putc("Wait...\n");
mmc_write_block(100);
mmc_read_block(100);
}
delay_ms(2000);
}
}
doianhve
22-06-2007, 01:01 PM
-----------------------lcd_driver.c---------------
// As defined in the following structure the pin connection is as follows:
// D0 enable
// D1 rs
// D2 rw
// D4 D4
// D5 D5
// D6 D6
// D7 D7
//
// LCD pins D0-D3 are not used and PIC D3 is not used.
// Un-comment the following define to use port B
// #define use_portb_lcd TRUE
struct lcd_pin_map { // This structure is overlayed
BOOLEAN enable; // on to an I/O port to gain
BOOLEAN rs; // access to the LCD pins.
BOOLEAN rw; // The bits are allocated from
BOOLEAN unused; // low order up. ENABLE will
int data : 4; // be pin B0.
} lcd;
#if defined(__PCH__)
#if defined use_portb_lcd
#byte lcd = 0xF81 // This puts the entire structure
#else
#byte lcd = 0xF83 // This puts the entire structure
#endif
#else
#if defined use_portb_lcd
#byte lcd = 6 // on to port B (at address 6)
#else
#byte lcd = 8 // on to port D (at address 8)
#endif
#endif
#if defined use_portb_lcd
#define set_tris_lcd(x) set_tris_b(x)
#else
#define set_tris_lcd(x) set_tris_d(x)
#endif
#define lcd_type 2 // 0=5x7, 1=5x10, 2=2 lines
#define lcd_line_two 0x40 // LCD RAM address for the second line
BYTE const LCD_INIT_STRING[4] = {0x20 | (lcd_type << 2), 0xc, 1, 6};
// These bytes need to be sent to the LCD
// to start it up.
// The following are used for setting
// the I/O port direction register.
struct lcd_pin_map const LCD_WRITE = {0,0,0,0,0}; // For write mode all pins are out
struct lcd_pin_map const LCD_READ = {0,0,0,0,15}; // For read mode data pins are in
BYTE lcd_read_byte() {
BYTE low,high;
set_tris_lcd(LCD_READ);
lcd.rw = 1;
delay_cycles(1);
lcd.enable = 1;
delay_cycles(1);
high = lcd.data;
lcd.enable = 0;
delay_cycles(1);
lcd.enable = 1;
delay_us(1);
low = lcd.data;
lcd.enable = 0;
set_tris_lcd(LCD_WRITE);
return( (high<<4) | low);
}
void lcd_send_nibble( BYTE n ) {
lcd.data = n;
delay_cycles(1);
lcd.enable = 1;
delay_us(2);
lcd.enable = 0;
}
void lcd_send_byte( BYTE address, BYTE n ) {
lcd.rs = 0;
while ( bit_test(lcd_read_byte(),7) ) ;
lcd.rs = address;
delay_cycles(1);
lcd.rw = 0;
delay_cycles(1);
lcd.enable = 0;
lcd_send_nibble(n >> 4);
lcd_send_nibble(n & 0xf);
}
void lcd_init() {
BYTE i;
set_tris_lcd(LCD_WRITE);
lcd.rs = 0;
lcd.rw = 0;
lcd.enable = 0;
delay_ms(15);
for(i=1;i<=3;++i) {
lcd_send_nibble(3);
delay_ms(5);
}
lcd_send_nibble(2);
for(i=0;i<=3;++i)
lcd_send_byte(0,LCD_INIT_STRING[i]);
}
void lcd_gotoxy( BYTE x, BYTE y) {
BYTE address;
if(y!=1)
address=lcd_line_two;
else
address=0;
address+=x-1;
lcd_send_byte(0,0x80|address);
}
void lcd_putc( char c) {
switch (c) {
case '\f' : lcd_send_byte(0,1);
delay_ms(2);
break;
case '\n' : lcd_gotoxy(1,2); break;
case '\b' : lcd_send_byte(0,0x10); break;
default : lcd_send_byte(1,c); break;
}
}
char lcd_getc( BYTE x, BYTE y) {
char value;
lcd_gotoxy(x,y);
while ( bit_test(lcd_read_byte(),7) ); // wait until busy flag is low
lcd.rs=1;
value = lcd_read_byte();
lcd.rs=0;
return(value);
}
doianhve
22-06-2007, 01:02 PM
-------------------------------SPI.c-------------------------
// for the original source, and hundreds more examples of PIC C code, see:
// http://www.microchipc.com/sourcecode/#mmc
int8 Nhay_dong;
char str[80];
int mmc_init();
int mmc_response(unsigned char response);
int mmc_read_block(unsigned long block_number);
int mmc_write_block(unsigned long block_number);
int mmc_get_status();
/************************** MMC Init **************************************/
/* Initialises the MMC into SPI mode and sets block size, returns 0 on success */
int mmc_init()
{
int i;
SETUP_SPI(SPI_MASTER | SPI_H_TO_L | SPI_CLK_DIV_4 | SPI_SS_DISABLED);
*0x94 |= 0x40; // set CKE = 1 - clock idle low
*0x14 &= 0xEF; // set CKP = 0 - data valid on rising edge
OUTPUT_HIGH(PIN_C2); // set SS = 1 (off)
for(i=0;i<10;i++) // initialise the MMC card into SPI mode by sending clks on
{
SPI_WRITE(0xFF);
}
OUTPUT_LOW(PIN_C2); // set SS = 0 (on) tells card to go to spi mode when it receives reset
SPI_WRITE(0x40); // send reset command
SPI_WRITE(0x00); // all the arguments are 0x00 for the reset command
SPI_WRITE(0x00);
SPI_WRITE(0x00);
SPI_WRITE(0x00);
SPI_WRITE(0x95); // precalculated checksum as we are still in MMC mode
lcd_putc("\fSent go to SPI\n\r");
if(mmc_response(0x01)==1) return 1; // if = 1 then there was a timeout waiting for 0x01 from the mmc
lcd_putc("Got response from MMC\n\r");
i = 0;
while((i < 255) && (mmc_response(0x00)==1)) // must keep sending command if response
{
SPI_WRITE(0x41); // send mmc command one to bring out of idle state
SPI_WRITE(0x00); // all the arguments are 0x00 for command one
SPI_WRITE(0x00);
SPI_WRITE(0x00);
SPI_WRITE(0x00);
SPI_WRITE(0xFF); // checksum is no longer required but we always send 0xFF
i++;
}
if(i >= 254) return 1; // if >= 254 then there was a timeout waiting for 0x00 from the mmc
lcd_putc("\fGot out of idle response from MMC\n\r");
OUTPUT_HIGH(PIN_C2); // set SS = 1 (off)
SPI_WRITE(0xFF); // extra clocks to allow mmc to finish off what it is doing
OUTPUT_LOW(PIN_C2); // set SS = 0 (on)
SPI_WRITE(0x50); // send mmc command one to bring out of idle state
SPI_WRITE(0x00);
SPI_WRITE(0x00);
SPI_WRITE(0x02); // high block length bits - 512 bytes
SPI_WRITE(0x00); // low block length bits
SPI_WRITE(0xFF); // checksum is no longer required but we always send 0xFF
if((mmc_response(0x00))==1) return 1;
OUTPUT_HIGH(PIN_C2); // set SS = 1 (off)
lcd_putc("\fGot set block length response from MMC\n\r");
return 0;
}
/************************** MMC Get Status **************************************/
/* Get the status register of the MMC, for debugging purposes */
int mmc_get_status()
{
OUTPUT_LOW(PIN_C2); // set SS = 0 (on)
SPI_WRITE(0x58); // send mmc command one to bring out of idle state
SPI_WRITE(0x00);
SPI_WRITE(0x00);
SPI_WRITE(0x00); //
SPI_WRITE(0x00); // always zero as mulitples of 512
SPI_WRITE(0xFF); // checksum is no longer required but we always send 0xFF
OUTPUT_HIGH(PIN_C2); // set SS = 1 (off)
return 0;
}
/************************** MMC Write Block **************************************/
int mmc_write_block(unsigned long block_number)
{
unsigned long i;
unsigned long varh,varl;
varl=((block_number&0x003F)<<9);
varh=((block_number&0xFFC0)>>7);
puts("Write block\n\r"); // block size has been set in mmc_init()
OUTPUT_LOW(PIN_C2); // set SS = 0 (on)
SPI_WRITE(0x58); // send mmc write block
/*
SPI_WRITE(HIGH(varh));
SPI_WRITE(LOW(varh));
SPI_WRITE(HIGH(varl));
*/
SPI_WRITE(0x1001); // arguments are address
SPI_WRITE(0x1011);
SPI_WRITE(0x100);
SPI_WRITE(0x00); // always zero as mulitples of 512
SPI_WRITE(0xFF); // checksum is no longer required but we always send 0xFF
if((mmc_response(0x00))==1) return 1;
puts("Got response to write block\n\r");
SPI_WRITE(0xFE); // send data token
//----------------Ghi du lieu vao MMC-----------------
strcpy(str,"Nguyen Duc Hung_Dl1_K47_DHBKHN"); ///Ghi vao the nho
nhay_dong=0;
for(i=0;i<512;i++)
{
++nhay_dong;
SPI_WRITE(str[Nhay_Dong]); // send data
if (nhay_dong>=32)
{
nhay_dong=0;
}
}
SPI_WRITE(0xFF); // dummy CRC
SPI_WRITE(0xFF);
if((SPI_READ(0xFF)&0x0F)!=0x05) return 1;
puts("Got data response to write block\n\r");
OUTPUT_HIGH(PIN_C2); // set SS = 1 (off)
return 0;
}
/************************** MMC Read Block **************************************/
/**** Reads a 512 Byte block from the MMC and outputs each byte to RS232 ****/
int mmc_read_block(unsigned long block_number)
{
unsigned long i;
unsigned long varh,varl;
varl=((block_number&0x003F)<<9);
varh=((block_number&0xFFC0)>>7);
OUTPUT_LOW(PIN_C2); // set SS = 0 (on)
SPI_WRITE(0x51); // send mmc read single block command
SPI_WRITE(0x1001); // arguments are address
SPI_WRITE(0x1011);
SPI_WRITE(0x100);
SPI_WRITE(0x00);
SPI_WRITE(0xFF); // checksum is no longer required but we always send 0xFF
if((mmc_response(0x00))==1) return 1; // if mmc_response returns 1 then we failed to get a 0x00 response (affirmative)
lcd_putc("Got response to read block command\n\r");
if((mmc_response(0xFE))==1) return 1; // wait for data token
//---------------------------------------doc tu the len-------------------
nhay_dong=0;
lcd_putc("\fGot data token\n\r");
lcd_putc("\f"); //Xoa Man Hinh
for(i=0;i<512;i++)
{
++nhay_dong;
lcd_putc(SPI_READ(0xFF)); // we should now receive 512 bytes
if (nhay_dong==16)
{
lcd_putc("\n");
lcd_putc(SPI_READ(0xFF)); // we should now receive 512 bytes
}
if (nhay_dong>=31)
{
lcd_putc("\n");
nhay_dong=0;
lcd_putc("\f");
}
delay_ms(100);
}
SPI_READ(0xFF); // CRC bytes that are not needed
SPI_READ(0xFF);
OUTPUT_HIGH(PIN_C2); // set SS = 1 (off)
SPI_WRITE(0xFF); // give mmc the clocks it needs to finish off
lcd_putc("End of read block");
return 0;
}
/************************** MMC get response **************************************/
/**** Repeatedly reads the MMC until we get the response we want or timeout ****/
int mmc_response(unsigned char response)
{
unsigned long count = 0xFFFF; // 16bit repeat, it may be possible to shrink this to 8 bit but there is not much point
while(SPI_READ(0xFF) != response && --count > 0);
if(count==0) return 1; // loop was exited due to timeout
else return 0; // loop was exited before timeout
}
doianhve
23-06-2007, 11:52 AM
alo.Ko ai nói j à.Chán ghê.
bien_van_khat
05-07-2007, 11:22 AM
Các bạn post code thì nên bỏ vào trong thẻ [code] để vậy đọc ko nổi. Lần này mình sửa dùm bạn, nhưng ko có lần sau nhé.
Chính xác vấn đề mà bạn gặp phải là gì, mình cũng đã làm MMC ở mode SPI rồi, có gì mình có thể giúp bạn. Vấn đề lớn nhất mà mình gặp phải là cái connector, vì đồ chế nên tiếp xúc ko tốt lúc chạy lúc ko, đành phải hi sinh 1 cái đầu đọc thẻ để tháo mỗi cái connector.
bluepine
16-07-2007, 10:04 AM
Xin chào các cao thủ.Tôi đang nghiên cứu giao tiếp card MMC thông qua chuẩn truyền SPI mà thấy khó ghê.Ai có tài liệu hay kinh nghiệm gì share tôi với.Thanks.
Chào bạn,
tôi gửi bạn một số tài liệu tham khảo rất có ích cho bạn khi bắt đầu nghiên cứu MMC card qua giao tiếp SPI. Tôi cũng đang tịm hiểu về MMC card, chúng ta có thể trao đổi thêm.
http://elm-chan.org/docs/mmc/mmc_e.html
http://www.hcilab.org/projects/particles/particles-mmc.htm
http://forum.microchip.com/tm.aspx?m=58980&mpage=3
Thân.
batinh
28-08-2007, 11:08 AM
tôi sử dụng 18F4550 thì khai báo có gì khác không mà sao làm mấy ngày rồi không đc. SD card với LCD.
quyenemic
30-08-2007, 05:25 PM
Bài viết hay đó, cảm ơn bạn.
tui chơi quả AVR giao tiếp với thẻ nhớ. Chạy ngon, file đọc được ngon nhưng chẳng biết làm gì với nó cả. trừ file text cho hiển thị lcd. Nói chung viết với Vdk nào thì cũng vậy thôi, có điều là mình làm thế nào thì nó mới đưa cho mình dữ liệu (giải thuật). Để ghi dữ liệu vào hay đọc dữ liệu ra theo một sector thì đơn giản hơn những gì bạn tưởng. Chỉ đến khi nào bạn muốn làm việc với file thì lúc đó vấn đề mới thực sự bắt đầu. Tôi lằng nhằng mãi với cái đống FAT, rdet, sdet, bootsector...mãi mới ra, giờ thì cũng thông rồi. Các bạn cứ làm đi, có gì tôi biết tôi có thể chỉ cho các bạn.
Bạn chú ý khi mắc phần cứng, tay MMC làm việc với điện áp 3.3v cho nên bạn đấu cẩn thận. Nguồn 5V cho qua 2 thằng diode mới được đưa vào thẻ nhớ. (5-0.7*2 = 3.4 ~3.3). Mức 1 ở VDK là 5V, khi đưa mức 1 này vào thẻ cũng cần qua cầu phân áp cho nó còn khoảng 3.3 v mới dc. Tôi chưa thử phi 5V vào nên chẳng biết là sẽ có chuyện gì sảy ra. Nhưng nói chung là không nên. Hì hì
Bạn đừng hỏi nhiều quá, bắt tay vào làm từ ABC, đến đâu không biết bắt đầu mới hỏi. Như vậy thì mình mới hiểu sâu vấn đề dc.
namqn
01-12-2007, 04:56 PM
...
Nguồn 5V cho qua 2 thằng diode mới được đưa vào thẻ nhớ. (5-0.7*2 = 3.4 ~3.3). ...
5 - 0.7*2 = 3.6 chứ. Các giải pháp rẻ tiền tạo nguồn 3.3 V từ nguồn 5 V tôi đã nói ở post #21 trong luồng sau:
http://www.picvietnam.com/forum/showthread.php?t=401&page=2
Thân,
hì, quên. Nếu chơi sang làm hẳn con IC gì gì đó về tạo nguồn 3.3V , cái đó tui cũng chưa biết, trước tới giờ toàn chơi 2 chú 1n4007. Hì hì
minhtienbk
17-01-2008, 12:24 AM
cái này tui nghĩ nó có thể thay thế com ROM rất ok , 1 mạch thu thập dữ liệu , lưu vào đó , sau 1 thời gian , lấy thẻ ra , cắm vào máy tính hay DTDD , rồi đọc dữ liệu đó , hình ảnh , hay âm thanh , hay biểu đồ , có lẽ vậy là ứng dụng dc vài thế mạnh của nó ... , còn ai siêu thì lưu mp3 vô hát ( mắc hơn đi mua máy mp3)
còn tạo ra 3.3v , thì chỉ cần 1 con zenner 3.3v , hé hé , cái này học trc khi học BJT
PIC_Phan
17-01-2008, 03:28 PM
Ổn áp 3V3 cho MMC card nên dùng con BA033T cho ổn định, nếu dùng zenner ghim áp lỡ "giữa đường đứt gánh" thì toi cái thẻ!!
#include<16f877a.h>
#include<def_877a.h>
// Speihersutz121345=aus,Debug11=aus,ProgrammFlash9=a n,EEpromRead8=an,NiendervoltProgr7=aus
// NiederVoltReset6=an,EinschaltTimer3=an,WachDogTime r2=aus,Oszilator01=XC
#fuses HS,NOWDT,NOPROTECT,NOLVP
#use delay(clock=4000000)
#use rs232 (baud=4800 , parity = N , xmit=pin_C6 , rcv=pin_C7 )
#bit CS = PORTC.2 //Ausgang für Chip Select
#bit SCK = PORTC.3 //Ausgang Clock
#bit SDO = PORTC.5 //Ausgang Daten Output
#bit SDI = PORTC.4 //Eingang Daten Input
#byte temp = 0x31
#bit temp_7 = temp.7
#byte temp1 = 0x32
#bit temp1_0 = temp1.0
#define bls 20
int mmc_init();
int mmc_response(unsigned char response);
int mmc_read_block(int32 add,int result);
int1 mmc_write_block(int32 add,int tem);
int mmc_get_status();
#INT_RDA // Ham xu ly ngat noi tiep
void Receive_isr()
{
int c;
c = fgetc();
printf("%d",c);
}
/*-------------------------------------------------------------------------*/
int1 command(int8 bef,long adrh,long adrl,int8 bes)
{spi_write(0xff);
spi_write(bef);
spi_write(make8(adrh,1));
spi_write(make8(adrh,0));
spi_write(make8(adrl,1));
spi_write(make8(adrh,0));
spi_write(bes);
spi_write(0xff);
return (spi_read(0xff));
}
/************************** MMC Init **************************************/
/*
Initialises the MMC into SPI mode and sets block size, returns 0 on success */
int mmc_init()
{
long i;
SETUP_SPI(SPI_MASTER | SPI_l_TO_h | SPI_CLK_DIV_16);
*0x94 |= 0x40; // set CKE = 1 - clock idle low
*0x14 &= 0xEF; // set CKP = 0 - data valid on rising edge
cs=1; // set SS = 1 (off)
for(i=0;i<1000;i++) // initialise the MMC card into SPI mode by sending clks on
{
SPI_WRITE(0xff);
}
cs=0; ;
// set SS = 0 (on) tells card to go to spi mode when it receives reset
i=20;
while((command(0x40,0,0,0x95)!=1)&&(i>0)) { command(0x40,0,0,0x95);--i; }
if(i==0) return 1;
// precalculated checksum as we are still in MMC mode
puts("Sent go to SPI\n\r");
// if = 1 then there was a timeout waiting for 0x01 from the mmc
puts("Got response from MMC\n\r");
i = 0;
while((i < 255) && (spi_read(0xff)==0))
// must keep sending command if response
{
SPI_WRITE(0x41);
// send mmc command one to bring out of idle state
SPI_WRITE(0x00);
// all the arguments are 0x00 for command one
SPI_WRITE(0x00);
SPI_WRITE(0x00);
SPI_WRITE(0x00);
SPI_WRITE(0xFF);
// checksum is no longer required but we always send 0xFF
i++;
}
if(i >= 254) return 1;
// if >= 254 then there was a timeout waiting for 0x00 from the mmc
puts("Got out of idle response from MMC\n\r");
OUTPUT_HIGH(PIN_C2);
// set SS = 1 (off)
SPI_WRITE(0xFF);
// extra clocks to allow mmc to finish off what it is doing
OUTPUT_LOW(PIN_C2);
// set SS = 0 (on)
SPI_WRITE(0x50);
// send mmc command one to bring out of idle state
SPI_WRITE(0x00);
SPI_WRITE(0x00);
SPI_WRITE(0x00);
// high block length bits - 512 bytes
SPI_WRITE(0x14);
// low block length bits
SPI_WRITE(0xFe);
// checksum is no longer required but we always send 0xFF
if((mmc_response(0x00))==1) return 1;
OUTPUT_HIGH(PIN_C2); // set SS = 1 (off)
puts("Got set block length response from MMC\n\r");
return 0;
}
/************************** MMC Get Status **************************************/
/* Get the status register of the MMC, for debugging purposes */
int mmc_get_status()
{
OUTPUT_LOW(PIN_C2);
// set SS = 0 (on)
SPI_WRITE(0x58);
// send mmc command one to bring out of idle state
SPI_WRITE(0x00);
SPI_WRITE(0x00);
SPI_WRITE(0x00);
//
SPI_WRITE(0x00);
// always zero as mulitples of 512
SPI_WRITE(0xFF);
// checksum is no longer required but we always send 0xFF
OUTPUT_HIGH(PIN_C2);
// set SS = 1 (off)
return 0;
}
/*---------------------------------------------------------------------------*/
int1 mmc_write_sector(int32 add,int temp)
{int32 j;
int8 val,tg;
j=add;
output_low(pin_c2);
SPI_WRITE(0x58);
// send mmc write block
SPI_WRITE(make8(j,3));
SPI_WRITE(make8(j,2));
SPI_WRITE(make8(j,1));
SPI_WRITE(make8(j,0));
SPI_WRITE(0x00);
SPI_WRITE(0xff);
if(spi_read(0xff)!=0x05) return 1;
SPI_WRITE(0xff);
spi_write(0xfe); //crc
for(tg=20;tg>0;--tg) Spi_write(temp);
spi_write(0xff); //crc
spi_write(0xff); //crc
if(!(mmc_response(0x00)&&0x1f)==0x05) return 1;
printf("ok da 1 xong\n\r");
output_high(pin_c2);
return 0;
}
/*---------------------------------------------------------------------------*/
int mmc_read_block(int32 add,int result)
{
int32 i;
int8 tg;
i=add;
output_low(pin_c2);
spi_write(0x51);
SPI_WRITE(make8(i,3));
SPI_WRITE(make8(i,2));
SPI_WRITE(make8(i,1));
SPI_WRITE(make8(i,0));
SPI_WRITE(0x00);
SPI_WRITE(0xff);
if(spi_read(0xff)!=0) return 1;
printf("da doc\n\r");
for(tg=20;tg>0;--tg) result=spi_read(0xff);
spi_write(0xff); //crc
spi_write(0xff); //crc
Output_high(Pin_c2);
spi_write(0xff);
return result;
}
/************************** MMC get response **************************************/
/**** Repeatedly reads the MMC until we get the response we want or timeout ****/
int mmc_response(unsigned char response)
{
unsigned long count = 0xFFFF;
// 16bit repeat, it may be possible to shrink this to 8 bit but there is not much point
while(SPI_READ(0xFF) != response && --count > 0);
if(count==0) return 1; // loop was exited due to timeout
else return 0; // loop was exited before timeout
}
void main()
{
int add,hi,m;
char i,temp;
TRISC=0xc3;
trisb=0x00;
portc=0x00;
i=2;
add=1024;
enable_interrupts(int_rda);
enable_interrupts(GLOBAL);
mmc_init();
if(mmc_init()==0) printf("Hello PIC Viet Nam!\n\r ");
else
printf("chan qua! ");
}
cho em hỏi code của em sai tại đâu mà không thể khởi tạo được MMC. Tức phản hồi R1 của MMC luôn #0x01
chán quá
Hem ai quan tâm tới vẫn đề này nữa sao??????????????
bien_van_khat
29-11-2008, 11:12 AM
- Sơ đồ mạch của bạn như thế nào? Trước tiên phải chắc chắn mạch của bạn đúng.
- Bắt đầu từ command nào, thẻ ko phản hồi, hoặc phản hồi sai?
debugger
30-11-2008, 12:08 AM
chán quá
Hem ai quan tâm tới vẫn đề này nữa sao??????????????
chào bạn bogu, hình như bạn copy đoạn code này của một thằng Tây nào đúng không. Code của nó không chạy là vì thế này: để đợi cái Respond 0x01 thì biến đếm i=20 là quá nhỏ, bạn cho to lên cỡ vài nghìn, hoặc vài chục nghìn là chạy ngay (trừ khi phần cứng của bạn có vấn đề). Nhớ là là phải dùng kiểu int16 nhá. Chúc bạn may mắn. À quên, mình có viết một thư viện đọc/ghi/liệt kê/tạo mới/xóa file và thư mục trên thẻ nhớ theo định dạng fat32, tốc độ rất nhanh và chắc chắn dễ dùng hơn của mấy ông Tây kia nhiều... bạn cần thì cứ cho ý kiến nhá.
Em thử mô phỏng trên Proteus7.2
Ngay từ command 1 nó đã không nhận rồi
Em kiẻm tra Response R1 nó đã khác 1
làm đi làm lại mãi rùi, mà kể cả cho "i=5000" luôn, như lời debugger cũng hem được nữa
Nản quá! Đại ca nào giúp em với! :((
À wên em gởi lun theo đây file mô phỏng của anh Yankazaz post lên
Mong các anh hồi âm mau mau nhé
bạn Deugger ơi, còn Onl không
Bạn có thể cho send cho mình cái thư viện đó mau mau được hem, tại thứ 3 tới là phải gặp thầy lần nữa rùi !!!
Cảm ơn bạn trước nhá :D
debugger
30-11-2008, 08:11 AM
Thư viện của mình mới dùng được cho họ MCS-51 và ARM thôi, mình đang port nó sang PIC. Nhưng vấn đề là thư viện của mình sử dụng cache khoảng 2K, trong khi, như bạn biết đấy, RAM của mấy con PIC16 ít quá, lại bị xé lẻ thành nhiều bank. Có lẽ mình sẽ port nó sang thằng PIC24 hoặc 32 thôi.
Để cho nhanh bạn send cho mình cái project của bạn cùng với source code và mô phỏng, mình xem và sửa cho. Mà cái file MMC_PC lúc nãy bạn gửi thiếu file hex và file image
debugger
30-11-2008, 08:57 AM
i=20;
while((command(0x40,0,0,0x95)!=1)&&(i>0)) { command(0x40,0,0,0x95);--i; }
if(i==0) return 1;
Mình xem lại code của bạn rồi, cái vòng while là không ổn. thường thì sau khi nhận lệnh 0x40 trong vòng khoảng 64 chu kì đồng hồ là nó respond lại 0x01 rồi. Bên trong vòng while của bạn lại một command nữa với rất nhiều clock bắn vào mà không kiểm tra từng byte nó bắn ra. Khi đó cái respond 0x01 ra lúc nào mà bạn không biết. Bạn thử sửa lại thế này xem nhá:
command(0x40,0,0,0x95);
i=100;
while(spi_read(0xFF)!= 0x01)
{
if(i== 0) return 1;
i--;
}
Đồng thời sửa lại hàm command sang kiểu void thế này
void command(int8 bef,long adrh,long adrl,int8 bes)
{
spi_write(bef);
spi_write(make8(adrh,1));
spi_write(make8(adrh,0));
spi_write(make8(adrl,1));
spi_write(make8(adrh,0));
spi_write(bes);
}
Debugger ơi, chán quá thử lại rùi mà vẫn không được:(
Hay đã giúp thì giúp cho chót, mình đã post mạch với code rồi đó
bạn có thể sửa code xong mô phỏng luôn xem chạy chưa
Trời ơi, điên đầu với con MMC này gần 5 tuần rồi!!:(
À t đưa luôn file hex với image của anh Yankazza
debugger
01-12-2008, 03:16 PM
Cái file MMC_PC bạn bogu gửi lên làm gì có code, cũng không có file hex và file image của mmc nữa, có mỗi 1 cái file proteus thì làm sao mình chạy được. bạn gửi lại đi
Uh, mình quên.Tại gửi file cardimage sẵn trong file của anh Yankazza, nên mình thui
Mình đã gởi kèm luôn cả project MMC và mạch mô phỏng đó. À mình đọc trên diễn đàn thấy
nói khi khởi tạo MMC phải giữ tốc độ <400K/s sau khi khởi tạo xong mới được tăng lên
cũng chả rõ nữa, nhưng thử luôn rồi mà cũng chẳng xong...hết thuốc cứu???:(
À lại quên nữa mình dùng CCS4.03 lập trình cho PIC. Debugger có chưa, nếu chưa bạn download ở đây nè
http://rs111.rapidshare.com/files/32212183/CCS_PCWH_v4.033.rar
Cảm ơn bạn Debugger nhiệt tình giúp mình nha:)
debugger
03-12-2008, 11:35 AM
Mình sửa cho bạn rồi đấy. Lỗi chính là bạn đấu sai chân và cách đợi time-out. Bạn Xem rồi cho ý kiến nhá. Good luck!
Phải nói thật tình là rất cảm ơn debugger.
Không có bạn chắc tiêu quá:) Tuy vậy...hì hì. Sau nè chắc còn phải làm phiền debugger nhiều nhiều nữa...
quocloc.pham
11-12-2008, 10:08 AM
Mình đang làm giao tiếp giữa micro SD card và 876A, nhưng mình gặp vấn đề giao tiếp 5v và 3.3V giữa SD và PIC, mình định sử dụng 74HC07 hoặc 74HC125 nhưng tìm cả chợ Nhật Tảo mà không thấy dòng HC. Ai biết có chổ nào bán thì chỉ giúp mình với
hay bạn nào có giải pháp nào hay có thể chia sẽ, mình cũng đã thử phân áp nhưng không khả thi
Thân!
debugger
11-06-2009, 11:41 PM
Giới thiệu mọi người một module giao tiếp thẻ nhớ MMC/SD hỗ trợ FAT32 đã hoàn chỉnh của tôi. Module này hỗ trợ hầu hết các chức năng về đọc, ghi, xóa, tạo mới,... với tệp và thư mục lưu trong thẻ nhớ định dạng FAT32.
Đặc biệt module này làm việc với dải điện áp rộng, nuôi bằng 3.3V hoặc 5V đều được nên có thể đầu nối trực tiếp với VĐK chạy 3.3V hoặc 5V mà không cần thông qua bất kì một mạch chuyển đổi điện áp nào cả.
Bạn có thể tham khảo và so sánh với các sản phẩm cùng loại của các hãng khác như
- uMMC của Rogue Robotics (Canada)
- uALFAT của GhiElectronics (USA)
- Serial MMC/SD của Cubloc (Korea)
-----------------------------------------------------------------------------------------------
Mọi chi tiết về sản phẩm xin liên hệ theo email: bvhoang42@yahoo.com
haquang
03-07-2009, 12:48 PM
Em có cái thắc mắc về thẻ MMC, các bác giải đáp giúp em với!
Em có trong tay 1 thẻ MMC Mobile, e muốn làm giao tiếp với nó!Em đang thắc mắc là cái thẻ của em có 13 chân còn các thẻ trong các schematic hướng dẫn chỉ có 7 chân? Không biết có gì khác biệt mà....... chương trình của em mô phỏng thì chạy được nhưng chạy thật thì không init được gì cả!
Các bác giải thích hộ em cái!
Thanks các bác!
debugger
03-07-2009, 11:04 PM
Em có cái thắc mắc về thẻ MMC, các bác giải đáp giúp em với!
Em có trong tay 1 thẻ MMC Mobile, e muốn làm giao tiếp với nó!Em đang thắc mắc là cái thẻ của em có 13 chân còn các thẻ trong các schematic hướng dẫn chỉ có 7 chân? Không biết có gì khác biệt mà....... chương trình của em mô phỏng thì chạy được nhưng chạy thật thì không init được gì cả!
Các bác giải thích hộ em cái!
Thanks các bác!
MMC Mobile thực chất rất giống với MMC. Bạn có thể lên google tìm và tra, rất rõ ràng và chi tiết. Tốt nhất khi bắt đầu bạn nên dùng các loại thẻ phổ biến như MMC, SD. Giá của mấy loại này cũng ko đắt và socket cắm thì cũng sẵn ở chợ. Còn việc bạn Init ko được có nhiều nguyên nhân. Về phần mềm thì bạn có thể down chương trình của mình post ở các bài trươc. Về phần cứng bạn cũng cần chú ý mức điện áp giao tiếp vì các loại thẻ này chạy 3.3V.
haquang
04-07-2009, 12:00 PM
Em vừa lượn 1 vòng chợ trời mà không tìm được cái thẻ MMC 7 chân nào hết! :((
Có 1 vấn đề, e nhận thấy điện áp 2 chân 3 và 4 trên áo của thẻ MMC là 3.3V trước khi cắm thẻ vào nhưng...... khi cắm thẻ thì điện áp lên đến hơn 4V? Đây có phải là nguyên nhân không và làm sao để khắc phục? Các bác giúp em với!
PS: Em dùng IC 1117-33G để tạo điện áp 3.3V. Con này e dùng vài ứng dụng rồi, thấy chạy bình thường:(
nguyenhung1811
08-08-2009, 12:32 PM
lam the nao de tu con pic minh co the tao file text trong the MMC ha cac ban. Cac ban co the huong dan cho minh duoc ko vay. Thanx
debugger
08-08-2009, 05:20 PM
lam the nao de tu con pic minh co the tao file text trong the MMC ha cac ban. Cac ban co the huong dan cho minh duoc ko vay. Thanx
Cách nhanh nhất là bạn dùng FMC32. Nối chân RxD của FMC32 với chân TX của con Pic. Viết đoạn chương trình sau sẽ tạo file txt có tên là newfile.txt trong thẻ nhớ MMC:
void main()
{
delay_ms(1000); // đợi FMC32 khởi động xong
printf("o,rwc,/newfile.txt\r"); // Gửi lệnh tạo file
while(1); // Kết thúc chương trình
}
nguyenhung1811
11-08-2009, 09:54 AM
thế mình có thể viết trực tiếp mà không cần dùng FMC32, pic giao tiếp SPI với MMC card kia`, nếu bạn nào biết xin hướng dẫn giúp mình với. Mình định làm thử một bộ đo nhiệt độ rồi cứ 1 giây nó ghi thời gian và nhiệt độ lên thé, sau đó mình lấy thẻ đem bỏ vào máy tính để xem thông số...
nguyenhung1811
11-08-2009, 03:56 PM
nhu vay minh fai tim hieu ve fat16/32 j do phai ko cac ban?
hotronghieu
05-08-2010, 11:47 PM
bạn debugger có thể gửi đoạn code ví dụ dử dụng fmc 32 bằng covision dc khộng?
mail:tronghieu_spk@yahoo.com
th0001
14-09-2011, 05:26 PM
bác debugger làm ơn chỉ e cách doc một sector đi?.cam on nhiu
th0001
15-09-2011, 05:14 PM
Bac làm ơn chỉ giùm cách đọc một sector hiển thi trên virtual terminal với!
th0001
15-09-2011, 05:28 PM
lệnh spi_read(data);data có nghĩa là gì vậy?
Có lúc thì có data có lúc lại không là sao vậy?
Có ai biết hông chỉ giúp với?.cam on
th0001
17-09-2011, 02:44 PM
không ai giúp????
th0001
18-09-2011, 10:21 AM
???????????
th0001
18-09-2011, 10:21 AM
lệnh spi_read(data);data có nghĩa là gì vậy?
Có lúc thì có data có lúc lại không là sao vậy?
Có ai biết hông chỉ giúp với?.cam on
th0001 đang trong diễn đàn Sửa/Xóa nội dung
th0001
20-09-2011, 06:07 PM
??????????
mynhanxst
28-11-2011, 06:21 PM
#include <16f877a.h>
#DEVICE *=16 CCSICD=TRUE
/// add new open file handling
//// working May 13 2003 with 18F452
//// write append tested for no new cluster append
#fuses HS,NOWDT,NOPROTECT,NOPUT,NOLVP,NOBROWNOUT,NOWRT
#use delay(clock=20 000 000)
#use rs232(baud=9600, bits=8, parity = N, xmit=PIN_C6, rcv=PIN_C7)
#use rs232(DEBUGGER)
#USE FAST_IO(A)
#USE FAST_IO(B)
#USE FAST_IO(C)
#USE FAST_IO(D)
#USE FAST_IO(E)
////////////////
/// test of SPI interface at 40 mz prior to merging into web server
///
/// hardware SDI is C4 SDO is C5 SCK is C3
#DEFINE _CS PIN_C2
#define PIC_MODE PIN_A0 /// NIC or DRAM
#DEFINE MAX_FILES 2 /// max number of open files
#DEFINE MMC_BUFF_SIZE 32 /// 32 for PCM
///////////////////////////// SPI interface for ///////////
// Multi Media Card FAT16 only
// FAT16 is a copyright of Microsoft
// This program was developed for personal use only based on
// information Microsoft placed in the public domain
// The code will read MMC SD cards in SPI mode previously formatted
// on a PC
// To write a file update to cards a 512 byte buffer is required
// to store the existing info from a sector prior to updating
// An append or writing a new sector can be done without the buffer
// THe PIC is at 5v and the MMC at 3.3v ... a 5v 7407 open collector
// buffer is used to level convert with 2.2k pull ups on the SPI lines
// the 3.3v MMC supply is either obtained from the 5v via a 3.3 Vreg
// or is dropped down via a led ( also works as a power on indicator)
// and smoothed via 100 uf cap
//
// the MMC card and the PIC aren't ever in sync so the card has to be polled to
// get the required response. Often a command is just repeated until the CARD responds
// and the card is polled until it sends the data
///////////////////////////////////////////////////////////
//
/// PIN Assignments //////////////////////////////
/// _CS PIN_C2 // chip select for MMC
/// SDO PIN_C5
/// CLK PIN_C3
/// SDI PIN_C4
// SPI hardware pins are
// SDO C5
// SDI C4
// SCK C3
///////////////////////////////////////////////////////////////
///// Note old values needed before all SPI modes could be set up using SPI_setup
/// for 16 parts ///////////
//#DEFINE SSPCON 0x14
//#DEFINE SSPSTAT 0x94
//#BIT SMP=SSPSTAT.7
//#BIT CKE=SSPSTAT.6
//#BIT CKP=SSPCON.4
//#BIT SSPEN=SSPCON.5
//////////////////////////////
// For 18F452
//#DEFINE SSPSTAT 0x0FC7
//#DEFINE SSPCON1 0x0FC6
//#BIT SMP=SSPSTAT.7
//#BIT CKE=SSPSTAT.6
//#BIT CKP=SSPCON1.4
//#DEFINE MAX_FILES 2 /// max number of open files
//#DEFINE MMC_BUFF_SIZE 32 /// 32 for PCM
#DEFINE MMC_FILE_NAME_SIZE 32
#DEFINE ROOT_CLUSTER 0
#DEFINE NEXT_CLUSTER 1
#define MMC_INIT_TRACE FALSE
#define MMC_CMD_TRACE FALSE
#define MMC_CLUSTER_TRACE FALSE // if true prints to serial port
#define MMC_OPEN_TRACE FALSE // if true prints to serial port
#define MMC_READ_TRACE FALSE // if true prints file_addr,cluster index etc
#define MMC_WRITE_TRACE FALSE
#define MMC_READ_BLOCK_TRACE FALSE
#define MMC_SET_BLOCK_LEN_TRACE FALSE
#define MMC_WRITE_BLOCK_TRACE FALSE
#define MMC_NEW_CLUSTER FALSE
////// MMC prototypes
#separate
int init_MMC(int max_tries);
#separate
int open_file(int fnbr,char *fname,int16 rec_length);
#separate
int file_read(int8 fnbr,char *buff);
#separate
int file_write(int8 fnbr,int *buff);
#separate
int file_set(int fnbr,int32 offset);
#separate
int file_new_cluster(int8 fnbr,int8 mode); /// mode 1=fat1 2=fat2
int32 atoint32 (char *s );
signed int strncmp(char *s1, char *s2, int n);
///////////////////// MMC GLOBALS /////////////////////////////
int16 cluster_size_bytes; // bytes in a cluster
//int16 dir_cluster_chain_ptr; // link to the first cluster in the dir
int32 fat1_address; // physical address of fat1 cluster table assigned by INIT_MMC
int32 fat2_address; // physical address of fat2 cluster table assigned by INIT_MMC
int32 root_dir_address; // physical address of volume,file,folder tiles assigned by INIT_MMC
int32 data_area_address; // physical address of data area assigned by INIT_MMC
int32 winhex_adj; // Win hex hides the bytes in the reserved sectors
// this means Fat1 is address 512
// so adj is fat1-512
int32 block_size; // current MMC block size
int MMC_init=FALSE;
int MMC_dir_protected=TRUE;
////////// open file specific globals ///////////////////////
struct
{
char name[MMC_FILE_NAME_SIZE+1]; // fopen file name
int32 dir_addr_ptr; // physical address of this files tile info
int16 root_cluster_ptr; // location of first cluster in FAT
int16 this_cluster_ptr; // location of current cluster in FAT
int16 next_cluster_ptr; // location of the next cluster for a file or sub dir in FAT
int32 addr_ptr; // physical address in the file the current
// cluster points to
// address=(this_chain_ptr-2)*cluster_size_bytes+data_area_address
//
// cluster_addr(THIS_CLUSTER) assigns it
// cluster_addr(NEXT_CLUSTER) moves to the data the next
// cluster points to
int32 size; // size of open file in bytes
int32 cluster_offset; // offset within the file representing the start of the current cluster
// (0 is start and ends with the cluster contianing eof )
// auto increased by cluster_size_bytes each time a new cluster is entered
int32 offset; // current offset into the open file ( 0 is start size(file size) is end)
// auto increased by rec size each time a rec is read
// addr_prt+offset-cluster_offset is physical address of
// the current position within the file
// the physical positions are not always contiguous since the
// clusters of the file are not always adjacent to each other
int16 rec_size; // fopen record_size
// char buff[MMC_BUFF_SIZE+1]; // used for open and for read write
// init MMC uses file 0 buff to fetch the globals
} file[MAX_FILES];
#separate
int mmc_cmd(int8 cmd,int32 address,int8 tries,int8 valid,int8 invalid)
{
int i,r1;
for( i=0;i<16;i++) SPI_READ(0xFF);// digest prior operation
// commands
// 7 6 5 4 3 2 1 0
// 0 1 b b b b b b bbbbbb=cmd
// 16=0x50 set blocklength
// 17=0x51 read block
// 24=0x58 write block
#if MMC_CMD_TRACE
printf("\n\r cmd=%2X \n\r",cmd);
#endif
SPI_READ(cmd);
SPI_READ(MAKE8(address,3));
SPI_READ(MAKE8(address,2));
SPI_READ(MAKE8(address,1));
SPI_READ(MAKE8(address,0));
SPI_READ(0x95);
// card comes up in MMC mode and requires a valid MMC cmd to switch to SPI mode
// valid crc for MMC 0x40 cmd only
// spi mode doesn't require the CRC to be correct just there
for(i=0;i< tries;i++) {
r1=SPI_READ(0xFF);
#if MMC_CMD_TRACE
printf(" %2X",r1);
#endif
if (r1==valid) break;
if (r1==invalid) break;
}
return(r1);
}
#separate
int set_BLOCKLEN( int32 size)
{
int r1;
r1=mmc_cmd(0x50,size,16,0x00,0x40); /// cmd.data,tries,valid code,invalid code
if (r1==0x00) goto done ;
if (r1==0x40) goto invalid;
return(false);
invalid:
#IF MMC_SET_BLOCK_LEN_TRACE
printf("\n\r para err\n\r");
#ENDIF
return(false);
done:
block_size=size; //// assign global block size
//printf("\n\r blk size=%lu",block_size);
return(true);
}
#separate
int read_BLOCK( int32 address, char *buff)
{
//// low level read ..requires block len to be called first to set global blocksize
int r1;
long i,iw; /// allows large gt 255 buff size addressing
//int data[128];
r1=mmc_cmd(0x51,address,16,0x00,0x40);
if (r1==0x00) goto get_token ; // we can read data payload
if (r1==0x40) goto invalid;
#IF MMC_READ_BLOCK_TRACE
printf("\n\r read block err 1 address=%lu \n\r",address);
#ENDIF
return(false);
invalid:
#IF MMC_READ_BLOCK_TRACE
printf("\n\r read block err 2 adress=%lu \n\r",address);
#ENDIF
return(false);
get_token:
for(iw=0;iw<1024;iw++){
r1=SPI_READ(0xFF);
//data[iw]=r1;
if (r1==0xFE) goto read_data; // read token $FE
}
#IF MMC_READ_BLOCK_TRACE
printf("\n\r read block err 3 address=%lu \n\r",address);
#ENDIF
return(false);
read_data:
#IF MMC_READ_BLOCK_TRACE
printf("\n\r read block tries for FE =%lu \n\r",iw);
#ENDIF
for (i=0;i<block_size;i++) buff[i]=SPI_READ(0xFF);
SPI_READ(0xFF); // read crc
SPI_READ(0xFF);
return(true);
}
//////////////////////////////////////////////////////////////////
///////////////////////////////// INIT MMC ///////////////////////
//////////////////////////////////////////////////////////////////
#separate
int init_MMC(int max_tries)
{
int32 start_lsec=0;
int16 sec_resv,sec_for_FAT,bytes_per_sector,root_dir_ent ries,
sec_for_data,count_of_clusters,root_dir_sectors,to tal_sectors;
int i,tries,sec_per_cluster,c;
char buff[32];
tries=0;
cmd0:
///////////////////// place null treminators in globals fname and buff
for(i=0;i<MAX_FILES;i++)
{
file[i].name[0]=0;
file[i].rec_size=32; //// default rec_size = 32 byte tile size of FAT16
}
//buff[MMC_BUFF_SIZE]=0;
//frec_size=32; //// default rec_size = 32 byte tile size of FAT16
output_high(_CS); /// reset chip hardware !!! required
delay_ms(20);
for(i=0;i<20;i++) SPI_READ(0xFF); // min 80 clocks to get MMC ready
output_low(_CS); /// !!! required
delay_ms(20);
#if MMC_INIT_TRACE
printf("cmd0");
#ENDIF
c=mmc_cmd(0x40,0x00000000,128,0x01,0x99);
if (c==0x01) goto exit_cmd1;
// note: i must cycle at least 8 times (16 is safe )
if (tries++<max_tries) goto cmd0; /// restart
else
return (10);
exit_cmd1:
// CPDMOD - This SOMETIMES seems to be necessary
// output_high(_CS);
// SPI_READ(0xFF); // min 8 clocks to get MMC ready
// output_low(_CS);
//CPDMOD End
tries=0;
cmd1:
/// now try to switch to idle mode
/// Note: cmd1(idle) is the only command allowed after a cmd0(reset)
//
c=mmc_cmd(0x41,0x00000000,128,0x00,0x99);
if (c==0x00) { goto ready;}
if( tries++<max_tries) { printf("cmd1"); goto cmd1;}
else return(11);
ready:
//for( i=0;i<32;i++) SPI_READ(0xFF);// digest operation
/// MMC is inialized and in idle state ready for commands
////
//// we need to first access the master boot sector physical address=0
///
if(set_BLOCKLEN((int32)32)==false) return(12); /// sets global block_size to 32
if (read_block(0x00000000,buff)==false) return (99); /// read the first few bytes
#if MMC_INIT_TRACE
printf("\n\r sector0=");
for(i=0;i<32;i++)printf("%2X ",buff[i]);
#ENDIF
if (buff[0]==0xEB || buff[0]==0xE9)
{
/// sector 0 is the boot sector
#if MMC_INIT_TRACE
printf("\n\r boot sector= 0");
#ENDIF
}
else
{
//// partition
/// access the master boot sector physical address 0 at offset 1BE
if (read_BLOCK(0x000001BE,buff)==false) return(13);
#if MMC_INIT_TRACE
for(i=0;i<32;i++)printf("%2X ",buff[i]);
#ENDIF
// start_lsec is address of the partion boot sector
start_lsec=make32(buff[11],buff[10],buff[9],buff[8]);
#if MMC_INIT_TRACE
printf("\n\r boot sector= %lu",start_lsec);
#ENDIF
if (read_BLOCK(start_lsec*512,buff)==false) return(14);
}
bytes_per_sector=make16(buff[12],buff[11]);
if(bytes_per_sector!=512) return(15);
sec_per_cluster=buff[13];
cluster_size_bytes=(int16)sec_per_cluster*bytes_pe r_sector;
sec_resv=make16(buff[15],buff[14]);
root_dir_entries=make16(buff[18],buff[17]);// number of 32 byte tiles
total_sectors=make16(buff[20],buff[19]);
sec_for_FAT=make16(buff[23],buff[22]);
//branch to file directory
fat1_address=(start_lsec+sec_resv)*bytes_per_secto r;
fat2_address=fat1_address+bytes_per_sector*sec_for _FAT;
root_dir_address=(sec_for_FAT*2+start_lsec+sec_res v)*bytes_per_sector;
data_area_address=root_dir_address+root_dir_entrie s*32;
///// check for FAT16
root_dir_sectors=root_dir_entries>>4;
sec_for_data=total_sectors - sec_resv -sec_for_fat*2 -root_dir_sectors;
count_of_clusters=sec_for_data/sec_per_cluster;
if (count_of_clusters <4085 || count_of_clusters>65525) return(17);
winhex_adj=fat1_address-bytes_per_sector;
return(0);
}
#separate
int get_CID(char s)
{int i,r1;
r1=mmc_cmd(0x4A,0x00000000,16,0x00,0x99);
if (r1==0x00) goto get_token ; // we can read data payload
return(false);
get_token:
for(i=0;i<16;i++)if (SPI_READ(0xFF)==0xFE) goto read_CID; // read token $FE
return(false);
read_CID:
for (i=0;i<18;i++)
s[i]=SPI_READ(0xFF);
return(true);
}
#separate
int get_CSD(char s)
{int i,r1;
r1=mmc_cmd(0x49,0x00000000,16,0x00,0x99);
if (r1==0x00) goto get_token ; // we can read data payload
return(false);
get_token:
for(i=0;i<16;i++)if (SPI_READ(0xFF)==0xFE) goto read_CSD; // read token $FE
return(false);
read_CSD:
for (i=0;i<18;i++)
s[i]=SPI_READ(0xFF);
return(true);
}
#separate
int write_BLOCK( int32 address,char *buff,int16 size)
{
/// low level write ....MMC restriction is that exactly 512 bytes must be written
/// so a 512 byte section is read in starting at address the first (size) bytes
/// are over written with the new data and the updated 512 bytes written back
/// the starting address of the block that contains the requeseted address
///
/// the data may span a block if so it is split and two writes are done
/// so as to maitain MMC 512 write boundary restrictions
int r1,a,b,c,d;
int16 i,blk_offset,bytes_posted;
char tmp_buff[512];
int32 block_address;
#if MMC_WRITE_BLOCK_TRACE
printf("addr=%lu",address);
#endif
a=make8(address,3);
b=make8(address,2);
c=make8(address,1);
c=c & 0b11111110;
d=0;
block_address=make32(a,b,c,d); //// address int divided by 512
#if MMC_WRITE_BLOCK_TRACE
printf("wb>> size=%lu payload=",size);
for(i=0;i<size;i++)printf("%c",buff[i]);
#endif
// first set up the block size to 512
if(set_BLOCKLEN((int32)512)==false) return(false); // sets global block_size
if(block_size!=512) return(false);
bytes_posted=0; /// no data updated yet
////////////////////////////////////////////////
next_block: /// loop back here for second block
////////////////////////////////////////////////
#if MMC_WRITE_BLOCK_TRACE
printf("\n\r blk addr=%lu \n\r",block_address);
#endif
if((block_address < data_area_address) && MMC_dir_protected) return(false);
MMC_dir_protected=true;
#if MMC_WRITE_BLOCK_TRACE
printf("read blk");
#endif
/// first read in the existing block
if(read_block(block_address,tmp_buff)==false)
{return(false) ;
}
/// now update the block with new data
blk_offset=(address - block_address); /// offset within the block
#if MMC_WRITE_BLOCK_TRACE
printf("blk_offset=%lu size=%lu",blk_offset,size);
#endif
if( blk_offset + size > 512 )
{
// data spans the block so write to end of block first
#if MMC_WRITE_BLOCK_TRACE
//// original data
printf("\n\r spans wb=");
for(i=blk_offset;i<512;i++)printf("%c",tmp_buff[i]);
#endif
for (i=blk_offset;i < 512;i++)tmp_buff[i]=buff[i-blk_offset];
#if MMC_WRITE_BLOCK_TRACE
/// updated data
printf("\n\r spans wb*=");
for(i=blk_offset;i<512;i++)printf("%c",tmp_buff[i]);
#endif
bytes_posted=512-blk_offset; /// wrote from offset to end of block
#if MMC_WRITE_BLOCK_TRACE
printf("\n\r posted=%lu",bytes_posted);
#endif
}
else
{
//original or remaining spanned block data fits in next block or original block
#if MMC_WRITE_BLOCK_TRACE
printf(" blk offset=%lu",blk_offset);
/// original data
printf("\n\r wb=");
for(i=blk_offset;i<blk_offset+size;i++)printf("%c",tmp_buff[i]);
#endif
for (i=blk_offset;i<blk_offset+ size;i++)tmp_buff[i]=buff[bytes_posted+i-blk_offset];
#if MMC_WRITE_BLOCK_TRACE
/// updated data
printf("\n\r wb*=");
for(i=blk_offset;i<blk_offset+size;i++)printf("%c",tmp_buff[i]);
#endif
bytes_posted=size;
#if MMC_WRITE_BLOCK_TRACE
printf("\n\r posted=%lu",bytes_posted);
#endif
}
///////////////////////////////////
/////////// write out the block
//////////////////////////////////
#if MMC_WRITE_BLOCK_TRACE
printf("wb>> writing block %lu",block_address);
#endif
r1=mmc_cmd(0x58,block_address,16,0x00,0x40);
if (r1==0x00) goto send_token ; // we can send data payload
if (r1==0x40) goto invalid;
return(false);
invalid:
printf("\n\r write block err %2X\n\r",r1);
return(false);
send_token:
SPI_READ(0xFE);
for (i=0;i < 512;i++) {
SPI_READ(tmp_buff[i]); /// send payload
}
SPI_READ(0xFF); // send dummy chcksum
SPI_READ(0xFF);
r1=SPI_READ(0xFF);
for( i=0;i<0x0fff;i++) {
r1=SPI_READ(0xFF);// digest prior operation
if (r1!=0x00) break;
}
if(size > bytes_posted)
{
/// data spanned block so we need to upadte next block as well
size=size-bytes_posted;
block_address=block_address+512;/// advance a block
address=address+bytes_posted; /// move address ptr forward
goto next_block;
}
return(true);
}
#separate
void dump_block()
{
int in_buff[12],c,i,j;
int32 read_address;
char buff[MMC_BUFF_SIZE+1];
for(i=0;i<12;i++)in_buff[i]=0;
printf("\n\r Input Start address:");
j=0;
do {
c=getc();
in_buff[j++]=c;
putc(c);
}while(c!=13);
in_buff[j-1]=0;
read_address=atoint32(in_buff);
if (read_BLOCK(read_address,buff)==true){
printf(" BLOCK\n\r");
for(j=0;j<MMC_BUFF_SIZE;j=j+8)
{
printf("%4LX ",read_address+j);
for(i=0;i<8;i++)printf(" %2X",buff[i+j]);
printf("\n\r");
}
}
else printf("\n\r read_BLOCK failed");
}
#separate
int32 cluster_addr(int fnbr,int mode)
{
int32 address;
char buff[2]; //// buffer for 2 byte ptrs
///// returns the physical address in the data area of the data pointed to by either the
///// root cluster or the next cluster in the chain
/////
///// if ROOT_CLUSTER is called then this routine returns the address of the first cluster
///// and assigns this_cluster_ptr and next_cluster_ptr
/////
///// if NEXT_CLUSTER is called then this routine returns the address of the next cluster
///// using the existing next_cluster ptr number
///// and moves the existing next_cluster ptr number into this_cluster
///// and assigns the new next cluster ptr number (FFFF) if at the end of chain
///// if NEXT_CLUSTER is called and the next_cluster_ptr number is FFFF
///// an address of FFFFFFFF is returned
///// uses the globals cluster_size_bytes,data_area_address
//// file struct has the base=root cluster ptr, current=this cluster ptr ,next =cluster chain ptr
//// !!!! a call with NEXT_cluster must have a valid next_cluster_ptr value
//// !!!! a call to THIS CLUSTER must have a valid this_cluster_ptr
//// !!!! Fopen logic considers the cluster prt in the directory tile
//// to be a next=next_cluster_ptr so NEXT_CLUSTER is used to calc the physical address
//// of the first root cluster this also assigns the current=this_cluster_ptr
/// and fetches the next cluster prt
////
#IF MMC_CLUSTER_TRACE // if true prints to serial port
printf("\n\r cluster addr>> next_cluster_ptr= %lu this_cluster=%lu \r\n",file[fnbr].next_cluster_ptr,file[fnbr].this_cluster_ptr);
#ENDIF
if (mode==NEXT_CLUSTER)
{
///access the next cluster in the chain
/// requires a valid this_cluster_ptr number and a valid next_cluster_ptr number
if(file[fnbr].next_cluster_ptr==0xFFFF)
{
#IF MMC_CLUSTER_TRACE // if true prints to serial port
printf("last cluster");
#ENDIF
address=0XFFFFFFFF;
}
else
{
if(set_BLOCKLEN((int32)2)==false) return(35); /// set up to read 2 bytes
if(read_BLOCK(fat1_address+(file[fnbr].next_cluster_ptr)*2,buff)==false) return(33);
file[fnbr].this_cluster_ptr=file[fnbr].next_cluster_ptr; // update current with prev next in chain
file[fnbr].next_cluster_ptr=make16(buff[1],buff[0]); /// update next in chain
address=((int32)file[fnbr].this_cluster_ptr-(int32)2)*(int32)cluster_size_bytes+
data_area_address;
}
}
if (mode==ROOT_CLUSTER)
{
//// root_cluster_ptr was assigned from the file tile in fopen
file[fnbr].this_cluster_ptr=file[fnbr].root_cluster_ptr;
if(set_BLOCKLEN((int32)2)==false) return(35); /// set up to read 2 bytes
if(read_BLOCK(fat1_address+(file[fnbr].this_cluster_ptr)*2,buff)==false) return(33);
file[fnbr].next_cluster_ptr=make16(buff[1],buff[0]); /// update next in chain
address=((int32)file[fnbr].this_cluster_ptr-(int32)2)*(int32)cluster_size_bytes+
data_area_address;
}
// printf("clust addr call fnbr=%u blk_size=%lu",fnbr,file[fnbr].rec_size);
if(set_BLOCKLEN(file[fnbr].rec_size)==false) return(37); /// reset to original rec_size
#IF MMC_CLUSTER_TRACE // if true prints to serial port
printf("\n\r cluster addr>> next_cluster_ptr*= %lu this_cluster*=%lu \r\n",file[fnbr].next_cluster_ptr,file[fnbr].this_cluster_ptr);
#ENDIF return(address);
}
///////////////////////////////////////////////////////////////////////////////////
///////////////////////// OPEN FILE ///////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////
#separate
int open_file(int fnbr,char *fname,int16 rec_length)
{
int32 dir_addr_ptr;
int16 bytes_read;
int i,ptr1,ptr2,lnf_tiles;
char file_name[12];
int attribute,directory,archive;
char tmp;
char buff[32]; //// buffer for 32 byte tiles
int level; /// level in the directory structure 0 is top
/////// directory is searched and if file is found
//////
////// init_MMC(tries) must be called first
////// uses globals root_dir_address
//start by searching the root directory for folder or file
/// assign an inital next_cluster_ptr in the root directory
file[fnbr].next_cluster_ptr=0;
file[fnbr].this_cluster_ptr=0;
dir_addr_ptr=root_dir_address;
file_name[11]=0;
level=0;
ptr1=0;
ptr2=0;
bytes_read=0; //// byte read so far in this cluster
read_directory:
/// extract the directory levels(folders)
while ((fname[ptr2]!='/') && (fname[ptr2]!='\\') && (fname[ptr2]!='\0') && (fname[ptr2]!='.') )
{
// a dos directory (folder) name can not exceed 8 chars
if ((ptr2-ptr1)>7) return (20);
ptr2++;
}
#IF MMC_OPEN_TRACE
printf("\n\r fopen ptr1=%u ptr2=%u ",ptr1,ptr2);
#ENDIF
if (ptr2==0){ ptr2=1;ptr1=1;goto read_directory;} /// skip a leading '/' or '\'
if ((ptr2-ptr1)==0) return (21);
// ptr1 is the chars processed so far
// ptr2 is the position of '/' or '\' or '.' or '\0'
// prepare the file or directory name fomat is cccccccceee
// c is a valid letter or blank eee is extension or blank
// a directory name is 'cccccccc ' a file 'cccccccceee' always 11 chars
for(i=0;i<11;i++)file_name[i]=32;//blank
file_name[11]=0;
i=0;
while(ptr1<ptr2)
{
// extract the name
tmp=fname[ptr1];
tmp=TOUPPER(tmp);
file_name[i]=tmp;
ptr1++;i++;
}
if(fname[ptr2]=='.')
{
// extract the extension
i=8;
while((fname[ptr1]!='\0') && (i<12))
{
ptr1++;
tmp=fname[ptr1];
file_name[i]=TOUPPER(tmp);
i++;
}
}
ptr1++;
ptr2=ptr1; // advance over the '\' or '/' so next pass starts correctly
if (block_size!=(int32)32)
{
if(set_BLOCKLEN((int32)32)==false) return(17); /// tiles are 32 bytes
}
if (read_BLOCK(dir_addr_ptr,buff)==false) return(10);
// decode the FAT16 entries
// a tile is 32 bytes
// std dos files take one tile
// a long file name has multiple tiles
// starting with the last down to the first and
// then a std dos tile is found
// byte 11 is 0x0f for LNF tiles and 0x00 for std
// we skip the LNF and goto STD tile
tile_decode:
lnf_tiles=0;
if (buff[0]==0xE5) goto next_tile; ///0xE5 is the deleted file flag
if (buff[0]==0x00)
{
printf("\n\r file err [%s] not found \n\r",file_name);
return(11); /// file not found
}
if (buff[11]==0x0F)
{
/// get number of LNF tiles
lnf_tiles=buff[0] & 0b00111111;
bytes_read=bytes_read+lnf_tiles*32;
if(bytes_read>cluster_size_bytes)
{
// compute next cluster address next_cluster_ptr must be valid
// assigns this_cluster_ptr
dir_addr_ptr=cluster_addr(fnbr,NEXT_CLUSTER);
if (dir_addr_ptr==0xFFFFFF) return (22);
bytes_read=bytes_read-cluster_size_bytes;
dir_addr_ptr=dir_addr_ptr+bytes_read;
}
else
{
dir_addr_ptr=dir_addr_ptr+lnf_tiles*32;
}
//advance over the lnf tiles
/// test to see if we need next cluster in chain
if (read_BLOCK(dir_addr_ptr,buff)==false) return(31);
/// !!! may read into next sector
}
/// check out the standard DOS tile
#IF MMC_OPEN_TRACE
printf("\n\r fname[%s] level=%u \n\r",file_name,level);
for (j=0;j<11;j++)printf("%c",buff[j]);
#ENDIF
if(strncmp(buff,file_name, 11)==0) ///8.3 file name ex "FILE EXT"
/// "FOLDER "
{
// we have a file type or a sub directory(folder)
// so we get the starting cluster number
attribute=buff[11];
file[fnbr].root_cluster_ptr=make16(buff[27],buff[26]);/// assign initial cluster ptr
/// if it is not a directory
/// it points to the begining of the file
/// cluster chain
if ((attribute & 0b00010000)>0)directory=true;
else directory=false;
if ((attribute & 0b00100000)>0 || attribute==0)
{
archive=true; //// we have our file
file[fnbr].size=make32(buff[31],buff[30],buff[29],buff[28]);
file[fnbr].dir_addr_ptr=dir_addr_ptr; ///save address of this files tile
/// assign global value
}
else archive=false;
goto match_found;
// goto fill_table; // we have a match
}
next_tile:
bytes_read=bytes_read+32;
if(bytes_read > cluster_size_bytes)
{
/// requires a valid next=next_cluster_ptr
// compute next cluster address and assign this cluster
dir_addr_ptr=cluster_addr(fnbr,NEXT_CLUSTER);
if (dir_addr_ptr==0xFFFFFF) return (23);
bytes_read=bytes_read-cluster_size_bytes;
dir_addr_ptr=dir_addr_ptr+bytes_read;
}
else
{
dir_addr_ptr=dir_addr_ptr+32;
}
dir_addr_ptr=dir_addr_ptr+32;
if (read_BLOCK(dir_addr_ptr,buff)==false) return(32);
goto tile_decode;
match_found:
///// if we have a sub directory we need to cycle down a level
if (directory==true) {
// compute the sub directory address
// compute this cluster address this_cluster_ptr must be valid
dir_addr_ptr=cluster_addr(fnbr,ROOT_CLUSTER); /// set physical addr of starting cluster
#IF MMC_OPEN_TRACE
printf("\n\r next_cluster_ptr=%lu \n\r ",file[fnbr].next_cluster_ptr);
#ENDIF
//printf("\n\r dir_addr_ptr=%lu",dir_addr_ptr);
// dir_addr_ptr=((int32)cluster_table[0]-(int32)2)*(int32)cluster_size_bytes+
// data_area_address;
level++;
goto read_directory;
}
// note record length must divide into 512 to align properly
if (rec_length<2) return(12);
/// get the initial file_addr_ptr
file[fnbr].addr_ptr=cluster_addr(fnbr,ROOT_CLUSTER);
file[fnbr].offset=0; //init bytes read from beginning of open file
file[fnbr].cluster_offset=0; //init bytes read to beginning of the current cluster
file[fnbr].rec_size=(int32)rec_length; /// assign file record size
#IF MMC_OPEN_TRACE
printf("root_cluster=%lu \n\r",file[fnbr].root_cluster_ptr);
#ENDIF
//printf("\n\r fopen %u rec size=%lu",fnbr,file[fnbr].rec_size);
if(set_BLOCKLEN(file[fnbr].rec_size)==false) return(13);
return(0);
}
//////////////////////////////////////////////////////////////////////////////////
////////////////////////////// FILE READ ///////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////
#separate
int file_read(int8 fnbr,char *buff)
{
int32 address;
int32 nxt_cluster;
//// MMC allows a read to start and stop at any address but this file system
//// imposes a record size restriction the record size must divide into the
/// 512 block to allow writing of the records
/// rec_size must align with cluster boundary 2048 ...must be a divisor of 2048
/// find the cluster containing the offset
/// buff must be at least the size of the recordsize requested in the File open
//printf("foffset=%lu coffset=%lu ",file[fnbr].offset,file[fnbr].cluster_offset);////$$$$
if ( file[fnbr].offset>=file[fnbr].size) return(10); /// already beyond eof
if ( file[fnbr].offset + (int32) file[fnbr].rec_size > file[fnbr].cluster_offset + (int32) cluster_size_bytes)
{
#IF MMC_READ_TRACE
printf("adv to next cluster");
#ENDIF
/// need to advance to the next cluster
nxt_cluster=cluster_addr(fnbr,NEXT_CLUSTER);
if ( nxt_cluster!=0XFFFFFFFF) file[fnbr].addr_ptr=nxt_cluster;
else return(11); /// last cluster in file reached
file[fnbr].cluster_offset=file[fnbr].cluster_offset+(int32)cluster_size_bytes; //foffset is the byte offset within the file
//that file_addr_ptr points to
}
address=file[fnbr].addr_ptr+file[fnbr].offset-file[fnbr].cluster_offset;
#IF MMC_READ_TRACE
printf("\n\r offset=%lu",offset);
printf("\n\r data_area_address=%lu",data_area_address);
printf("\n\r cluster_size_bytes=%lu",cluster_size_bytes);
printf("\n\r file_addr_ptr=%lu",file_addr_ptr);
#ENDIF
if (read_BLOCK(address,buff)==false)return(12); /// read block into buff
if ( file[fnbr].offset+file[fnbr].rec_size< file[fnbr].size )
file[fnbr].offset=file[fnbr].offset+file[fnbr].rec_size;
else
{ /// end of file
#IF MMC_READ_TRACE
printf("eof size=%lu",file[fnbr].size);
#ENDIF
buff[ file[fnbr].size-file[fnbr].offset]=0; /// short record
file[fnbr].offset=file[fnbr].size;
return(255); //eof
}
return(0);
}
//////////////////////////////////////////////////////////////////////////////////
////////////////////////////// WRITE FILE /////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////
#separate
int file_write(int8 fnbr,int *buff)
{
//// buff size must be at least the recordsize requested in File open
//// the record is updated only chars beyond rec_size are ignored
/// set up for write
/// A MMC write is restricted it must be for a block and allign on block boundaries
/// blocklen must be exactly 512 and start address must be the begining of a
/// sector
/// the buff could potentially span a sector and or span a block(512) boundary
/// ex there could be 1byte left in a block and 1 byte lect in a sector
// if the block is the last block in the sector
/// worst case we could write to two blocks and need a new sector
int32 address,nxt_cluster;
int16 in_cluster_size,out_cluster_size;
int8 appending_flag;
appending_flag=0;
if (file[fnbr].offset + file[fnbr].rec_size>=file[fnbr].size) appending_flag=1;
/// find the cluster containing the offset
if ( file[fnbr].offset+file[fnbr].rec_size>=file[fnbr].cluster_offset + cluster_size_bytes)
{
#IF MMC_WRITE_TRACE
printf("spanning cluster \n\r");
#ENDIF
/// spans the current cluster so we split the write
in_cluster_size=file[fnbr].cluster_offset+cluster_size_bytes-file[fnbr].offset;
/// bytes from start of file to end of this cluste- bytes into the file
out_cluster_size=file[fnbr].rec_size - in_cluster_size;
#IF MMC_WRITE_TRACE
printf("write>> spanning cluster inside=%lu outside=%lu \n\r",in_cluster_size,out_cluster_size);
#ENDIF
address=file[fnbr].addr_ptr+file[fnbr].offset - file[fnbr].cluster_offset;
// physical address=
// physical address of the cluster +offset from begining of file
// - offset from the begining of file for the byte at the begining of the cluster
#IF MMC_WRITE_TRACE
printf("write file>>cluster=%lu in clstr addr=%lu",file[fnbr].this_cluster_ptr,address);
#ENDIF
//// address=physical offset of this cluster +bytes into this cluster
if(write_BLOCK(address,buff,in_cluster_size)==fals e)return(81); //// write first chunk
/// allocate the next cluster
nxt_cluster=cluster_addr(fnbr,NEXT_CLUSTER); ///physical address of file data that the
/// specific cluster indexes
#IF MMC_WRITE_TRACE
printf("nxt_cluster=%lu",nxt_cluster);
#ENDIF
if ( nxt_cluster==0xFFFFFFFF)
{
#IF MMC_WRITE_TRACE
printf("updating FAT");
#ENDIF
//// FAT2 is an identical copy of FAT1
file_new_cluster(fnbr,1); /// a new cluster is allocated in FAT1
file_new_cluster(fnbr,2); /// a new cluster is allocated in FAT2
nxt_cluster=cluster_addr(fnbr,NEXT_CLUSTER); ///physical address of file data that the
#IF MMC_WRITE_TRACE
printf("\n\r write>>nxt_cluster addr=%lu this clstr=%lu next=%lu",nxt_cluster,file[fnbr].this_cluster_ptr,file[fnbr].next_cluster_ptr); /// specific cluster indexes
#ENDIF
}
file[fnbr].addr_ptr =nxt_cluster;
file[fnbr].cluster_offset=file[fnbr].cluster_offset + cluster_size_bytes; //foffset is the byte offset within the file
//that file_addr_ptr points to
address=file[fnbr].addr_ptr + file[fnbr].offset - file[fnbr].cluster_offset + in_cluster_size;
#IF MMC_WRITE_TRACE
printf("out addr=%lu,out size=%lu",address,out_cluster_size);
#ENDIF
if(write_BLOCK(address,&buff[in_cluster_size],out_cluster_size)==false)return(82); /// write block pads with 0x00 to end of sector
}// end of spanned cluster
else
{
/// within the current cluster
address=file[fnbr].addr_ptr+file[fnbr].offset - file[fnbr].cluster_offset;
if(write_BLOCK(address,buff,file[fnbr].rec_size)==false)return(84); /// write block pads with 0x00 to end of sector
}
if(appending_flag==1) {
/// if appended we need to up date the file size
file[fnbr].size=file[fnbr].size + file[fnbr].rec_size; /// add one record
address=file[fnbr].dir_addr_ptr+28; /// file size is offset 28 in tiles
#IF MMC_WRITE_TRACE
printf("new file size=%lu",file[fnbr].size);
#ENDIF
buff[0]=make8(file[fnbr].size,0);
buff[1]=make8(file[fnbr].size,1);
buff[2]=make8(file[fnbr].size,2);
buff[3]=make8(file[fnbr].size,3);
MMC_dir_protected=false;
if(write_BLOCK(address,buff,4)==false)return(85);
}
if(set_BLOCKLEN(file[fnbr].rec_size)==false) return(86); /// reset to original rec_size
return(0);
}
#separate
int file_set(int fnbr,int32 offset)
{
/// file open sets the offset to the begining offset=0
/// this sets the offset within the file ...offset of 0 is a reset
if(offset>=file[fnbr].size) return(71);
file[fnbr].offset=offset; //// overwrite the existing offset
file[fnbr].next_cluster_ptr=file[fnbr].root_cluster_ptr; /// set current ptr to beginning
file[fnbr].cluster_offset=0;
// move the cluster to the one containing the offset
while ( offset>cluster_size_bytes )
{
file[fnbr].addr_ptr=cluster_addr(fnbr,NEXT_CLUSTER);
file[fnbr].cluster_offset+=cluster_size_bytes; //foffset is the byte offset within the file
if (offset-cluster_size_bytes >0) offset= offset - cluster_size_bytes;
}
return(0);
}
#separate
int file_new_cluster(int8 fnbr,int8 mode)
///////////// this does identical writes to either the FAT1 and FAT2 sectors
{
int16 eof_cluster;
char buff[2],tmp_buff[2];
int32 address;
int32 fat_address;
int16 slot;
/// an unused cluster has the value 0x0000 as its next cluster ptr
/// a used cluster has either 0xFFFF meaning last in chain
/// or a valid cluster displacement in the FAT1 amd FAT2 area
/// to append a cluster the 0XFFFF needs to be replaced by the appended
/// cluster location and the appended locations data (next ptr) needs to be set to 0XFFFF
eof_cluster=file[fnbr].this_cluster_ptr;
#IF MMC_NEW_CLUSTER
printf("the cluster with eof (FFFF)=%lu \n\r",eof_cluster);
#ENDIF
slot=0;
if(set_BLOCKLEN((int32)2)==false)return(false); // force blocklen to 2
/// use global address of FAT1 assigned by INIT
if (mode==2)fat_address=fat2_address;
else fat_address=fat1_address;
address=fat_address;
#IF MMC_NEW_CLUSTER
printf("mode=%u FAT addr=%lu \n\r",mode,address);
#ENDIF
do
{
if(read_block(address,buff)==false) return(false) ;
slot=slot+1;
address=address+2;
//printf(" slot %lu =%2x %2x",slot,buff[0],buff[1]);
}while (buff[0]!=0 || buff[1]!=0);
address=address-2; // correct for over step
slot=slot-1;
#IF MMC_NEW_CLUSTER
printf("slot=%lu address=%lu",slot,address);
#ENDIF
/// found an unused cluster
tmp_buff[0]=0xFF;tmp_buff[1]=0xFF; /// stamp it as last
MMC_dir_protected=false; /// allow writes to the protected areas
if(write_block(address,tmp_buff,2)==false ) return(false);
/////////////////////////////////////////////
/// update prev cluster with 0xFFFF in it
tmp_buff[1]=make8(slot,1);
tmp_buff[0]=make8(slot,0);
if (mode==1)
{
//// update the file info
file[fnbr].next_cluster_ptr=slot;
#IF MMC_NEW_CLUSTER
printf("cluster %lu was updated to point to %lu",file[fnbr].this_cluster_ptr,file[fnbr].next_cluster_ptr);
#ENDIF
}
/// compute physical address of the current cluster
MMC_dir_protected=false; /// allow writes to the protected areas
if(write_BLOCK(fat_address+(file[fnbr].this_cluster_ptr)*2,tmp_buff,2)==false) return(33);
if(set_BLOCKLEN((int32)file[fnbr].rec_size)==false)return(false); // reset blocklen
return(true);
}
signed int strncmp(char *s1, char *s2, int n)
{
for (; n > 0; s1++, s2++, n--)
if (*s1 != *s2)
return((*s1 <*s2) ? -1: 1);
else if (*s1 == '\0') return(0);
return(0);
}
end of the driver file mmcdos.c
below is an example of opening and reading the file HOME.HTM in the directory WEB
//#include <18F8720.h>
main()
{
int r1,i,j,error,error0,error1;
int16 rec_no;
int16 index,rec_size;
int32 offset;
char fname[32],buff0[MMC_BUFF_SIZE+1],buff1[MMC_BUFF_SIZE+1];
char c;
//int32 read_address,dir_address,dir_addr_ptr,start_lsec,
// file_addr_ptr,file_size,file_start_addr,total_byte s_read,fat1_address;
//int16 sec_resv,sec_for_FAT,start_cluster,this_cluster,ne xt_cluster,cluster_size_bytes,
// total_clusters_read,cluster_bytes_read;
//int sec_per_cluster,lnf_tiles;
printf("\n\r start mmctest");
/// init SPI interface
setup_adc_ports(NO_ANALOGS);
init_dram();
/// MMC Setup
set_tris_c(0b10010011); //c7=rx I, c6=tx O, c5 SDO O,c4 SDI I
//c3 CLK O,c2 CS O,
output_high(_CS);
/// init SPI interface
printf("\n\r Start SPI MMC\n\r");
// Note code below was needed before SPI_XMIT_LTO_H was available
// SETUP_SPI(SPI_MASTER | SPI_CLK_DIV_16 | SPI_L_TO_H );
// CKE=0;
// CKP=1;
// SMP=0;
SETUP_SPI(SPI_MASTER | SPI_CLK_DIV_16 | SPI_H_TO_L |SPI_XMIT_L_TO_H );
/// transmit on rising edge and sample receive on the rising edge
/// of the clock
/// idle clock is high
buff0[MMC_BUFF_SIZE]=0;
buff1[MMC_BUFF_SIZE]=0;
rec_no=0;
///////// init MMC ////////////////////////////////////////
error=init_MMC(10);
if (error>0) {
printf("\n\r Init failed error=%U\n\r",error);
goto mmc_exit;
}
printf("\n\r MMC initialized \n\r");
rec_size=MMC_BUFF_SIZE;
//////////////////////////////////////////////////////////////////////
// note \ is a special char in CCS so we use \\ to get a single \ (0x5C)
//strcpy(fname,"MMCTEST\\PICFILES\\PIC.TXT");
/// same as "MMCTEST\PICFILES\PIC.TXT"
///////////////////////////////////////////////////////////////////////
strcpy(fname,"WEB\\HOME.HTM");
rec_size=MMC_BUFF_SIZE;
error0=open_file(0,fname,rec_size);
if (error0>0) {
printf("\n\r fopen as 0 failed error=%U\n\r",error);
goto mmc_exit;
}
else printf("\n\r opened as 0 file %s with rec size %lu \n\r",fname,rec_size);
set_dram_address(0);
do {
error0=file_read(0,buff0);
if (error0>0 && error0<255 ) {
printf("\n\r fread 0 failed error=%U\n\r",error0);
break;
}
printf("%s",buff0);
rec_no++;
} while (error0==0);
mmc_exit:
///printf("\n\r done winhex adj= %lu \n\r",winhex_adj);
while(true);
}
th0001
30-11-2011, 05:13 PM
bo tay!!!!!!!!!!!!!!!!!!
lamtuanhung
13-02-2012, 09:50 PM
Xin chào các cao thủ.Tôi đang nghiên cứu giao tiếp card MMC thông qua chuẩn truyền SPI mà thấy khó ghê.Ai có tài liệu hay kinh nghiệm gì share tôi với.Thanks.
bạn có thể download miễn phí tài liệu và ví dụ tại địa chỉ này : http://updatebook.vn/dien-dien-tu-29/help-ccs-tieng-viet-4-0-2-a-25508/#post26966
lamtuanhung
13-02-2012, 09:53 PM
bạn hãy download tài liệu ở trên rất dễ hiểu chỉ 20 dòng lệnh là bạn có thể lắm bắt được giao thức giữ MMC/SD và PIC16F877 chú bạn học thật tốt
0241050240
17-08-2012, 09:43 AM
chán quá
Hem ai quan tâm tới vẫn đề này nữa sao??????????????
bạn bogu ơi.
bạn giao tiếp dc với mmc chưa giúp mình với
mình cũng đang giao tiếp với mmc bằng pic18f45k22 mà làm mãi ko dc
ban xem code mình gửi sai cho nào chỉ mình với
cảm ơn bạn nhìu
dubui
19-11-2013, 01:36 AM
có ai giúp dùm em cái code đồ án giao tiếp pic 16f877a với thẻ nhớ MMc k ak (viết bằng CCS)...? jup e voi e cam ơn nhìu....huhu
huuhao1993
08-11-2014, 05:16 PM
alo.Ko ai nói j à.Chán ghê.
a ơi e đang làm giao tiếp MMC mà chả biết gì, có cái file tìm được trên mạng mà ko hiểu, a xem rồi giải thích code hộ e được ko ạ?
huuhao1993
08-11-2014, 05:21 PM
Cái file MMC_PC bạn bogu gửi lên làm gì có code, cũng không có file hex và file image của mmc nữa, có mỗi 1 cái file proteus thì làm sao mình chạy được. bạn gửi lại đi
a ơi giải thích giúp e cái code trong file này dc ko, e gà mờ chả hiểu gì
vBulletin® v3.8.11, Copyright ©2000-2025, vBulletin Solutions Inc.