PIC Vietnam

PIC Vietnam (http://www.picvietnam.com/forum/index.php)
-   Giao tiếp USB, CAN, I2C, SPI, USART... (http://www.picvietnam.com/forum/forumdisplay.php?f=45)
-   -   Giao tiếp card MMC ? (http://www.picvietnam.com/forum/showthread.php?t=1212)

doianhve 22-06-2007 09:46 AM

Giao tiếp card MMC ?
 
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

code tham khảo
 
Để 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-----------
Code:

#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

Code:

-----------------------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

Code:

-------------------------------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

Trích:

Nguyên văn bởi doianhve (Post 9520)
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/parti...ticles-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.

byte 01-12-2007 12:38 PM

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

Trích:

Nguyên văn bởi byte (Post 13189)
...
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/show...p?t=401&page=2

Thân,

byte 01-12-2007 05:01 PM

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ì


Múi giờ GMT. Hiện tại là 06:16 AM.

Tên diễn đàn: vBulletin Version 3.8.11
Được sáng lập bởi Đoàn Hiệp.
Copyright © PIC Vietnam