Auf einem STM32F407 kann mit SPI nicht in die SD-Kartendatei geschrieben werden, wenn die Chan FatFs-Bibliothek verwendet wird

Ich verwende ein STM32F4-Entwicklungsboard mit einem STM32F407-Chip. Um mit der SD-Karte zu kommunizieren, verwende ich SPI1 und verwende die von Chan erstellte FatFs-Bibliothek.

Der Kern des Problems ist also, dass ich es erfolgreich geschafft habe, eine Datei auf der SD-Karte zu erstellen, von der ich lesen kann. Aber wenn ich versuche, in die Datei zu schreiben, wird entweder die Datei beschädigt oder Mülldaten wie diese "{46040EDD-C" gedruckt. Wenn ich mir den Speicher ansehe, kann ich das Zeug sehen, das ich geschrieben habe, aber irgendwie wird es an die falsche Speicheradresse geschrieben.

Ein weiteres Problem, das ich habe, ist, dass ich beim ersten Erstellen einer Datei und dem Versuch, mit f_write darauf zu schreiben, die Antwort FR_DISK_ERR bekomme. Der Fehler kommt vom Versuch, eine Cluster-Kette zu erstellen, wenn ich durch den Code gehe, funktioniert es gut. Es könnte also eine Verzögerung fehlen. Das nächste Mal, wenn ich das Programm starte, funktioniert es, und f_write gibt FR_OK zurück.

Ich bin mir nicht sicher, ob diese Probleme zusammenhängen oder nicht. Ich versuche jetzt seit etwa zwei Wochen, dies zum Laufen zu bringen, und würde mich über jede Hilfe freuen, die ich bekommen kann. Danke schön.

Der Code:

Haupt c

int main(void)
{
    int i;

    //SD CARD INIT

    //Fatfs object
    FATFS FatFs;
    //File object
    FIL fil;
    UINT fa;

    FRESULT res_mount, res_open, res_seek, res_write;

    delay(10ms);
    res_mount = f_mount(&FatFs, "", 1);
    if (res_mount == FR_OK) {
        GPIO_ToggleBits(GPIOD, GPIO_Pin_12);
        delay(10ms);
        res_open = f_open(&fil, "test.txt", FA_OPEN_ALWAYS | FA_READ | FA_WRITE);
        if (res_open == FR_OK) {
            GPIO_ToggleBits(GPIOD, GPIO_Pin_13);
            delay(10ms);
            res_seek = f_lseek(&fil, f_size(&fil));
            if(res_seek == FR_OK)
            {
                delay(10ms);
                GPIO_ToggleBits(GPIOD, GPIO_Pin_14);
                res_write = f_write(&fil, "Alpha Beta\n", 11, &fa);
                if (fa > 0 && res_write == FR_OK) {
                    GPIO_ToggleBits(GPIOD, GPIO_Pin_15);
                    f_sync(&fil);
                }
            }
            f_close(&fil);
        }
        f_mount(0, "", 1);
    }

    while(1);

    //SD CARD INIT END
}

Chans diskio.c-Datei, die ich bearbeitet habe.

#include "diskio.h"     /* FatFs lower layer API */

/* Definitions of physical drive number for each drive */
#define DEV_RAM     0   /* Example: Map Ramdisk to physical drive 0 */
#define DEV_MMC     1   /* Example: Map MMC/SD card to physical drive 1 */
#define DEV_USB     2   /* Example: Map USB MSD to physical drive 2 */

static volatile DSTATUS Stat = STA_NOINIT;  /* Disk status */

static BYTE CardType;   /* Card type flags (b0:MMC, b1:SDv1, b2:SDv2, b3:Block addressing) */



/*-----------------------------------------------------------------------*/
/* Get Drive Status                                                      */
/*-----------------------------------------------------------------------*/

DSTATUS disk_status (
    BYTE pdrv       /* Physical drive nmuber to identify the drive */
)
{
    if(pdrv) 
        return STA_NOINIT;      // Supports only drive 0

    return Stat;
}



/*-----------------------------------------------------------------------*/
/* Inidialize a Drive                                                    */
/*-----------------------------------------------------------------------*/

