MMC/SD initialization

        Mò mẫm ba ngày ròng rã, cuối cùng con AVR cũng chịu nói chuyện với thằng MMC/SD. Post ở đây vừa chia sẻ kiến thức vừa lưu lại để dành, hồi chừng quên thì quay lại có cái mà mò ;))

        Đầu tiên cần lưu ý là thằng MMC/SD chỉ nói chuyện bằng giao thức SPI, do đó mọi chuyện cần bắt đầu bằng SPI. Toàn bộ code được viết bằng C, trên trình biên dịch CodeVisionAVR Ver 2.03.4 đã được “cờ rắc” :D – Nếu chưa có thì tải ở đây!

Đầu tiên là khởi tạo SPI

void SPI_init()
{
       delay_ms(500);
       DDRB  =  0xB0;                                           // Đặt SCK, MOSI & SS chế độ xuất (outputs )
       SPCR =  0b01010010;                            // Khởi tạo cổng SPI (Mode 0) 
       SPSR  =  0b00000000;
       PORTB  =  0xEF;                                       // Xóa bit MOSI & SCK
}

Gửi / nhận 1 byte bằng SPI

unsigned char SPI_transfer(unsigned char dataS)
{
       char dataR=0;
       SPDR = dataS;
       while (!(SPSR & 0x80));
       dataR=SPDR;
       return (dataR);
}

       Phần khởi tạo giao thức chỉ có bi nhiu đó thôi, gửi thử 1 byte rồi kẹp oscillocope vô, nhìn xung ra đẹp thấy thương. :))

       Với mỗi một thiết bị, nhà sản xuất thường định sẵn các tập lệnh để ghép nối, các tập lênh này với cùng loại thiết bị thì như nhau, đó xem như tiêu chuẩn. Thằng MMC/SD  tuân thủ đúng như vậy, nó cũng có những tập lệnh riêng để giao tiếp, mỗi lệnh có một chức năng khác nhau, cái này muốn hiểu rõ thì phải tham khảo thêm datasheet. Chỉ cần chú ý là sau mỗi lần nói chuyện xong, cần disable em nó một phát, khi nào cần nói tiếp thì enable lại. Vậy nên cần tạo sẵn hai chương trình con bật/tắt để tiện các thao tác về sau.

Enable MMC/SD

void MMC_en()
{
     SPIPORT &= ~CS;
     SPI_transfer(0xFF);
    SPI_transfer(0xFF);
}

Disable MMC/SD

void MMC_dis()
{
     SPIPORT |=CS;
    SPI_transfer(0xFF);
    SPI_transfer(0xFF); 
}

       Vì MMC/SD làm việc với các tập lệnh riêng của nó, nến làm sẵn chương trình con gởi lệnh đến MMC theo đúng cấu trúc lệnh.

Gửi / Nhận giá trị với MMC/SD

char Command(unsigned char B5, unsigned char B4, unsigned char B3, unsigned char B2, unsigned char B1, unsigned char B0 )

    SPI_transfer(0xFF);
    SPI_transfer(B5);
    SPI_transfer(B4);
    SPI_transfer(B3);
    SPI_transfer(B2);
    SPI_transfer(B1);
    SPI_transfer(B0);
    SPI_transfer(0xFF);
    return SPI_transfer(0xFF);

      Các bước chuẩn bị xong, giờ là đến lúc khởi tạo em nó đây.
       Đầu tiên là disable em nó, gửi liên tục 80 xung SCK cho em nó tự khởi động, sau đó enable lên, gửi command 0, nếu kết quả từ MMC/SD trả về là 1 là ok, gửi tiếp command 1, nếu trả về 0 là ok, lại gửi tiếp command 16, kết quả trả về 0 là ok.

Khởi tạo MMC/SD

unsigned char MMC_init()
{
       unsigned int i=0;
       MMC_dis();
       for(i=0;i<10; i++)              //10×8=80 xung SCK cho MMC tu khoi tao
        SPI_transfer(0xFF);
/*———————-Gui CMD0———————-*/
       MMC_en();
       while (Command(0x40,0,0,0,0,0×95)!=1);
       MMC_dis();
/*———————-Gui CMD1———————-*/
       MMC_en();
       while (Command(0x41,0,0,0,0,0xFF)!=0);
       MMC_dis();
/*———————-Gui CMD16———————*/
       MMC_en();
       while (Command(0x50,0,0,0×02,0,0xFF)!=0);
        MMC_dis();
        return 1; 
}

       Sau khi MMC/SD khởi tạo, giờ đọc thử một sector bằng commnad 17, BLOCK_SIZE=512, được định nghĩa ở đầu chương trình : #define BLOCK_SIZE  512 

Đọc một sector

unsigned char  MMC_readblock(unsigned long SECTOR)
{
    unsigned int i=0;
    unsigned long ADDRESS=0;
    unsigned char mmcData=0;

    ADDRESS=(unsigned long)SECTOR*BLOCK_SIZE;
    MMC_en();
   
    while (Command(0x51,ADDRESS>>24,ADDRESS>>16,ADDRESS>>8,ADDRESS>>0,0xFF)!=0);
    while(SPI_transfer(0xFF) != 0xFE);
         
    for(i=0;i<BLOCK_SIZE;i++)
    {
        mmcData=SPI_transfer(0xFF);     
        Sector_buff[i]=mmcData;
    }   
    SPI_transfer(0xFF);
    SPI_transfer(0xFF);
    MMC_dis();
    return 1;
}

       MMC/SD không đặt sector từ đầu không gian lưu trữ, nên cần lấy địa chỉ bắt đầu, dùng command 17

