/* ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ #include #include "ch.h" #include "hal.h" #include "shell.h" #include "chprintf.h" #include "ff.h" #define SDC_DATA_DESTRUCTIVE_TEST FALSE #define SDC_BURST_SIZE 8 /* how many sectors reads at once */ static uint8_t outbuf[MMCSD_BLOCK_SIZE * SDC_BURST_SIZE + 1]; static uint8_t inbuf[MMCSD_BLOCK_SIZE * SDC_BURST_SIZE + 1]; /* FS object.*/ static FATFS SDC_FS; /* FS mounted and ready.*/ static bool_t fs_ready = FALSE; /** * @brief Parody of UNIX badblocks program. * * @param[in] start first block to check * @param[in] end last block to check * @param[in] blockatonce number of blocks to check at once * @param[in] pattern check pattern * * @return The operation status. * @retval SDC_SUCCESS operation succeeded, the requested blocks have been * read. * @retval SDC_FAILED operation failed, the state of the buffer is uncertain. */ bool_t badblocks(uint32_t start, uint32_t end, uint32_t blockatonce, uint8_t pattern){ uint32_t position = 0; uint32_t i = 0; chDbgCheck(blockatonce <= SDC_BURST_SIZE, "badblocks"); /* fill control buffer */ for (i=0; i < MMCSD_BLOCK_SIZE * blockatonce; i++) outbuf[i] = pattern; /* fill SD card with pattern. */ position = start; while (position < end){ if (sdcWrite(&SDCD1, position, outbuf, blockatonce)) goto ERROR; position += blockatonce; } /* read and compare. */ position = start; while (position < end){ if (sdcRead(&SDCD1, position, inbuf, blockatonce)) goto ERROR; if (memcmp(inbuf, outbuf, blockatonce * MMCSD_BLOCK_SIZE) != 0) goto ERROR; position += blockatonce; } return FALSE; ERROR: return TRUE; } /** * */ void fillbuffer(uint8_t pattern, uint8_t *b){ uint32_t i = 0; for (i=0; i < MMCSD_BLOCK_SIZE * SDC_BURST_SIZE; i++) b[i] = pattern; } /** * */ void fillbuffers(uint8_t pattern){ fillbuffer(pattern, inbuf); fillbuffer(pattern, outbuf); } /** * */ void cmd_sdiotest(BaseSequentialStream *chp, int argc, char *argv[]){ (void)argc; (void)argv; uint32_t i = 0; chprintf(chp, "Trying to connect SDIO... "); chThdSleepMilliseconds(100); if (!sdcConnect(&SDCD1)) { chprintf(chp, "OK\r\n"); chprintf(chp, "*** Card CSD content is: "); chprintf(chp, "%X %X %X %X \r\n", (&SDCD1)->csd[3], (&SDCD1)->csd[2], (&SDCD1)->csd[1], (&SDCD1)->csd[0]); chprintf(chp, "Single aligned read..."); chThdSleepMilliseconds(100); if (sdcRead(&SDCD1, 0, inbuf, 1)) chSysHalt(); chprintf(chp, " OK\r\n"); chThdSleepMilliseconds(100); chprintf(chp, "Single unaligned read..."); chThdSleepMilliseconds(100); if (sdcRead(&SDCD1, 0, inbuf + 1, 1)) chSysHalt(); if (sdcRead(&SDCD1, 0, inbuf + 2, 1)) chSysHalt(); if (sdcRead(&SDCD1, 0, inbuf + 3, 1)) chSysHalt(); chprintf(chp, " OK\r\n"); chThdSleepMilliseconds(100); chprintf(chp, "Multiple aligned reads..."); chThdSleepMilliseconds(100); fillbuffers(0x55); /* fill reference buffer from SD card */ if (sdcRead(&SDCD1, 0, inbuf, SDC_BURST_SIZE)) chSysHalt(); for (i=0; i<1000; i++){ if (sdcRead(&SDCD1, 0, outbuf, SDC_BURST_SIZE)) chSysHalt(); if (memcmp(inbuf, outbuf, SDC_BURST_SIZE * MMCSD_BLOCK_SIZE) != 0) chSysHalt(); } chprintf(chp, " OK\r\n"); chThdSleepMilliseconds(100); chprintf(chp, "Multiple unaligned reads..."); chThdSleepMilliseconds(100); fillbuffers(0x55); /* fill reference buffer from SD card */ if (sdcRead(&SDCD1, 0, inbuf + 1, SDC_BURST_SIZE)) chSysHalt(); for (i=0; i<1000; i++){ if (sdcRead(&SDCD1, 0, outbuf + 1, SDC_BURST_SIZE)) chSysHalt(); if (memcmp(inbuf, outbuf, SDC_BURST_SIZE * MMCSD_BLOCK_SIZE) != 0) chSysHalt(); } chprintf(chp, " OK\r\n"); chThdSleepMilliseconds(100); #if SDC_DATA_DESTRUCTIVE_TEST chprintf(chp, "Single aligned write..."); chThdSleepMilliseconds(100); fillbuffer(0xAA, inbuf); if (sdcWrite(&SDCD1, 0, inbuf, 1)) chSysHalt(); fillbuffer(0, outbuf); if (sdcRead(&SDCD1, 0, outbuf, 1)) chSysHalt(); if (memcmp(inbuf, outbuf, MMCSD_BLOCK_SIZE) != 0) chSysHalt(); chprintf(chp, " OK\r\n"); chprintf(chp, "Single unaligned write..."); chThdSleepMilliseconds(100); fillbuffer(0xFF, inbuf); if (sdcWrite(&SDCD1, 0, inbuf+1, 1)) chSysHalt(); fillbuffer(0, outbuf); if (sdcRead(&SDCD1, 0, outbuf+1, 1)) chSysHalt(); if (memcmp(inbuf+1, outbuf+1, MMCSD_BLOCK_SIZE) != 0) chSysHalt(); chprintf(chp, " OK\r\n"); chprintf(chp, "Running badblocks at 0x10000 offset..."); chThdSleepMilliseconds(100); if(badblocks(0x10000, 0x11000, SDC_BURST_SIZE, 0xAA)) chSysHalt(); chprintf(chp, " OK\r\n"); #endif /* !SDC_DATA_DESTRUCTIVE_TEST */ /** * Now perform some FS tests. */ FRESULT err; uint32_t clusters; FATFS *fsp; FIL FileObject; uint32_t bytes_written; uint32_t bytes_read; FILINFO filinfo; uint8_t teststring[] = {"This is test file\r\n"}; chprintf(chp, "Register working area for filesystem... "); chThdSleepMilliseconds(100); err = f_mount(0, &SDC_FS); if (err != FR_OK){ chSysHalt(); } else{ fs_ready = TRUE; chprintf(chp, "OK\r\n"); } #if SDC_DATA_DESTRUCTIVE_TEST chprintf(chp, "Formatting... "); chThdSleepMilliseconds(100); err = f_mkfs (0,0,0); if (err != FR_OK){ chSysHalt(); } else{ chprintf(chp, "OK\r\n"); } #endif /* SDC_DATA_DESTRUCTIVE_TEST */ chprintf(chp, "Mount filesystem... "); chThdSleepMilliseconds(100); err = f_getfree("/", &clusters, &fsp); if (err != FR_OK) { chSysHalt(); } chprintf(chp, "OK\r\n"); chprintf(chp, "FS: %lu free clusters, %lu sectors per cluster, %lu bytes free\r\n", clusters, (uint32_t)SDC_FS.csize, clusters * (uint32_t)SDC_FS.csize * (uint32_t)MMCSD_BLOCK_SIZE); chprintf(chp, "Create file \"chtest.txt\"... "); chThdSleepMilliseconds(100); err = f_open(&FileObject, "0:chtest.txt", FA_WRITE | FA_OPEN_ALWAYS); if (err != FR_OK) { chSysHalt(); } chprintf(chp, "OK\r\n"); chprintf(chp, "Write some data in it... "); chThdSleepMilliseconds(100); err = f_write(&FileObject, teststring, sizeof(teststring), (void *)&bytes_written); if (err != FR_OK) { chSysHalt(); } else chprintf(chp, "OK\r\n"); chprintf(chp, "Close file \"chtest.txt\"... "); err = f_close(&FileObject); if (err != FR_OK) { chSysHalt(); } else chprintf(chp, "OK\r\n"); chprintf(chp, "Check file size \"chtest.txt\"... "); err = f_stat("0:chtest.txt", &filinfo); chThdSleepMilliseconds(100); if (err != FR_OK) { chSysHalt(); } else{ if (filinfo.fsize == sizeof(teststring)) chprintf(chp, "OK\r\n"); else chSysHalt(); } chprintf(chp, "Check file content \"chtest.txt\"... "); err = f_open(&FileObject, "0:chtest.txt", FA_READ | FA_OPEN_EXISTING); chThdSleepMilliseconds(100); if (err != FR_OK) { chSysHalt(); } uint8_t buf[sizeof(teststring)]; err = f_read(&FileObject, buf, sizeof(teststring), (void *)&bytes_read); if (err != FR_OK) { chSysHalt(); } else{ if (memcmp(teststring, buf, sizeof(teststring)) != 0){ chSysHalt(); } else{ chprintf(chp, "OK\r\n"); } } chprintf(chp, "Umount filesystem... "); f_mount(0, NULL); chprintf(chp, "OK\r\n"); chprintf(chp, "Disconnecting from SDIO..."); chThdSleepMilliseconds(100); if (sdcDisconnect(&SDCD1)) chSysHalt(); chprintf(chp, " OK\r\n"); chprintf(chp, "------------------------------------------------------\r\n"); chprintf(chp, "All tests passed successfully.\r\n"); chThdSleepMilliseconds(100); } else{ chSysHalt(); } } /* * SDIO configuration. */ static const SDCConfig sdccfg = { 0 }; /** * */ static SerialConfig ser_cfg = { 115200, 0, 0, 0, }; static const ShellCommand commands[] = { {"sdiotest", cmd_sdiotest}, {NULL, NULL} }; static const ShellConfig shell_cfg1 = { (BaseSequentialStream *)&SD2, commands }; /* * Application entry point. */ int main(void) { halInit(); chSysInit(); /* start debugging serial link */ sdStart(&SD2, &ser_cfg); shellInit(); static WORKING_AREA(waShell, 2048); shellCreateStatic(&shell_cfg1, waShell, sizeof(waShell), NORMALPRIO); /* * Initializes the SDIO drivers. */ sdcStart(&SDCD1, &sdccfg); /* * Normal main() thread activity. * Blinking signaling about successful passing. */ while (TRUE) { palTogglePad(GPIOB, GPIOB_LED_R); chThdSleepMilliseconds(100); } }