DSTATUS disk_initialize (
    BYTE pdrv               /* Physical drive nmuber to identify the drive */
)
{
    if (Stat & STA_NODISK) 
        return Stat;    /* No card in the socket? */

    //SLOW

    uint8_t ty = 0;
    ty = SD_CARD_InitialiseCard();

    CardType = ty;

    if(ty)
        Stat &= ~STA_NOINIT;

    return Stat;
}



/*-----------------------------------------------------------------------*/
/* Read Sector(s)                                                        */
/*-----------------------------------------------------------------------*/

DRESULT disk_read (
    BYTE pdrv,      /* Physical drive nmuber to identify the drive */
    BYTE *buff,     /* Data buffer to store read data */
    DWORD sector,   /* Start sector in LBA */
    UINT count      /* Number of sectors to read */
)
{
    //DRESULT res;
    //int result;
    if(pdrv || !count)
        return RES_PARERR;
    if (Stat & STA_NOINIT)
        return RES_NOTRDY;

    if(!(CardType & SDCARD_BLOCK))
        sector *= 512;

    if(count == 1)
    {
        if((SD_CARD_Cmd(READ_SINGLE_BLOCK, sector) == 0x00) &&  SD_CARD_Read(buff, 512))
            count = 0;
    }
    else
    {
        if(SD_CARD_Cmd(READ_MULTIPLE_BLOCKS, sector) == 0)
        {
            do
            {
                if(!SD_CARD_Read(buff, 512))
                    break;
                buff += 512;
            }
            while(--count);
            SD_CARD_Cmd(STOP_TRANSMISSION, 0);
        }
    }

    return count ? RES_ERROR : RES_OK;
}



/*-----------------------------------------------------------------------*/
/* Write Sector(s)                                                       */
/*-----------------------------------------------------------------------*/

DRESULT disk_write (
    BYTE pdrv,          /* Physical drive nmuber to identify the drive */
    const BYTE *buff,   /* Data to be written */
    DWORD sector,       /* Start sector in LBA */
    UINT count          /* Number of sectors to write */
)
{
    //DRESULT res;
    //int result;

    if (pdrv || !count)
        return RES_PARERR;
    if (Stat & STA_NOINIT)
        return RES_NOTRDY;
    if (Stat & STA_PROTECT)
        return RES_WRPRT;

    if(!(CardType & SDCARD_BLOCK))
        sector *= 512;

    if(count == 1)
    {
        if((SD_CARD_Cmd(WRITE_SINGLE_BLOCK, sector) == 0x00) &&  SD_CARD_Write(buff, 0xFE))
            count = 0;
    }
    else
    {
        if (CardType & SDCARD_SDC)
            SD_CARD_Cmd(SET_WR_BLOCK_ERASE_COUNT, count);

        if(SD_CARD_Cmd(WRITE_MULTIPLE_BLOCKS, sector) == 0)
        {
            do
            {
                if(!SD_CARD_Write(buff, 0xFC))
                    break;

                buff += 512;
            }
            while(--count);

            if (!SD_CARD_Write(0, 0xFD))    /* STOP_TRAN token */
                count = 1;
        }
    }

    return count ? RES_ERROR : RES_OK;
}



/*-----------------------------------------------------------------------*/
/* Miscellaneous Functions                                               */
/*-----------------------------------------------------------------------*/

DRESULT disk_ioctl (
    BYTE pdrv,      /* Physical drive nmuber (0..) */
    BYTE cmd,       /* Control code */
    void *buff      /* Buffer to send/receive control data */
)
{
    //DRESULT res;
    //int result;

    //NOT NEEDED AT THE MOMENT

    return RES_PARERR;
}

DWORD get_fattime (void)
{
    /* Pack date and time into a DWORD variable */
    return    ((DWORD)(2017 - 1980) << 25)
            | ((DWORD)1 << 21)
            | ((DWORD)1 << 16)
            | ((DWORD)0 << 11)
            | ((DWORD)0 << 5)
            | ((DWORD)0 >> 1);
}

SD_CARD.c:

#include "SD_CARD.h"

