Mercurial > ~darius > hgwebdir.cgi > stm32temp
view sd.c @ 80:1a4573062b37
Reshuffle in preparation for being able to have a common API for SPI flash and (emulated) EEPROM.
author | Daniel O'Connor <darius@dons.net.au> |
---|---|
date | Sun, 07 Jul 2013 22:49:02 +0930 |
parents | 488085e0c7e1 |
children | fc21fb5b171b |
line wrap: on
line source
/* * SD card code * * Copyright (c) 2013 * Daniel O'Connor <darius@dons.net.au>. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include <assert.h> #include <inttypes.h> #include <stdio.h> #include <stdint.h> #include <stdlib.h> #include <string.h> #include "ff.h" #include "stm32f10x.h" #include "sd.h" #include "stm32_eval_sdio_sd.h" #define FAT_YEAR(d) ((((d) & 0xfe00) >> 9) + 1980) #define FAT_MONTH(d) (((d) & 0x01e0) >> 5) #define FAT_DAY(d) (((d) & 0x001f) >> 0) #define FAT_HOUR(t) (((t) & 0xf800) >> 11) #define FAT_MIN(t) (((t) & 0x07e0) >> 5) #define FAT_SEC(t) (((t) & 0x001f) << 1) static FATFS fsh; static void sd_domount(void); char *sderr2str(SD_Error err); void dump_buf(uint8_t *buf, uint32_t size); void sd_init(void) { sd_domount(); } void sd_domount(void) { SD_Error err; FRESULT fserr; if ((err = SD_Init()) != SD_OK) { printf("Failed init: %s\n", sderr2str(err)); return; } if ((fserr = f_mount(0, &fsh)) != FR_OK) { printf("Unable to mount FS\n"); return; } } void sd_cmd(int argc, char **argv) { SD_Error err; if (argc < 1) { printf("No command specified\n"); return; } if (!strcmp(argv[0], "info")) { SD_CardInfo cardinfo; if ((err = SD_GetCardInfo(&cardinfo)) != SD_OK) { printf("Get card info failed: %s\r\b", sderr2str(err)); } else { printf("Mfg ID %" PRIu8 ", OEM %" PRIu16 ", Prod1 %" PRIu32 ", Prod2 %" PRIu8 ", Rev %" PRIu8 ", SN %" PRIu32 ", Mfg %" PRIu16 "\n", cardinfo.SD_cid.ManufacturerID, cardinfo.SD_cid.OEM_AppliID, cardinfo.SD_cid.ProdName1, cardinfo.SD_cid.ProdName2, cardinfo.SD_cid.ProdRev, cardinfo.SD_cid.ProdSN, cardinfo.SD_cid.ManufactDate); printf("Capacity %" PRIu32 ", blocksize %" PRIu32 "\n", cardinfo.CardCapacity, cardinfo.CardBlockSize); } } else if (!strcmp(argv[0], "mount")) { sd_domount(); } else if (!strcmp(argv[0], "rdb")) { uint32_t addr; uint8_t *buf; if (argc != 2) { printf("Block to read not specified\n"); return; } addr = atoi(argv[1]); if ((buf = malloc(SD_BLOCK_SIZE)) == NULL) { printf("Unable to allocate buffer\n"); return; } /* If passed values not modulo 512 it hangs */ if ((err = SD_ReadBlock(buf, addr * SD_BLOCK_SIZE, SD_BLOCK_SIZE)) != SD_OK) { printf("Read block returned %s\n", sderr2str(err)); goto read_exit; } #ifdef SD_DMA_MODE if ((err = SD_WaitReadOperation()) != SD_OK) { printf("Wait returned %s\n", sderr2str(err)); goto read_exit; } #endif while(SD_GetStatus() != SD_TRANSFER_OK) ; dump_buf(buf, SD_BLOCK_SIZE); read_exit: free(buf); } else if (!strcmp(argv[0], "wrb")) { uint32_t addr; uint8_t *buf; int32_t i; if (argc < 3) { printf("Block to read and/or fill value(s) not specified\n"); return; } addr = atoi(argv[1]); if ((buf = malloc(SD_BLOCK_SIZE)) == NULL) { printf("Unable to allocate buffer\n"); return; } for (i = 0; i < SD_BLOCK_SIZE; i++) { //buf[i] = atoi(argv[(i % (argc - 2)) + 2]); if (i < argc - 2) buf[i] = atoi(argv[i + 2]); else buf[i] = 0; } /* If passed values not modulo 512 it hangs */ if ((err = SD_WriteBlock(buf, addr * SD_BLOCK_SIZE, SD_BLOCK_SIZE)) != SD_OK) { printf("Write block returned %s\n", sderr2str(err)); goto write_exit; } #ifdef SD_DMA_MODE if ((err = SD_WaitWriteOperation()) != SD_OK) { printf("Wait returned %s\n", sderr2str(err)); goto write_exit; } #endif while(SD_GetStatus() != SD_TRANSFER_OK) ; write_exit: free(buf); } else if (!strcmp(argv[0], "erase")) { uint32_t addr; if (argc != 2) { printf("Block to erase not specified\n"); return; } addr = atoi(argv[1]); if ((err = SD_Erase(addr * SD_BLOCK_SIZE, (addr + 1) * SD_BLOCK_SIZE)) != SD_OK) { printf("Erase block returned %s\n", sderr2str(err)); goto read_exit; } #ifdef SD_DMA_MODE if ((err = SD_WaitReadOperation()) != SD_OK) { printf("Wait returned %s\n", sderr2str(err)); goto read_exit; } #endif while(SD_GetStatus() != SD_TRANSFER_OK) ; printf("Erased OK\n"); } else if (!strcmp(argv[0], "mkfs")) { FRESULT fserr; if ((fserr = f_mkfs(0, 0, 0)) != FR_OK) { printf("Unable to mkfs: %d\n", fserr); } } else if (!strcmp(argv[0], "ls")) { FRESULT fserr; DIR d; FILINFO fno; char *fn; char label[12]; DWORD sn; if ((fserr = f_getlabel("", label, &sn)) != FR_OK) { printf("Unable to read label: %d\n", fserr); } else { printf("Label: %s Serial: %ld\n", label, sn); } if ((fserr = f_opendir(&d, argc == 1 ? "\\" : argv[1])) != FR_OK) { printf("Unable to opendir: %d\n", fserr); return; } for (;;) { fserr = f_readdir(&d, &fno); if (fserr != FR_OK) { printf("Readdir failed: %d\n", fserr); break; } if (fno.fname[0] == '\0') break; #if _USE_LFN fn = *fno.lfname ? fno.lfname : fno.fname; #else fn = fno.fname; #endif printf("%-12s %5lu %d/%d/%d %02d:%02d:%02d %s%s%s%s%s\n", fn, fno.fsize, FAT_YEAR(fno.fdate), FAT_MONTH(fno.fdate), FAT_DAY(fno.fdate), FAT_HOUR(fno.ftime), FAT_MIN(fno.ftime), FAT_SEC(fno.ftime), fno.fattrib & AM_DIR ? "D" : "", fno.fattrib & AM_RDO ? "R" : "", fno.fattrib & AM_HID ? "H" : "", fno.fattrib & AM_SYS ? "S" : "", fno.fattrib & AM_ARC ? "A" : ""); } } else if (!strcmp(argv[0], "cat")) { FRESULT fserr; FIL f; char buf[128]; if (argc != 2) { printf("No file given\n"); return; } if ((fserr = f_open(&f, argv[1], FA_READ)) != FR_OK) { printf("Failed to open file: %d\n", fserr); return; } while (f_gets(buf, sizeof(buf), &f) != NULL) fputs(buf, stdout); f_close(&f); } else if (!strcmp(argv[0], "wr")) { FRESULT fserr; FIL f; if (argc != 3) { printf("No file and/or text given\n"); return; } if ((fserr = f_open(&f, argv[1], FA_WRITE | FA_OPEN_ALWAYS)) != FR_OK) { printf("Failed to open file: %d\n", fserr); return; } if ((fserr = f_lseek(&f, f_size(&f))) != FR_OK) { printf("Failed to seek to end of file: %d\n", fserr); goto wr_out; } f_puts(argv[2], &f); f_putc('\n', &f); wr_out: f_close(&f); } else if (!strcmp(argv[0], "rm")) { FRESULT fserr; if (argc != 2) { printf("No file given\n"); return; } if ((fserr = f_unlink(argv[1])) != FR_OK) { printf("Failed to remove file: %d\n", fserr); return; } } else { printf("Unknown command\n"); } } void SD_LowLevel_DeInit(void) { GPIO_InitTypeDef GPIO_InitStructure; /*!< Disable SDIO Clock */ SDIO_ClockCmd(DISABLE); /*!< Set Power State to OFF */ SDIO_SetPowerState(SDIO_PowerState_OFF); /*!< DeInitializes the SDIO peripheral */ SDIO_DeInit(); /*!< Disable the SDIO AHB Clock */ RCC_AHBPeriphClockCmd(RCC_AHBPeriph_SDIO, DISABLE); /*!< Configure PC.08, PC.09, PC.10, PC.11, PC.12 pin: D0, D1, D2, D3, CLK pin */ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9 | GPIO_Pin_10 | GPIO_Pin_11 | GPIO_Pin_12; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIO_Init(GPIOC, &GPIO_InitStructure); /*!< Configure PD.02 CMD line */ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2; GPIO_Init(GPIOD, &GPIO_InitStructure); } void SD_LowLevel_Init(void) { GPIO_InitTypeDef GPIO_InitStructure; /* GPIOC and GPIOD Periph clock enable */ RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOD, ENABLE); /* Configure PC.08, PC.09, PC.10, PC.11, PC.12 pin: D0, D1, D2, D3, CLK pin */ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9 | GPIO_Pin_10 | GPIO_Pin_11 | GPIO_Pin_12; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_Init(GPIOC, &GPIO_InitStructure); /* Configure PD.02 CMD line */ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2; GPIO_Init(GPIOD, &GPIO_InitStructure); #ifdef SD_HAVE_DETECT RCC_APB2PeriphClockCmd(SD_DETECT_GPIO_CLK, ENABLE); /* Configure SD_SPI_DETECT_PIN pin: SD Card detect pin */ GPIO_InitStructure.GPIO_Pin = SD_DETECT_PIN; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; GPIO_Init(SD_DETECT_GPIO_PORT, &GPIO_InitStructure); #endif /* Enable the SDIO AHB Clock */ RCC_AHBPeriphClockCmd(RCC_AHBPeriph_SDIO, ENABLE); #ifdef SD_DMA_MODE /* Enable the DMA2 Clock */ RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA2, ENABLE); #endif } void SD_LowLevel_DMA_RxConfig(uint32_t *BufferDST, uint32_t BufferSize) { DMA_InitTypeDef DMA_InitStructure; DMA_ClearFlag(DMA2_FLAG_TC4 | DMA2_FLAG_TE4 | DMA2_FLAG_HT4 | DMA2_FLAG_GL4); /* DMA2 Channel4 disable */ DMA_Cmd(DMA2_Channel4, DISABLE); /* DMA2 Channel4 Config */ DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)0x40018080; DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)BufferDST; DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; DMA_InitStructure.DMA_BufferSize = BufferSize / 4; DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word; DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Word; DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; DMA_InitStructure.DMA_Priority = DMA_Priority_High; DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; DMA_Init(DMA2_Channel4, &DMA_InitStructure); /* DMA2 Channel4 enable */ DMA_Cmd(DMA2_Channel4, ENABLE); } void SD_LowLevel_DMA_TxConfig(uint32_t *BufferSRC, uint32_t BufferSize) { DMA_InitTypeDef DMA_InitStructure; DMA_ClearFlag(DMA2_FLAG_TC4 | DMA2_FLAG_TE4 | DMA2_FLAG_HT4 | DMA2_FLAG_GL4); /* DMA2 Channel4 disable */ DMA_Cmd(DMA2_Channel4, DISABLE); /* DMA2 Channel4 Config */ DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)0x40018080; DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)BufferSRC; DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST; DMA_InitStructure.DMA_BufferSize = BufferSize / 4; DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word; DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Word; DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; DMA_InitStructure.DMA_Priority = DMA_Priority_High; DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; DMA_Init(DMA2_Channel4, &DMA_InitStructure); /* DMA2 Channel4 enable */ DMA_Cmd(DMA2_Channel4, ENABLE); } uint32_t SD_DMAEndOfTransferStatus(void) { return (uint32_t)DMA_GetFlagStatus(DMA2_FLAG_TC4); } char * sderr2str(SD_Error err) { switch (err) { case SD_CMD_CRC_FAIL: return "CMD_CRC_FAIL"; case SD_DATA_CRC_FAIL: return "DATA_CRC_FAIL"; case SD_CMD_RSP_TIMEOUT: return "CMD_RSP_TIMEOUT"; case SD_DATA_TIMEOUT: return "DATA_TIMEOUT"; case SD_TX_UNDERRUN: return "TX_UNDERRUN"; case SD_RX_OVERRUN: return "RX_OVERRUN"; case SD_START_BIT_ERR: return "START_BIT_ERR"; case SD_CMD_OUT_OF_RANGE: return "CMD_OUT_OF_RANGE"; case SD_ADDR_MISALIGNED: return "ADDR_MISALIGNED"; case SD_BLOCK_LEN_ERR: return "BLOCK_LEN_ERR"; case SD_ERASE_SEQ_ERR: return "ERASE_SEQ_ERR"; case SD_BAD_ERASE_PARAM: return "BAD_ERASE_PARAM"; case SD_WRITE_PROT_VIOLATION: return "WRITE_PROT_VIOLATION"; case SD_LOCK_UNLOCK_FAILED: return "LOCK_UNLOCK_FAILED"; case SD_COM_CRC_FAILED: return "COM_CRC_FAILED"; case SD_ILLEGAL_CMD: return "ILLEGAL_CMD"; case SD_CARD_ECC_FAILED: return "CARD_ECC_FAILED"; case SD_CC_ERROR: return "CC_ERROR"; case SD_GENERAL_UNKNOWN_ERROR: return "GENERAL_UNKNOWN_ERROR"; case SD_STREAM_READ_UNDERRUN: return "STREAM_READ_UNDERRUN"; case SD_STREAM_WRITE_OVERRUN: return "STREAM_WRITE_OVERRUN"; case SD_CID_CSD_OVERWRITE: return "OVERWRITE"; case SD_WP_ERASE_SKIP: return "WP_ERASE_SKIP"; case SD_CARD_ECC_DISABLED: return "CARD_ECC_DISABLED"; case SD_ERASE_RESET: return "ERASE_RESET"; case SD_AKE_SEQ_ERROR: return "AKE_SEQ_ERROR"; case SD_INVALID_VOLTRANGE: return "INVALID_VOLTRANGE"; case SD_ADDR_OUT_OF_RANGE: return "ADDR_OUT_OF_RANGE"; case SD_SWITCH_ERROR: return "SWITCH_ERROR"; case SD_SDIO_DISABLED: return "SDIO_DISABLED"; case SD_SDIO_FUNCTION_BUSY: return "SDIO_FUNCTION_BUSY"; case SD_SDIO_FUNCTION_FAILED: return "SDIO_FUNCTION_FAILED"; case SD_SDIO_UNKNOWN_FUNCTION: return "SDIO_UNKNOWN_FUNCTION"; case SD_INTERNAL_ERROR: return "INTERNAL_ERROR"; case SD_NOT_CONFIGURED: return "NOT_CONFIGURED"; case SD_REQUEST_PENDING: return "REQUEST_PENDING"; case SD_REQUEST_NOT_APPLICABLE: return "REQUEST_NOT_APPLICABLE"; case SD_INVALID_PARAMETER: return "INVALID_PARAMETER"; case SD_UNSUPPORTED_FEATURE: return "UNSUPPORTED_FEATURE"; case SD_UNSUPPORTED_HW: return "UNSUPPORTED_HW"; case SD_ERROR: return "ERROR"; case SD_OK: return "OK"; default: return "Unknown"; } } void dump_buf(uint8_t *buf, uint32_t size) { uint32_t i; for (i = 0; i < size; i += 16) { printf("0x%04lx: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", i, buf[i + 0], buf[i + 1], buf[i + 2], buf[i + 3], buf[i + 4], buf[i + 5], buf[i + 6], buf[i + 7], buf[i + 8], buf[i + 9], buf[i + 10], buf[i + 11], buf[i + 12], buf[i + 13], buf[i + 14], buf[i + 15]); } } void SDIO_IRQHandler(void) { /* Process All SDIO Interrupt Sources */ SD_ProcessIRQSrc(); }