Tìm địa chỉ bảng FAT

unsigned long getPartitionOffset(void)
{
 unsigned int i = 0;
 unsigned long offset = 0;
 unsigned char tmp=0;

    MMC_en();
   
    while (Command(0x51,0,0,0,0,0xFF)!=0);
    while(SPI_transfer(0xFF) != 0xFE);
         
    for(i=0;i<454;i++)
        SPI_transfer(0xFF);
       
    tmp = SPI_transfer(0xFF);
    offset = tmp;
    tmp = SPI_transfer(0xFF);
    offset |= (unsigned long int)tmp << 8;
    tmp = SPI_transfer(0xFF);
    offset |= (unsigned long int)tmp << 16;
    tmp = SPI_transfer(0xFF);
    offset += (unsigned long int)tmp << 24;   
   
    for(i = 458;i<BLOCK_SIZE;i++)
        SPI_transfer(0xFF);

    SPI_transfer(0xFF);
    SPI_transfer(0xFF);
    MMC_dis();
    return offset;
}

các thao tác đọc, ghi xoá sector cũng dựa trên command để làm. Chỉ có nhiêu chương trình đó thôi mà mất 3 ngày 3 đêm :|

21 phản hồi

  1. hien nói:

    em cam on nhe. voi kien thu cua em hien gio chua the hieu duoc nhung em se tim hieu ve cai nay

  2. Chào bạn :) Bài viết của bạn rất hay và bổ ích, mình cũng làm 1 trang web về ĐTVT, hi vong chúng ta có thể trao đổi và bàn luận về kiến thức chứ :) Nick Y! của mình là: rainbowsmile111

  3. NgThang nói:

    hì.thấy bạn viết đến phần tìm địa chỉ bảng FAT thì ngừng lại,bạn có thể continue được không.mình rất muốn làm về SD,MMC

  4. pro_avr nói:

    tiếpđi bạn,bạn có thể giải thích rõ hơn về các biến bạn dùng không.

  5. viet nói:

    Chào bạn, mình là Việt. Mình có thể xin bạn code của phần mmc giao tiếp mega16/32 để tham khảo dc không? thanks bạn!

  6. Đây là một module trong luận văn của mình, mình tìm lại rồi gửi vào mail bạn nhé!

  7. kiD.It nói:

    hi!
    Bài viết rất hay. Mình cũng đang làm về cái này mới tìm hiểu về SPI. Còn cái MMC thì đang tìm hiểu. Mong cậu giúp đở. Có j add nik mình để tiện ll. Y!M: nvhoan_kid_it

  8. ngophuongchan nói:

    Cho minh xin code voi Minh Nguyen! mail cua minh la: ngophuongchan@gmail.com

  9. trinh nói:

    bạn ơi cho mình hỏi c cho avr có khác với c cho pic ko? mình cũng đang nghien cứu đề tài này mình viết c cho pic . nhung minh phân vân c cho avr và pic khác nhau cho nào?

  10. Mình chưa dùng PIC nên cũng không rõ lắm. Mình thích PIC chỉ vì nó có khả năng chống nhiễu cao thôi, còn về ứng dụng thì AVR giải quyết tất cả nhu cầu của mình rồi!

  11. trinh nói:

    ban oi. giao tiep voi may tinh co can dung chuong trinh ngat khong vay?

  12. trinh nói:

    phan void main can khai bao nhung gi de co the giao tiep voi pc vay ? ban co yahoo ko . minh co 1 so van de can tham khao y kien cua ban.

  13. Dungdtv nói:

    em đang tìm hiểu về việc ghi dữ liệu dựa vào bảng FAT dùng AVR, a có thể cho em xin code được ko? đoạn chương trình tìm đại chỉ bảng FAT của a ở trên e vẫn chưa hiểu. Rất mong a giúp đỡ! Thanks! dungdtvdh@gmail.com

  14. Minh nói:

    Bài viết rất hay. Cảm ơn bạn nhiều.

  15. Dong Khoi nói:

    Chào bạn! MÌnh thấy bài viết rất hay, mình cũng đang tìm hiểu về vấn đề này. Bạn có thể cho mình xin code hoàn chỉnh được không? Mail của mình là: khoihvktqs@gmail.com. Thanks bạn nhiều!

  16. Minh nói:

    bài viết hay quá ! anh ơi anh có thể cho em code cái này được không anh . .Mail của em là: vophilongptit@gmail.com .em cám ơn anh nhiều !!

  17. Tiến Hà nói:

    chào bạn.mình đọc được đoạn code giao tiếp của mega16 với SDcard.bạn có thể gửi cho mình xin toàn bộ code của bạn để mình tham khảo được không.
    mail:nguyentienha.ha@gmail.com

  18. Chào bạn, mình cũng đang thử MMC kết nối với AVR nhưng vẫn chưa được. Khai báo SPIPORT, và CS, Sector_buff mình vẫn chưa biết khai báo như thế nào. Bạn có thể chia sẻ thêm?

  19. Nguyện Hoa nói:

    Bạn tải cả bộ source ở đây về tham khảo nhé http://elm-chan.org/fsw/ff/00index_p.html

  20. Mình mới tìm hiểu SPI ? Còn cách mắc chân với VĐK tự do hay cần nguyên tắc gì hong bạn ?

Trả lời

Thư điện tử của bạn sẽ không được hiện thị công khai. Các trường bắt buộc được đánh dấu *


7 × 7 =

Bạn có thể sử dụng các thẻ HTML và thuộc tính sau: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>