/*
SPI1(GPIOA):    -   Type:   -   SD CARD:
Pin4            -   CS      -   Pin2
Pin5            -   SCLK    -   Pin5
Pin6            -   MISO    -   Pin7
Pin7            -   MOSI    -   Pin3
*/
uint8_t SD_CARD_InitialiseCard()
{
    INT i = 0;

    SPI1ENABLE();

    ChipSelect(SPI1, HIGH);
    for(i = 0;i < 16;i++)
        SPI_Send(SPI1, 0xFF);

    for(i = 0;i < 0xFFFF;i++);

    while(SD_CARD_Cmd(GO_IDLE_STATE, 0) != R1_IDLE_STATE); //CMD0

    uint32_t r = SD_CARD_Cmd(SEND_IF_COND, 0x1AA); //CMD8
    if(r == 0x1AA)
        return SD_CARD_InitialiseCardV2();
    else if(r == (R1_IDLE_STATE | R1_ILLEGAL_COMMAND))
        return SD_CARD_InitialiseCardV1();
    else
        return SDCARD_FAIL;
}

uint8_t SD_CARD_WriteRead(INT arg)
{
    SPI_Send(SPI1, arg);
    uint8_t test = SPI_Read(SPI1);
    return test;
}

uint8_t SD_CARD_InitialiseCardV1()
{
    uint8_t cmd;
    INT i = 0;

    if(SD_CARD_Cmd(SD_SEND_OP_COND, 0x40040000) <= 1) //ACMD41 - set to 3V, use 0x40200000 for 3V3
        cmd = SD_SEND_OP_COND;
    else
        cmd = SEND_OP_COND;

    for(i = 0; i < SD_COMMAND_TIMEOUT;i++)
    {
        if(SD_CARD_Cmd(cmd, 0) == 0) //CMD1 or ACMD41
        {   
            // Set block length to 512 (CMD16)
            if(SD_CARD_Cmd(SET_BLOCKLEN, 512) != 0) //CMD16
                return SDCARD_FAIL;

            //Init: SEDCARD_V1
            if(cmd == SD_SEND_OP_COND)
                return SDCARD_V1;
            else
                return SDCARD_MMCV3;
        }
    }

    //Timeout waiting for v1.x card
    return SDCARD_FAIL;
}

uint8_t SD_CARD_InitialiseCardV2()
{
    INT i = 0;
    INT j = 0;

    for(i = 0;i < SD_COMMAND_TIMEOUT;i++)
    {
        for(j = 0;j < 0xFF;j++);
        if(SD_CARD_Cmd(SD_SEND_OP_COND, 0x40040000) == 0) //ACMD41 - set to 3V, use 0x40200000 for 3V3
        {
            uint32_t ocr = SD_CARD_Cmd(READ_OCR, 0); //CMD58
            return (ocr & 0x40000000) ? SDCARD_V2 | SDCARD_BLOCK : SDCARD_V2;
        }
    }

    //Timed out waiting for v2.x card
    return SDCARD_FAIL;
}

uint32_t SD_CARD_Cmd(INT cmd, INT arg)
{
    struct command_fields com;
    com.start_bit = 0;
    com.transmitter_bit = 1;
    com.index = cmd;
    com.argument = arg;
    if(cmd == GO_IDLE_STATE)
        com.crc = 0x4A;
    else if(cmd == SEND_IF_COND)
        com.crc = 0x43;
    else
        com.crc = 0x7F;
    com.end_bit = 1;

    if(cmd == SD_STATUS | cmd == SET_WR_BLOCK_ERASE_COUNT | cmd == SD_SEND_OP_COND) //ACMDx
        SD_CARD_Cmd(APP_CMD, 0); //CMD55

    SD_CARD_WriteCom(&com);

    if(cmd == SEND_IF_COND)
        return SD_CARD_RecieveR7();
    else if(cmd == READ_OCR)
        return SD_CARD_RecieveR3();
    else
        return SD_CARD_RecieveR1();
}

void SD_CARD_WriteCom(struct command_fields *com)
{

    ChipSelect(SPI1, LOW);
    SPI_Send(SPI1, 0xFF);
    SPI_Send(SPI1, (0xFF & ((com->start_bit << 7) | (com->transmitter_bit << 6) | com->index)));
    SPI_Send(SPI1, (0xFF & (com->argument >> 24)));
    SPI_Send(SPI1, (0xFF & (com->argument >> 16)));
    SPI_Send(SPI1, (0xFF & (com->argument >> 8)));
    SPI_Send(SPI1, (0xFF & com->argument));
    SPI_Send(SPI1, (0xFF & ((com->crc << 1) | com->end_bit)));
}

