thseiler / embedded

some open source embedded stuff
130 stars 50 forks source link

Bootloader deadlock on FAT32 cards #5

Open willie68 opened 10 years ago

willie68 commented 10 years ago

Hi,

first the bootloader is working fine. I have made some minor changes, because i need some LEDs for the visual feedback. It runs on a atmega 328 with 16MHz. But i have serious problems with the bootloader, when there is a FAT32 formatted card inserted. The bootloader stops working and nothing more happens. It doesn't have to work with a FAT32 card, but i'm expecting that the bootloader start the normal program (which itself can handle a FAT32 card). Could you help me?

thseiler commented 10 years ago

Hi,

Thanks for using 2boots, and taking the time to report bugs. It is still proof of concept code, and these days, I rarely find the time to continue to work on it, so please excuse that there are still some rough edges and unfinished spots...

There is a check implemented on mcc_fat.c:238 where it checks that the FileSystemType field starts with a 'F' and has a '6' at the end (i.e. FAT16) so a FAT32 card would be skipped, and the boot process would continue. This works here using a SD (not SDHC) card that I formatted with FAT32, so that check should be working fine...

However, if I use a SDHC (>2GB) card with FAT32 on it, then this code is never even reached. It hangs in an endless loop at mcc_init (mcc_fat:149). The MCC_SEND_OP_COND is to ask the card for its capabilities. 2boot ignores the answer anyway and only does this to make some cards happy, which apparently need this to properly initialize. I suspect, with all modern cards this is no longer an issue. You could try to simply leave it away...

If that does not work, I would try to replace the while loop with a for loop and a retry counter, eventually giving up to initialize the card and the return.

If the *.hex file is contained within in the first 8GiB of the card, then the rest of the code should in theory even work with FAT32, so the checks on mmc_fat:238 and 248 could then be rewritten to no longer check for the '6' to regain some bytes...

In April, i should have again some more time, and I'll try to look at this.

Best Regards, Thomas

thseiler commented 10 years ago

Hi again,

I found that I have to initialize SD(HC) cards in a different manner to MCC cards. Using the SPI interface, only difference after GO_IDLE_STATE (CMD0) is the initialization command.

For MMC cards, SEND_OP_COND (CMD1) is the only one accepted. MMC cards will say CMD55&CMD41 are invalid. For SD cards, they might accept CMD1, but they should be initialized with CMD55&CMD41.

The Docs says, if both card types must be supported, first try the SD init with CMD55, and if it fails, then it is an MMC card and try the init with CMD1.

So uncommenting the SEND_OP_COND will not work, as the the card is then not initialized at all. So this is clearly a bug in 2boots, i'll try to fix it next weekend...

Best Regards, Thomas

willie68 commented 10 years ago

Hi Thomas, thanks for your effort.

willie68 commented 10 years ago

Hi, i just found this artikel (sorry only in german) http://www.mikrocontroller.net/articles/AVR_FAT32 in the mmc.c you will find a mmc_init function, which will send the desired commands to the SD card. Maybe this will help you.

uint8_t mmc_init (void){

    uint8_t cmd, ty, ocr[4];
    uint16_t n, j;

    spi_init();
    mmc_disable();

    for (n = 100; n; n--) spi_read_byte();                      // 80+ dummy clocks

    ty = 0;
    j=100;
    do {
        if (mmc_send_cmd(CMD0, 0) == 1) {                       // Enter Idle state
            j=0;
            TimingDelay = 100;                                  // Initialization timeout of 1000 msec

            if (mmc_send_cmd(CMD8, 0x1AA) == 1) {               // SDv2?
                for (n = 0; n < 4; n++){
                    ocr[n] = spi_read_byte();                   // Get trailing return value of R7 resp
                }
                if (ocr[2] == 0x01 && ocr[3] == 0xAA) {         // The card can work at vdd range of 2.7-3.6V
                    while (TimingDelay) {                       // Wait for leaving idle state (ACMD41 with HCS bit)
                        mmc_send_cmd(CMD55, 0);
                        if(!mmc_send_cmd(ACMD41, 1UL << 30))
                            break;
                    }

                    while(TimingDelay) {
                        if (mmc_send_cmd(CMD58, 0) == 0x00) {    // Check CCS bit in the OCR
                            for (n = 0; n < 4; n++){
                                ocr[n] = spi_read_byte();
                            }
                            ty = (ocr[0] & 0x40) ? CT_SD2 | CT_BLOCK : CT_SD2;  // SDv2
                            break;
                        }
                    }
                }
            } else {                                            // SDv1 or MMCv3
                if (mmc_send_cmd(ACMD41, 0) <= 1)   {
                    ty = CT_SD1;
                    cmd = ACMD41;                               // SDv1
                } else {
                    ty = CT_MMC;
                    cmd = CMD1;                                 // MMCv3
                }
                while (TimingDelay && mmc_send_cmd(cmd, 0));    // Wait for leaving idle state
            }
            if(ty != (CT_SD2 | CT_BLOCK)) {
                while(TimingDelay && (mmc_send_cmd(CMD16, 512) != 0));
            }
            if(!TimingDelay) ty = 0;
        } else { j--; }
    }while(j>0);

    fat.card_type = ty;
    mmc_disable();

    if( fat.card_type == 0 ){
        return FALSE;
    }
    #if (MMC_MAX_SPEED==TRUE)
        spi_maxSpeed();
    #endif

    return TRUE;
}

I'm eagerly waiting for your answer.