INT SD_CARD_Write(const BYTE *buffer, BYTE token)
{
    INT i = 0;
    ChipSelect(SPI1, LOW);

    while(SD_CARD_WriteRead(0xFF) != 0xFF);

    // indicate start of block
    SPI_Send(SPI1, token);

    if(token != 0xFD)
    {
        // write the data
        for(i = 0;i < 512;i++)
        {
            SPI_Send(SPI1, *buffer);
            buffer++;
        }

        // write the checksum
        SPI_Send(SPI1, 0xFF);
        SPI_Send(SPI1, 0xFF);

        // check the repsonse token
        if(((SD_CARD_WriteRead(0xFF)) & 0x1F) != 0x05)
        {
            ChipSelect(SPI1, HIGH);
            SPI_Send(SPI1, 0xFF);
            return SUCCESS;
        }
    }

    // wait for write to finish
    while(SD_CARD_WriteRead(0xFF) != 0xFF);

    ChipSelect(SPI1, HIGH);
    SPI_Send(SPI1, 0xFF);
    return ERROR;
}

INT SD_CARD_Read(BYTE *buffer, INT length)
{
    INT i = 0;
    ChipSelect(SPI1, LOW);

    for(i = 0; i < SD_COMMAND_TIMEOUT;i++)
    {
        // read until start byte (0xFF)
        if(SD_CARD_WriteRead(0xFF) == 0xFE)
        {
            // read data
            for(i = 0;i < length;i++)
                buffer[i] = SD_CARD_WriteRead(0xFF);

            SPI_Send(SPI1, 0xFF); // checksum
            SPI_Send(SPI1, 0xFF);

            ChipSelect(SPI1, HIGH);
            SPI_Send(SPI1, 0xFF);
            return SUCCESS;
        }
    }

    return ERROR;
}

uint8_t SD_CARD_RecieveR1()
{
    INT i;
    uint8_t response = 0xFF;
    for(i = 0;i < SD_COMMAND_TIMEOUT;i++)
    {
        response = SD_CARD_WriteRead(0xFF);
        if((response == 0x00) || (response == 0x01))
        {
            ChipSelect(SPI1, HIGH);
            SPI_Send(SPI1, 0xFF);
            return response;
        }
    }
    ChipSelect(SPI1, HIGH);
    SPI_Send(SPI1, 0xFF);
    return 0xFF;
}

uint32_t SD_CARD_RecieveR7()
{
    INT i = 0, j = 0;
    for(i = 0;i < (SD_COMMAND_TIMEOUT * 1000);i++)
    {
        uint8_t response[5];
        response[0] = SD_CARD_WriteRead(0xFF);
        if(!(response[0] & 0x80))
        {
                for(j = 1;j < 5;j++)
                {
                    response[j] = SD_CARD_WriteRead(0xFF);
                }
                ChipSelect(SPI1, HIGH);
                SPI_Send(SPI1, 0xFF);
                return ((response[1] << 24) | (response[2] << 16) | (response[3] << 8) | response[4]);
        }
    }
    ChipSelect(SPI1, HIGH);
    SPI_Send(SPI1, 0xFF);
    return 0xFFFFFFFF; // timeout
}

uint32_t SD_CARD_RecieveR3()
{
    uint32_t ocr = 0;
    INT response;
    for(int i=0; i < SD_COMMAND_TIMEOUT; i++)
    {
        response = SD_CARD_WriteRead(0xFF);
        if(!(response & 0x80))
        {
            ocr = SD_CARD_WriteRead(0xFF) << 24;
            ocr |= SD_CARD_WriteRead(0xFF) << 16;
            ocr |= SD_CARD_WriteRead(0xFF) << 8;
            ocr |= SD_CARD_WriteRead(0xFF);
            ChipSelect(SPI1, HIGH);
            SPI_Send(SPI1, 0xFF);
            return ocr;
        }
    }
    ChipSelect(SPI1, HIGH);
    SPI_Send(SPI1, 0xFF);
    return 0xFFFFFFFF; // timeout
}

INT SD_CARD_InitialiseDisk()
{
    if(SD_CARD_InitialiseCard() == SDCARD_FAIL)
        return SDCARD_FAIL;

    SPI_SetSpeed(SPI1, SPI_SPEED_1300KHz);
    return SUCCESS;
}

SPI.c:

#include "SPI.h"

void SPI1ENABLE()
{
    GPIO_InitTypeDef GPIO_InitStruct;
    SPI_InitTypeDef SPI_InitStruct;
    static uint8_t SPI1_ENABLED = 0;
    if(SPI1_ENABLED)
        return;

    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);

    GPIO_PinAFConfig(GPIOA, GPIO_PinSource5, GPIO_AF_SPI1);
    GPIO_PinAFConfig(GPIOA, GPIO_PinSource6, GPIO_AF_SPI1);
    GPIO_PinAFConfig(GPIOA, GPIO_PinSource7, GPIO_AF_SPI1);

    GPIO_InitStruct.GPIO_Pin =  SPI1_SCLK | SPI1_MISO | SPI1_MOSI;
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF;
    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_100MHz;
    GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;
    GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL;
    GPIO_Init(GPIOA, &GPIO_InitStruct);

    GPIO_InitStruct.GPIO_Pin =  SPI1_CS;
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT;
    GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_DOWN;
    GPIO_Init(GPIOA, &GPIO_InitStruct);

    SPI_InitStruct.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
    SPI_InitStruct.SPI_Mode = SPI_Mode_Master;
    SPI_InitStruct.SPI_DataSize = SPI_DataSize_8b;
    SPI_InitStruct.SPI_CPOL = SPI_CPOL_Low;
    SPI_InitStruct.SPI_CPHA = SPI_CPHA_1Edge;
    SPI_InitStruct.SPI_NSS = SPI_NSS_Soft;
    SPI_InitStruct.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256;
    SPI_InitStruct.SPI_FirstBit = SPI_FirstBit_MSB;
    SPI_Init(SPI1, &SPI_InitStruct);

    SPI_Cmd(SPI1, ENABLE);

    SPI1_ENABLED = 1;
}

uint8_t SPI_Read(SPI_TypeDef* SPIx)
{
    while(SPI1->SR & SPI_I2S_FLAG_BSY);         // wait until SPI is not busy anymore
    while(!(SPI1->SR & SPI_I2S_FLAG_RXNE));    // wait until receive complete
    return SPI_ReceiveData(SPIx);
}

void SPI_Send(SPI_TypeDef* SPIx, unsigned char Data)
{
    while(SPI1->SR & SPI_I2S_FLAG_BSY);         // wait until SPI is not busy anymore
    while(!(SPI1->SR & SPI_I2S_FLAG_TXE));    // wait until transmit complete
    SPI_SendData(SPIx, Data);
    while(!(SPI1->SR & SPI_I2S_FLAG_RXNE));    // wait until receive complete
}

Antworten (1)

Also ich habe mein Problem herausgefunden. So dumm ich auch bin, in meiner Schreibfunktion habe ich vergessen, beim Senden von STOP_TRANs-Token den Erfolg zurückzugeben. So sieht die Schreibfunktion nach der Bearbeitung aus.

INT SD_CARD_Write(const BYTE *buffer, BYTE token)
{
    INT i = 0;
    ChipSelect(SPI1, LOW);

    while(SD_CARD_WriteRead(0xFF) != 0xFF);

    // indicate start of block
    SPI_Send(SPI1, token);

    if(token != 0xFD)
    {
        // write the data
        for(i = 0;i < 512;i++)
        {
            SPI_Send(SPI1, *buffer);
            buffer++;
        }

        // write the checksum
        SPI_Send(SPI1, 0xFF);
        SPI_Send(SPI1, 0xFF);

        // check the repsonse token
        uint8_t resp = 0x00;
        do
        {
            resp = SD_CARD_WriteRead(0xFF);
        }
        while(resp == 0x00);

        if((resp & 0x1F) != 0x05)
        {
            // wait for write to finish
            while(SD_CARD_WriteRead(0xFF) != 0xFF);

            SPI_Send(SPI1, 0xFF);
            ChipSelect(SPI1, HIGH);
            SPI_Send(SPI1, 0xFF);

            return SUCCESS;
        }
    }

    // wait for write to finish
    while(SD_CARD_WriteRead(0xFF) != 0xFF);

    SPI_Send(SPI1, 0xFF);
    ChipSelect(SPI1, HIGH);
    SPI_Send(SPI1, 0xFF);

    if(token == 0xFD)
        return SUCCESS;

    return ERROR;
}