Dependencies:   mbed

https://os.mbed.com/media/uploads/el18gs/pixil-frame-0.png

GHOST HUNTER

In a world of ghostly horrors there is much money to be made in underground ghost fighting rings. You've managed to get hold of a Ghostbuster, a special piece of equipment that allows you to catch, train and fight ghosts.

Instructions

Below you will find the instructions for the game. Please note that due to COVID-19 a large part of the game (fighting ghosts) could not be added as it would have required access to a second gamepad which i could not acquire.

Welcome screen

When first started you will be presented with a welcome screen

  • Pot 1 to adjust the contrast on the screen
  • Press A to continue.

Main menu

You have three options, catch ghosts (add ghosts to your inventory), inventory (sell ghosts) or settings(adjust the games settings).

  • Press X and B to move the selection up and down respectively
  • Press A to enter the selected submenu

Catch Ghost

Will now be presented with two challenges. In the first you need to find a ghost, in the second you catch it. Theses stages will start automatically.

Find ghost

Rotate the gamepad on its roll and pitch axis until all the LED's turn on. The ones on the left indicate roll and the right pitch.

  • Rotate the gamepad on it roll and pitch to light up the LED's

Catch ghost

Return the gamepad to a comfortable position and use the joystick to move the crosshairs onto the ghost sprite. When ready press the A button to catch the ghost. You will be told what kind of ghost you have captured and it will be added to your inventory.

  • Press A to catch the ghost
  • Move the joystick to move the crosshairs

Inventory

The inventory allows you to view your ghosts and sell them.

  • Use Pot 1 to scroll through the ghosts
  • Pot 2 to scroll up and down the details of the individual ghosts
  • Press X to prepare to sell a ghost and press again to confirm, if you don't press again the sale screen will disappear after 5 seconds
  • Press Start to return to the main menu

Settings

This menu allows you to adjust some of the settings of the game.

  • Press X to go up one option
  • Press B to go down one option
  • Press A to enter the selected submenu
  • Press Start to return to the main menu

Contrast

Set the contrast of the LCD screen, the contrast will adjust on this screen so you can see the effect (contrast is bounded between 0.4 and 0.6).

  • Pot 1 to increase or decrease the contrast
  • Press A to set the contrast

Button Delay

Set the minimum time between button presses; if this is too low the game will detect two button presses when there was only one, too high and the buttons will seem unresponsive. So as to ensure these issues do not occur while changing the setting button X temporarily operates on the new delay but none of the others will until A is pressed.

  • Pot 1 to increase or decrease the delay
  • Press X to test the new delay, this will toggle the small circle to be filled in or unfilled
  • Press A to save the setting
Committer:
el18gs
Date:
Tue May 26 13:37:32 2020 +0000
Revision:
17:3ebcf7bba112
Parent:
2:eaf245af2aae
Final Submission. I have read and agreed with Statement of Academic Integrity.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
el18gs 2:eaf245af2aae 1 /* SD/MMC File System Library
el18gs 2:eaf245af2aae 2 * Copyright (c) 2016 Neil Thiessen
el18gs 2:eaf245af2aae 3 *
el18gs 2:eaf245af2aae 4 * Licensed under the Apache License, Version 2.0 (the "License");
el18gs 2:eaf245af2aae 5 * you may not use this file except in compliance with the License.
el18gs 2:eaf245af2aae 6 * You may obtain a copy of the License at
el18gs 2:eaf245af2aae 7 *
el18gs 2:eaf245af2aae 8 * http://www.apache.org/licenses/LICENSE-2.0
el18gs 2:eaf245af2aae 9 *
el18gs 2:eaf245af2aae 10 * Unless required by applicable law or agreed to in writing, software
el18gs 2:eaf245af2aae 11 * distributed under the License is distributed on an "AS IS" BASIS,
el18gs 2:eaf245af2aae 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
el18gs 2:eaf245af2aae 13 * See the License for the specific language governing permissions and
el18gs 2:eaf245af2aae 14 * limitations under the License.
el18gs 2:eaf245af2aae 15 */
el18gs 2:eaf245af2aae 16
el18gs 2:eaf245af2aae 17 #include "SDFileSystem.h"
el18gs 2:eaf245af2aae 18 #include "diskio.h"
el18gs 2:eaf245af2aae 19 #include "pinmap.h"
el18gs 2:eaf245af2aae 20 #include "SDCRC.h"
el18gs 2:eaf245af2aae 21
el18gs 2:eaf245af2aae 22 SDFileSystem::SDFileSystem(PinName mosi, PinName miso, PinName sclk, PinName cs, const char* name, PinName cd, SwitchType cdtype, int hz)
el18gs 2:eaf245af2aae 23 : FATFileSystem(name),
el18gs 2:eaf245af2aae 24 m_Spi(mosi, miso, sclk),
el18gs 2:eaf245af2aae 25 m_Cs(cs, 1),
el18gs 2:eaf245af2aae 26 m_Cd(cd),
el18gs 2:eaf245af2aae 27 m_FREQ(hz)
el18gs 2:eaf245af2aae 28 {
el18gs 2:eaf245af2aae 29 //Initialize the member variables
el18gs 2:eaf245af2aae 30 m_CardType = CARD_NONE;
el18gs 2:eaf245af2aae 31 m_Crc = true;
el18gs 2:eaf245af2aae 32 m_LargeFrames = false;
el18gs 2:eaf245af2aae 33 m_WriteValidation = true;
el18gs 2:eaf245af2aae 34 m_Status = STA_NOINIT;
el18gs 2:eaf245af2aae 35
el18gs 2:eaf245af2aae 36 //Enable the internal pull-up resistor on MISO
el18gs 2:eaf245af2aae 37 pin_mode(miso, PullUp);
el18gs 2:eaf245af2aae 38
el18gs 2:eaf245af2aae 39 //Configure the SPI bus
el18gs 2:eaf245af2aae 40 m_Spi.format(8, 0);
el18gs 2:eaf245af2aae 41
el18gs 2:eaf245af2aae 42 //Configure the card detect pin
el18gs 2:eaf245af2aae 43 if (cdtype == SWITCH_POS_NO) {
el18gs 2:eaf245af2aae 44 m_Cd.mode(PullDown);
el18gs 2:eaf245af2aae 45 m_CdAssert = 1;
el18gs 2:eaf245af2aae 46 m_Cd.fall(this, &SDFileSystem::onCardRemoval);
el18gs 2:eaf245af2aae 47 } else if (cdtype == SWITCH_POS_NC) {
el18gs 2:eaf245af2aae 48 m_Cd.mode(PullDown);
el18gs 2:eaf245af2aae 49 m_CdAssert = 0;
el18gs 2:eaf245af2aae 50 m_Cd.rise(this, &SDFileSystem::onCardRemoval);
el18gs 2:eaf245af2aae 51 } else if (cdtype == SWITCH_NEG_NO) {
el18gs 2:eaf245af2aae 52 m_Cd.mode(PullUp);
el18gs 2:eaf245af2aae 53 m_CdAssert = 0;
el18gs 2:eaf245af2aae 54 m_Cd.rise(this, &SDFileSystem::onCardRemoval);
el18gs 2:eaf245af2aae 55 } else if (cdtype == SWITCH_NEG_NC) {
el18gs 2:eaf245af2aae 56 m_Cd.mode(PullUp);
el18gs 2:eaf245af2aae 57 m_CdAssert = 1;
el18gs 2:eaf245af2aae 58 m_Cd.fall(this, &SDFileSystem::onCardRemoval);
el18gs 2:eaf245af2aae 59 } else {
el18gs 2:eaf245af2aae 60 m_CdAssert = -1;
el18gs 2:eaf245af2aae 61 }
el18gs 2:eaf245af2aae 62 }
el18gs 2:eaf245af2aae 63
el18gs 2:eaf245af2aae 64 bool SDFileSystem::card_present()
el18gs 2:eaf245af2aae 65 {
el18gs 2:eaf245af2aae 66 //Check the card socket
el18gs 2:eaf245af2aae 67 checkSocket();
el18gs 2:eaf245af2aae 68
el18gs 2:eaf245af2aae 69 //Return whether or not a card is present
el18gs 2:eaf245af2aae 70 return !(m_Status & STA_NODISK);
el18gs 2:eaf245af2aae 71 }
el18gs 2:eaf245af2aae 72
el18gs 2:eaf245af2aae 73 SDFileSystem::CardType SDFileSystem::card_type()
el18gs 2:eaf245af2aae 74 {
el18gs 2:eaf245af2aae 75 //Check the card socket
el18gs 2:eaf245af2aae 76 checkSocket();
el18gs 2:eaf245af2aae 77
el18gs 2:eaf245af2aae 78 //Return the card type
el18gs 2:eaf245af2aae 79 return m_CardType;
el18gs 2:eaf245af2aae 80 }
el18gs 2:eaf245af2aae 81
el18gs 2:eaf245af2aae 82 bool SDFileSystem::crc()
el18gs 2:eaf245af2aae 83 {
el18gs 2:eaf245af2aae 84 //Return whether or not CRC is enabled
el18gs 2:eaf245af2aae 85 return m_Crc;
el18gs 2:eaf245af2aae 86 }
el18gs 2:eaf245af2aae 87
el18gs 2:eaf245af2aae 88 void SDFileSystem::crc(bool enabled)
el18gs 2:eaf245af2aae 89 {
el18gs 2:eaf245af2aae 90 //Check the card socket
el18gs 2:eaf245af2aae 91 checkSocket();
el18gs 2:eaf245af2aae 92
el18gs 2:eaf245af2aae 93 //Just update the member variable if the card isn't initialized
el18gs 2:eaf245af2aae 94 if (m_Status & STA_NOINIT) {
el18gs 2:eaf245af2aae 95 m_Crc = enabled;
el18gs 2:eaf245af2aae 96 return;
el18gs 2:eaf245af2aae 97 }
el18gs 2:eaf245af2aae 98
el18gs 2:eaf245af2aae 99 //Enable or disable CRC
el18gs 2:eaf245af2aae 100 if (enabled && !m_Crc) {
el18gs 2:eaf245af2aae 101 //Send CMD59(0x00000001) to enable CRC
el18gs 2:eaf245af2aae 102 m_Crc = true;
el18gs 2:eaf245af2aae 103 commandTransaction(CMD59, 0x00000001);
el18gs 2:eaf245af2aae 104 } else if (!enabled && m_Crc) {
el18gs 2:eaf245af2aae 105 //Send CMD59(0x00000000) to disable CRC
el18gs 2:eaf245af2aae 106 commandTransaction(CMD59, 0x00000000);
el18gs 2:eaf245af2aae 107 m_Crc = false;
el18gs 2:eaf245af2aae 108 }
el18gs 2:eaf245af2aae 109 }
el18gs 2:eaf245af2aae 110
el18gs 2:eaf245af2aae 111 bool SDFileSystem::large_frames()
el18gs 2:eaf245af2aae 112 {
el18gs 2:eaf245af2aae 113 //Return whether or not 16-bit frames are enabled
el18gs 2:eaf245af2aae 114 return m_LargeFrames;
el18gs 2:eaf245af2aae 115 }
el18gs 2:eaf245af2aae 116
el18gs 2:eaf245af2aae 117 void SDFileSystem::large_frames(bool enabled)
el18gs 2:eaf245af2aae 118 {
el18gs 2:eaf245af2aae 119 //Set whether or not 16-bit frames are enabled
el18gs 2:eaf245af2aae 120 m_LargeFrames = enabled;
el18gs 2:eaf245af2aae 121 }
el18gs 2:eaf245af2aae 122
el18gs 2:eaf245af2aae 123 bool SDFileSystem::write_validation()
el18gs 2:eaf245af2aae 124 {
el18gs 2:eaf245af2aae 125 //Return whether or not write validation is enabled
el18gs 2:eaf245af2aae 126 return m_WriteValidation;
el18gs 2:eaf245af2aae 127 }
el18gs 2:eaf245af2aae 128
el18gs 2:eaf245af2aae 129 void SDFileSystem::write_validation(bool enabled)
el18gs 2:eaf245af2aae 130 {
el18gs 2:eaf245af2aae 131 //Set whether or not write validation is enabled
el18gs 2:eaf245af2aae 132 m_WriteValidation = enabled;
el18gs 2:eaf245af2aae 133 }
el18gs 2:eaf245af2aae 134
el18gs 2:eaf245af2aae 135 int SDFileSystem::unmount()
el18gs 2:eaf245af2aae 136 {
el18gs 2:eaf245af2aae 137 //Unmount the filesystem
el18gs 2:eaf245af2aae 138 FATFileSystem::unmount();
el18gs 2:eaf245af2aae 139
el18gs 2:eaf245af2aae 140 //Change the status to not initialized, and the card type to unknown
el18gs 2:eaf245af2aae 141 m_Status |= STA_NOINIT;
el18gs 2:eaf245af2aae 142 m_CardType = CARD_UNKNOWN;
el18gs 2:eaf245af2aae 143
el18gs 2:eaf245af2aae 144 //Always succeeds
el18gs 2:eaf245af2aae 145 return 0;
el18gs 2:eaf245af2aae 146 }
el18gs 2:eaf245af2aae 147
el18gs 2:eaf245af2aae 148 int SDFileSystem::disk_initialize()
el18gs 2:eaf245af2aae 149 {
el18gs 2:eaf245af2aae 150 char token;
el18gs 2:eaf245af2aae 151 unsigned int resp;
el18gs 2:eaf245af2aae 152 Timer timer;
el18gs 2:eaf245af2aae 153
el18gs 2:eaf245af2aae 154 //Make sure there's a card in the socket before proceeding
el18gs 2:eaf245af2aae 155 checkSocket();
el18gs 2:eaf245af2aae 156 if (m_Status & STA_NODISK)
el18gs 2:eaf245af2aae 157 return m_Status;
el18gs 2:eaf245af2aae 158
el18gs 2:eaf245af2aae 159 //Make sure we're not already initialized before proceeding
el18gs 2:eaf245af2aae 160 if (!(m_Status & STA_NOINIT))
el18gs 2:eaf245af2aae 161 return m_Status;
el18gs 2:eaf245af2aae 162
el18gs 2:eaf245af2aae 163 //Set the SPI frequency to 400kHz for initialization
el18gs 2:eaf245af2aae 164 m_Spi.frequency(400000);
el18gs 2:eaf245af2aae 165
el18gs 2:eaf245af2aae 166 //Try to reset the card up to 3 times
el18gs 2:eaf245af2aae 167 for (int f = 0; f < 3; f++) {
el18gs 2:eaf245af2aae 168 //Send 80 dummy clocks with /CS deasserted and DI held high
el18gs 2:eaf245af2aae 169 m_Cs = 1;
el18gs 2:eaf245af2aae 170 for (int i = 0; i < 10; i++) {
el18gs 2:eaf245af2aae 171 m_Spi.write(0xFF);
el18gs 2:eaf245af2aae 172 }
el18gs 2:eaf245af2aae 173
el18gs 2:eaf245af2aae 174 //Send CMD0(0x00000000) to reset the card
el18gs 2:eaf245af2aae 175 token = commandTransaction(CMD0, 0x00000000);
el18gs 2:eaf245af2aae 176 if (token == 0x01) {
el18gs 2:eaf245af2aae 177 break;
el18gs 2:eaf245af2aae 178 }
el18gs 2:eaf245af2aae 179 }
el18gs 2:eaf245af2aae 180
el18gs 2:eaf245af2aae 181 //Check if the card reset
el18gs 2:eaf245af2aae 182 if (token != 0x01) {
el18gs 2:eaf245af2aae 183 //Initialization failed
el18gs 2:eaf245af2aae 184 m_CardType = CARD_UNKNOWN;
el18gs 2:eaf245af2aae 185 return m_Status;
el18gs 2:eaf245af2aae 186 }
el18gs 2:eaf245af2aae 187
el18gs 2:eaf245af2aae 188 //Send CMD59(0x00000001) to enable CRC if necessary
el18gs 2:eaf245af2aae 189 if (m_Crc) {
el18gs 2:eaf245af2aae 190 if (commandTransaction(CMD59, 0x00000001) != 0x01) {
el18gs 2:eaf245af2aae 191 //Initialization failed
el18gs 2:eaf245af2aae 192 m_CardType = CARD_UNKNOWN;
el18gs 2:eaf245af2aae 193 return m_Status;
el18gs 2:eaf245af2aae 194 }
el18gs 2:eaf245af2aae 195 }
el18gs 2:eaf245af2aae 196
el18gs 2:eaf245af2aae 197 //Send CMD8(0x000001AA) to see if this is an SDCv2 card
el18gs 2:eaf245af2aae 198 if (commandTransaction(CMD8, 0x000001AA, &resp) == 0x01) {
el18gs 2:eaf245af2aae 199 //This is an SDCv2 card, get the 32-bit return value and verify the voltage range/check pattern
el18gs 2:eaf245af2aae 200 if ((resp & 0xFFF) != 0x1AA) {
el18gs 2:eaf245af2aae 201 //Initialization failed
el18gs 2:eaf245af2aae 202 m_CardType = CARD_UNKNOWN;
el18gs 2:eaf245af2aae 203 return m_Status;
el18gs 2:eaf245af2aae 204 }
el18gs 2:eaf245af2aae 205
el18gs 2:eaf245af2aae 206 //Send CMD58(0x00000000) to read the OCR, and verify that the card supports 3.2-3.3V
el18gs 2:eaf245af2aae 207 if (commandTransaction(CMD58, 0x00000000, &resp) != 0x01 || !(resp & (1 << 20))) {
el18gs 2:eaf245af2aae 208 //Initialization failed
el18gs 2:eaf245af2aae 209 m_CardType = CARD_UNKNOWN;
el18gs 2:eaf245af2aae 210 return m_Status;
el18gs 2:eaf245af2aae 211 }
el18gs 2:eaf245af2aae 212
el18gs 2:eaf245af2aae 213 //Try to initialize the card using ACMD41(0x40100000) for up to 2 seconds
el18gs 2:eaf245af2aae 214 timer.start();
el18gs 2:eaf245af2aae 215 do {
el18gs 2:eaf245af2aae 216 token = commandTransaction(ACMD41, 0x40100000);
el18gs 2:eaf245af2aae 217 } while (token == 0x01 && timer.read_ms() < 2000);
el18gs 2:eaf245af2aae 218 timer.stop();
el18gs 2:eaf245af2aae 219 timer.reset();
el18gs 2:eaf245af2aae 220
el18gs 2:eaf245af2aae 221 //Check if the card initialized
el18gs 2:eaf245af2aae 222 if (token != 0x00) {
el18gs 2:eaf245af2aae 223 //Initialization failed
el18gs 2:eaf245af2aae 224 m_CardType = CARD_UNKNOWN;
el18gs 2:eaf245af2aae 225 return m_Status;
el18gs 2:eaf245af2aae 226 }
el18gs 2:eaf245af2aae 227
el18gs 2:eaf245af2aae 228 //Send CMD58(0x00000000) to read the OCR
el18gs 2:eaf245af2aae 229 if (commandTransaction(CMD58, 0x00000000, &resp) == 0x00) {
el18gs 2:eaf245af2aae 230 //Check the CCS bit to determine if this is a high capacity card
el18gs 2:eaf245af2aae 231 if (resp & (1 << 30))
el18gs 2:eaf245af2aae 232 m_CardType = CARD_SDHC;
el18gs 2:eaf245af2aae 233 else
el18gs 2:eaf245af2aae 234 m_CardType = CARD_SD;
el18gs 2:eaf245af2aae 235
el18gs 2:eaf245af2aae 236 //Increase the SPI frequency to full speed (up to 50MHz for SDCv2)
el18gs 2:eaf245af2aae 237 if (m_FREQ > 25000000) {
el18gs 2:eaf245af2aae 238 if (enableHighSpeedMode()) {
el18gs 2:eaf245af2aae 239 if (m_FREQ > 50000000) {
el18gs 2:eaf245af2aae 240 m_Spi.frequency(50000000);
el18gs 2:eaf245af2aae 241 } else {
el18gs 2:eaf245af2aae 242 m_Spi.frequency(m_FREQ);
el18gs 2:eaf245af2aae 243 }
el18gs 2:eaf245af2aae 244 } else {
el18gs 2:eaf245af2aae 245 m_Spi.frequency(25000000);
el18gs 2:eaf245af2aae 246 }
el18gs 2:eaf245af2aae 247 } else {
el18gs 2:eaf245af2aae 248 m_Spi.frequency(m_FREQ);
el18gs 2:eaf245af2aae 249 }
el18gs 2:eaf245af2aae 250 } else {
el18gs 2:eaf245af2aae 251 //Initialization failed
el18gs 2:eaf245af2aae 252 m_CardType = CARD_UNKNOWN;
el18gs 2:eaf245af2aae 253 return m_Status;
el18gs 2:eaf245af2aae 254 }
el18gs 2:eaf245af2aae 255 } else {
el18gs 2:eaf245af2aae 256 //Didn't respond or illegal command, this is either an SDCv1 or MMC card
el18gs 2:eaf245af2aae 257 //Send CMD58(0x00000000) to read the OCR, and verify that the card supports 3.2-3.3V
el18gs 2:eaf245af2aae 258 if (commandTransaction(CMD58, 0x00000000, &resp) != 0x01 || !(resp & (1 << 20))) {
el18gs 2:eaf245af2aae 259 //Initialization failed
el18gs 2:eaf245af2aae 260 m_CardType = CARD_UNKNOWN;
el18gs 2:eaf245af2aae 261 return m_Status;
el18gs 2:eaf245af2aae 262 }
el18gs 2:eaf245af2aae 263
el18gs 2:eaf245af2aae 264 //Try to initialize the card using ACMD41(0x40100000) for up to 2 seconds
el18gs 2:eaf245af2aae 265 timer.start();
el18gs 2:eaf245af2aae 266 do {
el18gs 2:eaf245af2aae 267 token = commandTransaction(ACMD41, 0x40100000);
el18gs 2:eaf245af2aae 268 } while (token == 0x01 && timer.read_ms() < 2000);
el18gs 2:eaf245af2aae 269 timer.stop();
el18gs 2:eaf245af2aae 270 timer.reset();
el18gs 2:eaf245af2aae 271
el18gs 2:eaf245af2aae 272 //Check if the card initialized
el18gs 2:eaf245af2aae 273 if (token == 0x00) {
el18gs 2:eaf245af2aae 274 //This is an SDCv1 standard capacity card
el18gs 2:eaf245af2aae 275 m_CardType = CARD_SD;
el18gs 2:eaf245af2aae 276
el18gs 2:eaf245af2aae 277 //Increase the SPI frequency to full speed (up to 25MHz for SDCv1)
el18gs 2:eaf245af2aae 278 if (m_FREQ > 25000000)
el18gs 2:eaf245af2aae 279 m_Spi.frequency(25000000);
el18gs 2:eaf245af2aae 280 else
el18gs 2:eaf245af2aae 281 m_Spi.frequency(m_FREQ);
el18gs 2:eaf245af2aae 282 } else {
el18gs 2:eaf245af2aae 283 //Try to initialize the card using CMD1(0x00100000) for up to 2 seconds
el18gs 2:eaf245af2aae 284 timer.start();
el18gs 2:eaf245af2aae 285 do {
el18gs 2:eaf245af2aae 286 token = commandTransaction(CMD1, 0x00100000);
el18gs 2:eaf245af2aae 287 } while (token == 0x01 && timer.read_ms() < 2000);
el18gs 2:eaf245af2aae 288 timer.stop();
el18gs 2:eaf245af2aae 289 timer.reset();
el18gs 2:eaf245af2aae 290
el18gs 2:eaf245af2aae 291 //Check if the card initialized
el18gs 2:eaf245af2aae 292 if (token == 0x00) {
el18gs 2:eaf245af2aae 293 //This is an MMCv3 card
el18gs 2:eaf245af2aae 294 m_CardType = CARD_MMC;
el18gs 2:eaf245af2aae 295
el18gs 2:eaf245af2aae 296 //Increase the SPI frequency to full speed (up to 20MHz for MMCv3)
el18gs 2:eaf245af2aae 297 if (m_FREQ > 20000000)
el18gs 2:eaf245af2aae 298 m_Spi.frequency(20000000);
el18gs 2:eaf245af2aae 299 else
el18gs 2:eaf245af2aae 300 m_Spi.frequency(m_FREQ);
el18gs 2:eaf245af2aae 301 } else {
el18gs 2:eaf245af2aae 302 //Initialization failed
el18gs 2:eaf245af2aae 303 m_CardType = CARD_UNKNOWN;
el18gs 2:eaf245af2aae 304 return m_Status;
el18gs 2:eaf245af2aae 305 }
el18gs 2:eaf245af2aae 306 }
el18gs 2:eaf245af2aae 307 }
el18gs 2:eaf245af2aae 308
el18gs 2:eaf245af2aae 309 //Send ACMD42(0x00000000) to disconnect the internal pull-up resistor on pin 1 if necessary
el18gs 2:eaf245af2aae 310 if (m_CardType != CARD_MMC) {
el18gs 2:eaf245af2aae 311 if (commandTransaction(ACMD42, 0x00000000) != 0x00) {
el18gs 2:eaf245af2aae 312 //Initialization failed
el18gs 2:eaf245af2aae 313 m_CardType = CARD_UNKNOWN;
el18gs 2:eaf245af2aae 314 return m_Status;
el18gs 2:eaf245af2aae 315 }
el18gs 2:eaf245af2aae 316 }
el18gs 2:eaf245af2aae 317
el18gs 2:eaf245af2aae 318 //Send CMD16(0x00000200) to force the block size to 512B if necessary
el18gs 2:eaf245af2aae 319 if (m_CardType != CARD_SDHC) {
el18gs 2:eaf245af2aae 320 if (commandTransaction(CMD16, 0x00000200) != 0x00) {
el18gs 2:eaf245af2aae 321 //Initialization failed
el18gs 2:eaf245af2aae 322 m_CardType = CARD_UNKNOWN;
el18gs 2:eaf245af2aae 323 return m_Status;
el18gs 2:eaf245af2aae 324 }
el18gs 2:eaf245af2aae 325 }
el18gs 2:eaf245af2aae 326
el18gs 2:eaf245af2aae 327 //The card is now initialized
el18gs 2:eaf245af2aae 328 m_Status &= ~STA_NOINIT;
el18gs 2:eaf245af2aae 329
el18gs 2:eaf245af2aae 330 //Return the disk status
el18gs 2:eaf245af2aae 331 return m_Status;
el18gs 2:eaf245af2aae 332 }
el18gs 2:eaf245af2aae 333
el18gs 2:eaf245af2aae 334 int SDFileSystem::disk_status()
el18gs 2:eaf245af2aae 335 {
el18gs 2:eaf245af2aae 336 //Check the card socket
el18gs 2:eaf245af2aae 337 checkSocket();
el18gs 2:eaf245af2aae 338
el18gs 2:eaf245af2aae 339 //Return the disk status
el18gs 2:eaf245af2aae 340 return m_Status;
el18gs 2:eaf245af2aae 341 }
el18gs 2:eaf245af2aae 342
el18gs 2:eaf245af2aae 343 int SDFileSystem::disk_read(uint8_t* buffer, uint32_t sector, uint32_t count)
el18gs 2:eaf245af2aae 344 {
el18gs 2:eaf245af2aae 345 //Make sure the card is initialized before proceeding
el18gs 2:eaf245af2aae 346 if (m_Status & STA_NOINIT)
el18gs 2:eaf245af2aae 347 return RES_NOTRDY;
el18gs 2:eaf245af2aae 348
el18gs 2:eaf245af2aae 349 //Read a single block, or multiple blocks
el18gs 2:eaf245af2aae 350 if (count > 1) {
el18gs 2:eaf245af2aae 351 return readBlocks((char*)buffer, sector, count) ? RES_OK : RES_ERROR;
el18gs 2:eaf245af2aae 352 } else {
el18gs 2:eaf245af2aae 353 return readBlock((char*)buffer, sector) ? RES_OK : RES_ERROR;
el18gs 2:eaf245af2aae 354 }
el18gs 2:eaf245af2aae 355 }
el18gs 2:eaf245af2aae 356
el18gs 2:eaf245af2aae 357 int SDFileSystem::disk_write(const uint8_t* buffer, uint32_t sector, uint32_t count)
el18gs 2:eaf245af2aae 358 {
el18gs 2:eaf245af2aae 359 //Make sure the card is initialized before proceeding
el18gs 2:eaf245af2aae 360 if (m_Status & STA_NOINIT)
el18gs 2:eaf245af2aae 361 return RES_NOTRDY;
el18gs 2:eaf245af2aae 362
el18gs 2:eaf245af2aae 363 //Make sure the card isn't write protected before proceeding
el18gs 2:eaf245af2aae 364 if (m_Status & STA_PROTECT)
el18gs 2:eaf245af2aae 365 return RES_WRPRT;
el18gs 2:eaf245af2aae 366
el18gs 2:eaf245af2aae 367 //Write a single block, or multiple blocks
el18gs 2:eaf245af2aae 368 if (count > 1) {
el18gs 2:eaf245af2aae 369 return writeBlocks((const char*)buffer, sector, count) ? RES_OK : RES_ERROR;
el18gs 2:eaf245af2aae 370 } else {
el18gs 2:eaf245af2aae 371 return writeBlock((const char*)buffer, sector) ? RES_OK : RES_ERROR;
el18gs 2:eaf245af2aae 372 }
el18gs 2:eaf245af2aae 373 }
el18gs 2:eaf245af2aae 374
el18gs 2:eaf245af2aae 375 int SDFileSystem::disk_sync()
el18gs 2:eaf245af2aae 376 {
el18gs 2:eaf245af2aae 377 //Select the card so we're forced to wait for the end of any internal write processes
el18gs 2:eaf245af2aae 378 if (select()) {
el18gs 2:eaf245af2aae 379 deselect();
el18gs 2:eaf245af2aae 380 return RES_OK;
el18gs 2:eaf245af2aae 381 } else {
el18gs 2:eaf245af2aae 382 return RES_ERROR;
el18gs 2:eaf245af2aae 383 }
el18gs 2:eaf245af2aae 384 }
el18gs 2:eaf245af2aae 385
el18gs 2:eaf245af2aae 386 uint32_t SDFileSystem::disk_sectors()
el18gs 2:eaf245af2aae 387 {
el18gs 2:eaf245af2aae 388 //Make sure the card is initialized before proceeding
el18gs 2:eaf245af2aae 389 if (m_Status & STA_NOINIT)
el18gs 2:eaf245af2aae 390 return 0;
el18gs 2:eaf245af2aae 391
el18gs 2:eaf245af2aae 392 //Try to read the CSD register up to 3 times
el18gs 2:eaf245af2aae 393 for (int f = 0; f < 3; f++) {
el18gs 2:eaf245af2aae 394 //Select the card, and wait for ready
el18gs 2:eaf245af2aae 395 if(!select())
el18gs 2:eaf245af2aae 396 break;
el18gs 2:eaf245af2aae 397
el18gs 2:eaf245af2aae 398 //Send CMD9(0x00000000) to read the CSD register
el18gs 2:eaf245af2aae 399 if (writeCommand(CMD9, 0x00000000) == 0x00) {
el18gs 2:eaf245af2aae 400 //Read the 16B CSD data block
el18gs 2:eaf245af2aae 401 char csd[16];
el18gs 2:eaf245af2aae 402 bool success = readData(csd, 16);
el18gs 2:eaf245af2aae 403 deselect();
el18gs 2:eaf245af2aae 404 if (success) {
el18gs 2:eaf245af2aae 405 //Calculate the sector count based on the card type
el18gs 2:eaf245af2aae 406 if ((csd[0] >> 6) == 0x01) {
el18gs 2:eaf245af2aae 407 //Calculate the sector count for a high capacity card
el18gs 2:eaf245af2aae 408 unsigned int size = (((csd[7] & 0x3F) << 16) | (csd[8] << 8) | csd[9]) + 1;
el18gs 2:eaf245af2aae 409 return size << 10;
el18gs 2:eaf245af2aae 410 } else {
el18gs 2:eaf245af2aae 411 //Calculate the sector count for a standard capacity card
el18gs 2:eaf245af2aae 412 unsigned int size = (((csd[6] & 0x03) << 10) | (csd[7] << 2) | ((csd[8] & 0xC0) >> 6)) + 1;
el18gs 2:eaf245af2aae 413 size <<= ((((csd[9] & 0x03) << 1) | ((csd[10] & 0x80) >> 7)) + 2);
el18gs 2:eaf245af2aae 414 size <<= (csd[5] & 0x0F);
el18gs 2:eaf245af2aae 415 return size >> 9;
el18gs 2:eaf245af2aae 416 }
el18gs 2:eaf245af2aae 417 }
el18gs 2:eaf245af2aae 418 } else {
el18gs 2:eaf245af2aae 419 //The command failed, get out
el18gs 2:eaf245af2aae 420 break;
el18gs 2:eaf245af2aae 421 }
el18gs 2:eaf245af2aae 422 }
el18gs 2:eaf245af2aae 423
el18gs 2:eaf245af2aae 424 //The read operation failed 3 times
el18gs 2:eaf245af2aae 425 deselect();
el18gs 2:eaf245af2aae 426 return 0;
el18gs 2:eaf245af2aae 427 }
el18gs 2:eaf245af2aae 428
el18gs 2:eaf245af2aae 429 void SDFileSystem::onCardRemoval()
el18gs 2:eaf245af2aae 430 {
el18gs 2:eaf245af2aae 431 //Check the card socket
el18gs 2:eaf245af2aae 432 checkSocket();
el18gs 2:eaf245af2aae 433 }
el18gs 2:eaf245af2aae 434
el18gs 2:eaf245af2aae 435 inline void SDFileSystem::checkSocket()
el18gs 2:eaf245af2aae 436 {
el18gs 2:eaf245af2aae 437 //Use the card detect switch (if available) to determine if the socket is occupied
el18gs 2:eaf245af2aae 438 if (m_CdAssert != -1) {
el18gs 2:eaf245af2aae 439 if (m_Status & STA_NODISK) {
el18gs 2:eaf245af2aae 440 if (m_Cd == m_CdAssert) {
el18gs 2:eaf245af2aae 441 //The socket is now occupied
el18gs 2:eaf245af2aae 442 m_Status &= ~STA_NODISK;
el18gs 2:eaf245af2aae 443 m_CardType = CARD_UNKNOWN;
el18gs 2:eaf245af2aae 444 }
el18gs 2:eaf245af2aae 445 } else {
el18gs 2:eaf245af2aae 446 if (m_Cd != m_CdAssert) {
el18gs 2:eaf245af2aae 447 //The socket is now empty
el18gs 2:eaf245af2aae 448 m_Status |= (STA_NODISK | STA_NOINIT);
el18gs 2:eaf245af2aae 449 m_CardType = CARD_NONE;
el18gs 2:eaf245af2aae 450 }
el18gs 2:eaf245af2aae 451 }
el18gs 2:eaf245af2aae 452 }
el18gs 2:eaf245af2aae 453 }
el18gs 2:eaf245af2aae 454
el18gs 2:eaf245af2aae 455 inline bool SDFileSystem::waitReady(int timeout)
el18gs 2:eaf245af2aae 456 {
el18gs 2:eaf245af2aae 457 char resp;
el18gs 2:eaf245af2aae 458
el18gs 2:eaf245af2aae 459 //Keep sending dummy clocks with DI held high until the card releases the DO line
el18gs 2:eaf245af2aae 460 m_Timer.start();
el18gs 2:eaf245af2aae 461 do {
el18gs 2:eaf245af2aae 462 resp = m_Spi.write(0xFF);
el18gs 2:eaf245af2aae 463 } while (resp == 0x00 && m_Timer.read_ms() < timeout);
el18gs 2:eaf245af2aae 464 m_Timer.stop();
el18gs 2:eaf245af2aae 465 m_Timer.reset();
el18gs 2:eaf245af2aae 466
el18gs 2:eaf245af2aae 467 //Return success/failure
el18gs 2:eaf245af2aae 468 return (resp > 0x00);
el18gs 2:eaf245af2aae 469 }
el18gs 2:eaf245af2aae 470
el18gs 2:eaf245af2aae 471 inline bool SDFileSystem::select()
el18gs 2:eaf245af2aae 472 {
el18gs 2:eaf245af2aae 473 //Assert /CS
el18gs 2:eaf245af2aae 474 m_Cs = 0;
el18gs 2:eaf245af2aae 475
el18gs 2:eaf245af2aae 476 //Send 8 dummy clocks with DI held high to enable DO
el18gs 2:eaf245af2aae 477 m_Spi.write(0xFF);
el18gs 2:eaf245af2aae 478
el18gs 2:eaf245af2aae 479 //Wait for up to 500ms for the card to become ready
el18gs 2:eaf245af2aae 480 if (waitReady(500)) {
el18gs 2:eaf245af2aae 481 return true;
el18gs 2:eaf245af2aae 482 } else {
el18gs 2:eaf245af2aae 483 //We timed out, deselect and return false
el18gs 2:eaf245af2aae 484 deselect();
el18gs 2:eaf245af2aae 485 return false;
el18gs 2:eaf245af2aae 486 }
el18gs 2:eaf245af2aae 487 }
el18gs 2:eaf245af2aae 488
el18gs 2:eaf245af2aae 489 inline void SDFileSystem::deselect()
el18gs 2:eaf245af2aae 490 {
el18gs 2:eaf245af2aae 491 //Deassert /CS
el18gs 2:eaf245af2aae 492 m_Cs = 1;
el18gs 2:eaf245af2aae 493
el18gs 2:eaf245af2aae 494 //Send 8 dummy clocks with DI held high to disable DO
el18gs 2:eaf245af2aae 495 m_Spi.write(0xFF);
el18gs 2:eaf245af2aae 496 }
el18gs 2:eaf245af2aae 497
el18gs 2:eaf245af2aae 498 inline char SDFileSystem::commandTransaction(char cmd, unsigned int arg, unsigned int* resp)
el18gs 2:eaf245af2aae 499 {
el18gs 2:eaf245af2aae 500 //Select the card, and wait for ready
el18gs 2:eaf245af2aae 501 if(!select())
el18gs 2:eaf245af2aae 502 return 0xFF;
el18gs 2:eaf245af2aae 503
el18gs 2:eaf245af2aae 504 //Perform the command transaction
el18gs 2:eaf245af2aae 505 char token = writeCommand(cmd, arg, resp);
el18gs 2:eaf245af2aae 506
el18gs 2:eaf245af2aae 507 //Deselect the card, and return the R1 response token
el18gs 2:eaf245af2aae 508 deselect();
el18gs 2:eaf245af2aae 509 return token;
el18gs 2:eaf245af2aae 510 }
el18gs 2:eaf245af2aae 511
el18gs 2:eaf245af2aae 512 char SDFileSystem::writeCommand(char cmd, unsigned int arg, unsigned int* resp)
el18gs 2:eaf245af2aae 513 {
el18gs 2:eaf245af2aae 514 char token;
el18gs 2:eaf245af2aae 515
el18gs 2:eaf245af2aae 516 //Try to send the command up to 3 times
el18gs 2:eaf245af2aae 517 for (int f = 0; f < 3; f++) {
el18gs 2:eaf245af2aae 518 //Send CMD55(0x00000000) prior to an application specific command
el18gs 2:eaf245af2aae 519 if (cmd == ACMD22 || cmd == ACMD23 || cmd == ACMD41 || cmd == ACMD42) {
el18gs 2:eaf245af2aae 520 token = writeCommand(CMD55, 0x00000000);
el18gs 2:eaf245af2aae 521 if (token > 0x01)
el18gs 2:eaf245af2aae 522 return token;
el18gs 2:eaf245af2aae 523
el18gs 2:eaf245af2aae 524 //Deselect and reselect the card between CMD55 and an ACMD
el18gs 2:eaf245af2aae 525 deselect();
el18gs 2:eaf245af2aae 526 if(!select())
el18gs 2:eaf245af2aae 527 return 0xFF;
el18gs 2:eaf245af2aae 528 }
el18gs 2:eaf245af2aae 529
el18gs 2:eaf245af2aae 530 //Prepare the command packet
el18gs 2:eaf245af2aae 531 char cmdPacket[6];
el18gs 2:eaf245af2aae 532 cmdPacket[0] = cmd;
el18gs 2:eaf245af2aae 533 cmdPacket[1] = arg >> 24;
el18gs 2:eaf245af2aae 534 cmdPacket[2] = arg >> 16;
el18gs 2:eaf245af2aae 535 cmdPacket[3] = arg >> 8;
el18gs 2:eaf245af2aae 536 cmdPacket[4] = arg;
el18gs 2:eaf245af2aae 537 if (m_Crc || cmd == CMD0 || cmd == CMD8)
el18gs 2:eaf245af2aae 538 cmdPacket[5] = (SDCRC::crc7(cmdPacket, 5) << 1) | 0x01;
el18gs 2:eaf245af2aae 539 else
el18gs 2:eaf245af2aae 540 cmdPacket[5] = 0x01;
el18gs 2:eaf245af2aae 541
el18gs 2:eaf245af2aae 542 //Send the command packet
el18gs 2:eaf245af2aae 543 for (int i = 0; i < 6; i++)
el18gs 2:eaf245af2aae 544 m_Spi.write(cmdPacket[i]);
el18gs 2:eaf245af2aae 545
el18gs 2:eaf245af2aae 546 //Discard the stuff byte immediately following CMD12
el18gs 2:eaf245af2aae 547 if (cmd == CMD12)
el18gs 2:eaf245af2aae 548 m_Spi.write(0xFF);
el18gs 2:eaf245af2aae 549
el18gs 2:eaf245af2aae 550 //Allow up to 8 bytes of delay for the R1 response token
el18gs 2:eaf245af2aae 551 for (int i = 0; i < 9; i++) {
el18gs 2:eaf245af2aae 552 token = m_Spi.write(0xFF);
el18gs 2:eaf245af2aae 553 if (!(token & 0x80))
el18gs 2:eaf245af2aae 554 break;
el18gs 2:eaf245af2aae 555 }
el18gs 2:eaf245af2aae 556
el18gs 2:eaf245af2aae 557 //Verify the R1 response token
el18gs 2:eaf245af2aae 558 if (token == 0xFF) {
el18gs 2:eaf245af2aae 559 //No data was received, get out early
el18gs 2:eaf245af2aae 560 break;
el18gs 2:eaf245af2aae 561 } else if (token & (1 << 3)) {
el18gs 2:eaf245af2aae 562 //There was a CRC error, try again
el18gs 2:eaf245af2aae 563 continue;
el18gs 2:eaf245af2aae 564 } else if (token > 0x01) {
el18gs 2:eaf245af2aae 565 //An error occured, get out early
el18gs 2:eaf245af2aae 566 break;
el18gs 2:eaf245af2aae 567 }
el18gs 2:eaf245af2aae 568
el18gs 2:eaf245af2aae 569 //Handle R2 and R3/R7 response tokens
el18gs 2:eaf245af2aae 570 if (cmd == CMD13 && resp != NULL) {
el18gs 2:eaf245af2aae 571 //Read the R2 response value
el18gs 2:eaf245af2aae 572 *resp = m_Spi.write(0xFF);
el18gs 2:eaf245af2aae 573 } else if ((cmd == CMD8 || cmd == CMD58) && resp != NULL) {
el18gs 2:eaf245af2aae 574 //Read the R3/R7 response value
el18gs 2:eaf245af2aae 575 *resp = (m_Spi.write(0xFF) << 24);
el18gs 2:eaf245af2aae 576 *resp |= (m_Spi.write(0xFF) << 16);
el18gs 2:eaf245af2aae 577 *resp |= (m_Spi.write(0xFF) << 8);
el18gs 2:eaf245af2aae 578 *resp |= m_Spi.write(0xFF);
el18gs 2:eaf245af2aae 579 }
el18gs 2:eaf245af2aae 580
el18gs 2:eaf245af2aae 581 //The command was successful
el18gs 2:eaf245af2aae 582 break;
el18gs 2:eaf245af2aae 583 }
el18gs 2:eaf245af2aae 584
el18gs 2:eaf245af2aae 585 //Return the R1 response token
el18gs 2:eaf245af2aae 586 return token;
el18gs 2:eaf245af2aae 587 }
el18gs 2:eaf245af2aae 588
el18gs 2:eaf245af2aae 589 bool SDFileSystem::readData(char* buffer, int length)
el18gs 2:eaf245af2aae 590 {
el18gs 2:eaf245af2aae 591 char token;
el18gs 2:eaf245af2aae 592 unsigned short crc;
el18gs 2:eaf245af2aae 593
el18gs 2:eaf245af2aae 594 //Wait for up to 500ms for a token to arrive
el18gs 2:eaf245af2aae 595 m_Timer.start();
el18gs 2:eaf245af2aae 596 do {
el18gs 2:eaf245af2aae 597 token = m_Spi.write(0xFF);
el18gs 2:eaf245af2aae 598 } while (token == 0xFF && m_Timer.read_ms() < 500);
el18gs 2:eaf245af2aae 599 m_Timer.stop();
el18gs 2:eaf245af2aae 600 m_Timer.reset();
el18gs 2:eaf245af2aae 601
el18gs 2:eaf245af2aae 602 //Check if a valid start block token was received
el18gs 2:eaf245af2aae 603 if (token != 0xFE)
el18gs 2:eaf245af2aae 604 return false;
el18gs 2:eaf245af2aae 605
el18gs 2:eaf245af2aae 606 //Check if large frames are enabled or not
el18gs 2:eaf245af2aae 607 if (m_LargeFrames) {
el18gs 2:eaf245af2aae 608 //Switch to 16-bit frames for better performance
el18gs 2:eaf245af2aae 609 m_Spi.format(16, 0);
el18gs 2:eaf245af2aae 610
el18gs 2:eaf245af2aae 611 //Read the data block into the buffer
el18gs 2:eaf245af2aae 612 unsigned short dataWord;
el18gs 2:eaf245af2aae 613 for (int i = 0; i < length; i += 2) {
el18gs 2:eaf245af2aae 614 dataWord = m_Spi.write(0xFFFF);
el18gs 2:eaf245af2aae 615 buffer[i] = dataWord >> 8;
el18gs 2:eaf245af2aae 616 buffer[i + 1] = dataWord;
el18gs 2:eaf245af2aae 617 }
el18gs 2:eaf245af2aae 618
el18gs 2:eaf245af2aae 619 //Read the CRC16 checksum for the data block
el18gs 2:eaf245af2aae 620 crc = m_Spi.write(0xFFFF);
el18gs 2:eaf245af2aae 621
el18gs 2:eaf245af2aae 622 //Switch back to 8-bit frames
el18gs 2:eaf245af2aae 623 m_Spi.format(8, 0);
el18gs 2:eaf245af2aae 624 } else {
el18gs 2:eaf245af2aae 625 //Read the data into the buffer
el18gs 2:eaf245af2aae 626 for (int i = 0; i < length; i++)
el18gs 2:eaf245af2aae 627 buffer[i] = m_Spi.write(0xFF);
el18gs 2:eaf245af2aae 628
el18gs 2:eaf245af2aae 629 //Read the CRC16 checksum for the data block
el18gs 2:eaf245af2aae 630 crc = (m_Spi.write(0xFF) << 8);
el18gs 2:eaf245af2aae 631 crc |= m_Spi.write(0xFF);
el18gs 2:eaf245af2aae 632 }
el18gs 2:eaf245af2aae 633
el18gs 2:eaf245af2aae 634 //Return the validity of the CRC16 checksum (if enabled)
el18gs 2:eaf245af2aae 635 return (!m_Crc || crc == SDCRC::crc16(buffer, length));
el18gs 2:eaf245af2aae 636 }
el18gs 2:eaf245af2aae 637
el18gs 2:eaf245af2aae 638 char SDFileSystem::writeData(const char* buffer, char token)
el18gs 2:eaf245af2aae 639 {
el18gs 2:eaf245af2aae 640 //Calculate the CRC16 checksum for the data block (if enabled)
el18gs 2:eaf245af2aae 641 unsigned short crc = (m_Crc) ? SDCRC::crc16(buffer, 512) : 0xFFFF;
el18gs 2:eaf245af2aae 642
el18gs 2:eaf245af2aae 643 //Wait for up to 500ms for the card to become ready
el18gs 2:eaf245af2aae 644 if (!waitReady(500))
el18gs 2:eaf245af2aae 645 return false;
el18gs 2:eaf245af2aae 646
el18gs 2:eaf245af2aae 647 //Send the start block token
el18gs 2:eaf245af2aae 648 m_Spi.write(token);
el18gs 2:eaf245af2aae 649
el18gs 2:eaf245af2aae 650 //Check if large frames are enabled or not
el18gs 2:eaf245af2aae 651 if (m_LargeFrames) {
el18gs 2:eaf245af2aae 652 //Switch to 16-bit frames for better performance
el18gs 2:eaf245af2aae 653 m_Spi.format(16, 0);
el18gs 2:eaf245af2aae 654
el18gs 2:eaf245af2aae 655 //Write the data block from the buffer
el18gs 2:eaf245af2aae 656 for (int i = 0; i < 512; i += 2)
el18gs 2:eaf245af2aae 657 m_Spi.write((buffer[i] << 8) | buffer[i + 1]);
el18gs 2:eaf245af2aae 658
el18gs 2:eaf245af2aae 659 //Send the CRC16 checksum for the data block
el18gs 2:eaf245af2aae 660 m_Spi.write(crc);
el18gs 2:eaf245af2aae 661
el18gs 2:eaf245af2aae 662 //Switch back to 8-bit frames
el18gs 2:eaf245af2aae 663 m_Spi.format(8, 0);
el18gs 2:eaf245af2aae 664 } else {
el18gs 2:eaf245af2aae 665 //Write the data block from the buffer
el18gs 2:eaf245af2aae 666 for (int i = 0; i < 512; i++)
el18gs 2:eaf245af2aae 667 m_Spi.write(buffer[i]);
el18gs 2:eaf245af2aae 668
el18gs 2:eaf245af2aae 669 //Send the CRC16 checksum for the data block
el18gs 2:eaf245af2aae 670 m_Spi.write(crc >> 8);
el18gs 2:eaf245af2aae 671 m_Spi.write(crc);
el18gs 2:eaf245af2aae 672 }
el18gs 2:eaf245af2aae 673
el18gs 2:eaf245af2aae 674 //Return the data response token
el18gs 2:eaf245af2aae 675 return (m_Spi.write(0xFF) & 0x1F);
el18gs 2:eaf245af2aae 676 }
el18gs 2:eaf245af2aae 677
el18gs 2:eaf245af2aae 678 inline bool SDFileSystem::readBlock(char* buffer, unsigned int lba)
el18gs 2:eaf245af2aae 679 {
el18gs 2:eaf245af2aae 680 //Try to read the block up to 3 times
el18gs 2:eaf245af2aae 681 for (int f = 0; f < 3; f++) {
el18gs 2:eaf245af2aae 682 //Select the card, and wait for ready
el18gs 2:eaf245af2aae 683 if(!select())
el18gs 2:eaf245af2aae 684 break;
el18gs 2:eaf245af2aae 685
el18gs 2:eaf245af2aae 686 //Send CMD17(block) to read a single block
el18gs 2:eaf245af2aae 687 if (writeCommand(CMD17, (m_CardType == CARD_SDHC) ? lba : lba << 9) == 0x00) {
el18gs 2:eaf245af2aae 688 //Try to read the block, and deselect the card
el18gs 2:eaf245af2aae 689 bool success = readData(buffer, 512);
el18gs 2:eaf245af2aae 690 deselect();
el18gs 2:eaf245af2aae 691
el18gs 2:eaf245af2aae 692 //Return if successful
el18gs 2:eaf245af2aae 693 if (success)
el18gs 2:eaf245af2aae 694 return true;
el18gs 2:eaf245af2aae 695 } else {
el18gs 2:eaf245af2aae 696 //The command failed, get out
el18gs 2:eaf245af2aae 697 break;
el18gs 2:eaf245af2aae 698 }
el18gs 2:eaf245af2aae 699 }
el18gs 2:eaf245af2aae 700
el18gs 2:eaf245af2aae 701 //The single block read failed
el18gs 2:eaf245af2aae 702 deselect();
el18gs 2:eaf245af2aae 703 return false;
el18gs 2:eaf245af2aae 704 }
el18gs 2:eaf245af2aae 705
el18gs 2:eaf245af2aae 706 inline bool SDFileSystem::readBlocks(char* buffer, unsigned int lba, unsigned int count)
el18gs 2:eaf245af2aae 707 {
el18gs 2:eaf245af2aae 708 //Try to read each block up to 3 times
el18gs 2:eaf245af2aae 709 for (int f = 0; f < 3;) {
el18gs 2:eaf245af2aae 710 //Select the card, and wait for ready
el18gs 2:eaf245af2aae 711 if(!select())
el18gs 2:eaf245af2aae 712 break;
el18gs 2:eaf245af2aae 713
el18gs 2:eaf245af2aae 714 //Send CMD18(block) to read multiple blocks
el18gs 2:eaf245af2aae 715 if (writeCommand(CMD18, (m_CardType == CARD_SDHC) ? lba : lba << 9) == 0x00) {
el18gs 2:eaf245af2aae 716 //Try to read all of the data blocks
el18gs 2:eaf245af2aae 717 do {
el18gs 2:eaf245af2aae 718 //Read the next block, and break on errors
el18gs 2:eaf245af2aae 719 if (!readData(buffer, 512)) {
el18gs 2:eaf245af2aae 720 f++;
el18gs 2:eaf245af2aae 721 break;
el18gs 2:eaf245af2aae 722 }
el18gs 2:eaf245af2aae 723
el18gs 2:eaf245af2aae 724 //Update the variables
el18gs 2:eaf245af2aae 725 lba++;
el18gs 2:eaf245af2aae 726 buffer += 512;
el18gs 2:eaf245af2aae 727 f = 0;
el18gs 2:eaf245af2aae 728 } while (--count);
el18gs 2:eaf245af2aae 729
el18gs 2:eaf245af2aae 730 //Send CMD12(0x00000000) to stop the transmission
el18gs 2:eaf245af2aae 731 if (writeCommand(CMD12, 0x00000000) != 0x00) {
el18gs 2:eaf245af2aae 732 //The command failed, get out
el18gs 2:eaf245af2aae 733 break;
el18gs 2:eaf245af2aae 734 }
el18gs 2:eaf245af2aae 735
el18gs 2:eaf245af2aae 736 //Deselect the card, and return if successful
el18gs 2:eaf245af2aae 737 deselect();
el18gs 2:eaf245af2aae 738 if (count == 0)
el18gs 2:eaf245af2aae 739 return true;
el18gs 2:eaf245af2aae 740 } else {
el18gs 2:eaf245af2aae 741 //The command failed, get out
el18gs 2:eaf245af2aae 742 break;
el18gs 2:eaf245af2aae 743 }
el18gs 2:eaf245af2aae 744 }
el18gs 2:eaf245af2aae 745
el18gs 2:eaf245af2aae 746 //The multiple block read failed
el18gs 2:eaf245af2aae 747 deselect();
el18gs 2:eaf245af2aae 748 return false;
el18gs 2:eaf245af2aae 749 }
el18gs 2:eaf245af2aae 750
el18gs 2:eaf245af2aae 751 inline bool SDFileSystem::writeBlock(const char* buffer, unsigned int lba)
el18gs 2:eaf245af2aae 752 {
el18gs 2:eaf245af2aae 753 //Try to write the block up to 3 times
el18gs 2:eaf245af2aae 754 for (int f = 0; f < 3; f++) {
el18gs 2:eaf245af2aae 755 //Select the card, and wait for ready
el18gs 2:eaf245af2aae 756 if(!select())
el18gs 2:eaf245af2aae 757 break;
el18gs 2:eaf245af2aae 758
el18gs 2:eaf245af2aae 759 //Send CMD24(block) to write a single block
el18gs 2:eaf245af2aae 760 if (writeCommand(CMD24, (m_CardType == CARD_SDHC) ? lba : lba << 9) == 0x00) {
el18gs 2:eaf245af2aae 761 //Try to write the block, and deselect the card
el18gs 2:eaf245af2aae 762 char token = writeData(buffer, 0xFE);
el18gs 2:eaf245af2aae 763 deselect();
el18gs 2:eaf245af2aae 764
el18gs 2:eaf245af2aae 765 //Check the data response token
el18gs 2:eaf245af2aae 766 if (token == 0x0A) {
el18gs 2:eaf245af2aae 767 //A CRC error occured, try again
el18gs 2:eaf245af2aae 768 continue;
el18gs 2:eaf245af2aae 769 } else if (token == 0x0C) {
el18gs 2:eaf245af2aae 770 //A write error occured, get out
el18gs 2:eaf245af2aae 771 break;
el18gs 2:eaf245af2aae 772 }
el18gs 2:eaf245af2aae 773
el18gs 2:eaf245af2aae 774 //Send CMD13(0x00000000) to verify that the programming was successful if enabled
el18gs 2:eaf245af2aae 775 if (m_WriteValidation) {
el18gs 2:eaf245af2aae 776 unsigned int resp;
el18gs 2:eaf245af2aae 777 if (commandTransaction(CMD13, 0x00000000, &resp) != 0x00 || resp != 0x00) {
el18gs 2:eaf245af2aae 778 //Some manner of unrecoverable write error occured during programming, get out
el18gs 2:eaf245af2aae 779 break;
el18gs 2:eaf245af2aae 780 }
el18gs 2:eaf245af2aae 781 }
el18gs 2:eaf245af2aae 782
el18gs 2:eaf245af2aae 783 //The data was written successfully
el18gs 2:eaf245af2aae 784 return true;
el18gs 2:eaf245af2aae 785 } else {
el18gs 2:eaf245af2aae 786 //The command failed, get out
el18gs 2:eaf245af2aae 787 break;
el18gs 2:eaf245af2aae 788 }
el18gs 2:eaf245af2aae 789 }
el18gs 2:eaf245af2aae 790
el18gs 2:eaf245af2aae 791 //The single block write failed
el18gs 2:eaf245af2aae 792 deselect();
el18gs 2:eaf245af2aae 793 return false;
el18gs 2:eaf245af2aae 794 }
el18gs 2:eaf245af2aae 795
el18gs 2:eaf245af2aae 796 inline bool SDFileSystem::writeBlocks(const char* buffer, unsigned int lba, unsigned int count)
el18gs 2:eaf245af2aae 797 {
el18gs 2:eaf245af2aae 798 char token;
el18gs 2:eaf245af2aae 799 const char* currentBuffer = buffer;
el18gs 2:eaf245af2aae 800 unsigned int currentLba = lba;
el18gs 2:eaf245af2aae 801 int currentCount = count;
el18gs 2:eaf245af2aae 802
el18gs 2:eaf245af2aae 803 //Try to write each block up to 3 times
el18gs 2:eaf245af2aae 804 for (int f = 0; f < 3;) {
el18gs 2:eaf245af2aae 805 //If this is an SD card, send ACMD23(count) to set the number of blocks to pre-erase
el18gs 2:eaf245af2aae 806 if (m_CardType != CARD_MMC) {
el18gs 2:eaf245af2aae 807 if (commandTransaction(ACMD23, currentCount) != 0x00) {
el18gs 2:eaf245af2aae 808 //The command failed, get out
el18gs 2:eaf245af2aae 809 break;
el18gs 2:eaf245af2aae 810 }
el18gs 2:eaf245af2aae 811 }
el18gs 2:eaf245af2aae 812
el18gs 2:eaf245af2aae 813 //Select the card, and wait for ready
el18gs 2:eaf245af2aae 814 if(!select())
el18gs 2:eaf245af2aae 815 break;
el18gs 2:eaf245af2aae 816
el18gs 2:eaf245af2aae 817 //Send CMD25(block) to write multiple blocks
el18gs 2:eaf245af2aae 818 if (writeCommand(CMD25, (m_CardType == CARD_SDHC) ? currentLba : currentLba << 9) == 0x00) {
el18gs 2:eaf245af2aae 819 //Try to write all of the data blocks
el18gs 2:eaf245af2aae 820 do {
el18gs 2:eaf245af2aae 821 //Write the next block and break on errors
el18gs 2:eaf245af2aae 822 token = writeData(currentBuffer, 0xFC);
el18gs 2:eaf245af2aae 823 if (token != 0x05) {
el18gs 2:eaf245af2aae 824 f++;
el18gs 2:eaf245af2aae 825 break;
el18gs 2:eaf245af2aae 826 }
el18gs 2:eaf245af2aae 827
el18gs 2:eaf245af2aae 828 //Update the variables
el18gs 2:eaf245af2aae 829 currentBuffer += 512;
el18gs 2:eaf245af2aae 830 f = 0;
el18gs 2:eaf245af2aae 831 } while (--currentCount);
el18gs 2:eaf245af2aae 832
el18gs 2:eaf245af2aae 833 //Wait for up to 500ms for the card to finish processing the last block
el18gs 2:eaf245af2aae 834 if (!waitReady(500))
el18gs 2:eaf245af2aae 835 break;
el18gs 2:eaf245af2aae 836
el18gs 2:eaf245af2aae 837 //Finalize the transmission
el18gs 2:eaf245af2aae 838 if (currentCount == 0) {
el18gs 2:eaf245af2aae 839 //Send the stop tran token, and deselect the card
el18gs 2:eaf245af2aae 840 m_Spi.write(0xFD);
el18gs 2:eaf245af2aae 841 deselect();
el18gs 2:eaf245af2aae 842
el18gs 2:eaf245af2aae 843 //Send CMD13(0x00000000) to verify that the programming was successful if enabled
el18gs 2:eaf245af2aae 844 if (m_WriteValidation) {
el18gs 2:eaf245af2aae 845 unsigned int resp;
el18gs 2:eaf245af2aae 846 if (commandTransaction(CMD13, 0x00000000, &resp) != 0x00 || resp != 0x00) {
el18gs 2:eaf245af2aae 847 //Some manner of unrecoverable write error occured during programming, get out
el18gs 2:eaf245af2aae 848 break;
el18gs 2:eaf245af2aae 849 }
el18gs 2:eaf245af2aae 850 }
el18gs 2:eaf245af2aae 851
el18gs 2:eaf245af2aae 852 //The data was written successfully
el18gs 2:eaf245af2aae 853 return true;
el18gs 2:eaf245af2aae 854 } else {
el18gs 2:eaf245af2aae 855 //Send CMD12(0x00000000) to abort the transmission
el18gs 2:eaf245af2aae 856 if (writeCommand(CMD12, 0x00000000) != 0x00) {
el18gs 2:eaf245af2aae 857 //The command failed, get out
el18gs 2:eaf245af2aae 858 break;
el18gs 2:eaf245af2aae 859 }
el18gs 2:eaf245af2aae 860
el18gs 2:eaf245af2aae 861 //Deselect the card
el18gs 2:eaf245af2aae 862 deselect();
el18gs 2:eaf245af2aae 863
el18gs 2:eaf245af2aae 864 //Check the error token
el18gs 2:eaf245af2aae 865 if (token == 0x0A) {
el18gs 2:eaf245af2aae 866 //Determine the number of well written blocks if possible
el18gs 2:eaf245af2aae 867 unsigned int writtenBlocks = 0;
el18gs 2:eaf245af2aae 868 if (m_CardType != CARD_MMC && select()) {
el18gs 2:eaf245af2aae 869 //Send ACMD22(0x00000000) to get the number of well written blocks
el18gs 2:eaf245af2aae 870 if (writeCommand(ACMD22, 0x00000000) == 0x00) {
el18gs 2:eaf245af2aae 871 //Read the data
el18gs 2:eaf245af2aae 872 char acmdData[4];
el18gs 2:eaf245af2aae 873 if (readData(acmdData, 4)) {
el18gs 2:eaf245af2aae 874 //Extract the number of well written blocks
el18gs 2:eaf245af2aae 875 writtenBlocks = acmdData[0] << 24;
el18gs 2:eaf245af2aae 876 writtenBlocks |= acmdData[1] << 16;
el18gs 2:eaf245af2aae 877 writtenBlocks |= acmdData[2] << 8;
el18gs 2:eaf245af2aae 878 writtenBlocks |= acmdData[3];
el18gs 2:eaf245af2aae 879 }
el18gs 2:eaf245af2aae 880 }
el18gs 2:eaf245af2aae 881 deselect();
el18gs 2:eaf245af2aae 882 }
el18gs 2:eaf245af2aae 883
el18gs 2:eaf245af2aae 884 //Roll back the variables based on the number of well written blocks
el18gs 2:eaf245af2aae 885 currentBuffer = buffer + (writtenBlocks << 9);
el18gs 2:eaf245af2aae 886 currentLba = lba + writtenBlocks;
el18gs 2:eaf245af2aae 887 currentCount = count - writtenBlocks;
el18gs 2:eaf245af2aae 888
el18gs 2:eaf245af2aae 889 //Try again
el18gs 2:eaf245af2aae 890 continue;
el18gs 2:eaf245af2aae 891 } else {
el18gs 2:eaf245af2aae 892 //A write error occured, get out
el18gs 2:eaf245af2aae 893 break;
el18gs 2:eaf245af2aae 894 }
el18gs 2:eaf245af2aae 895 }
el18gs 2:eaf245af2aae 896 } else {
el18gs 2:eaf245af2aae 897 //The command failed, get out
el18gs 2:eaf245af2aae 898 break;
el18gs 2:eaf245af2aae 899 }
el18gs 2:eaf245af2aae 900 }
el18gs 2:eaf245af2aae 901
el18gs 2:eaf245af2aae 902 //The multiple block write failed
el18gs 2:eaf245af2aae 903 deselect();
el18gs 2:eaf245af2aae 904 return false;
el18gs 2:eaf245af2aae 905 }
el18gs 2:eaf245af2aae 906
el18gs 2:eaf245af2aae 907 bool SDFileSystem::enableHighSpeedMode()
el18gs 2:eaf245af2aae 908 {
el18gs 2:eaf245af2aae 909 //Try to issue CMD6 up to 3 times
el18gs 2:eaf245af2aae 910 for (int f = 0; f < 3; f++) {
el18gs 2:eaf245af2aae 911 //Select the card, and wait for ready
el18gs 2:eaf245af2aae 912 if(!select())
el18gs 2:eaf245af2aae 913 break;
el18gs 2:eaf245af2aae 914
el18gs 2:eaf245af2aae 915 //Send CMD6(0x80FFFFF1) to change the access mode to high speed
el18gs 2:eaf245af2aae 916 if (writeCommand(CMD6, 0x80FFFFF1) == 0x00) {
el18gs 2:eaf245af2aae 917 //Read the 64B status data block
el18gs 2:eaf245af2aae 918 char status[64];
el18gs 2:eaf245af2aae 919 bool success = readData(status, 64);
el18gs 2:eaf245af2aae 920 deselect();
el18gs 2:eaf245af2aae 921 if (success) {
el18gs 2:eaf245af2aae 922 //Return whether or not the operation was successful
el18gs 2:eaf245af2aae 923 return ((status[16] & 0x0F) == 0x1);
el18gs 2:eaf245af2aae 924 }
el18gs 2:eaf245af2aae 925 } else {
el18gs 2:eaf245af2aae 926 //The command failed, get out
el18gs 2:eaf245af2aae 927 break;
el18gs 2:eaf245af2aae 928 }
el18gs 2:eaf245af2aae 929 }
el18gs 2:eaf245af2aae 930
el18gs 2:eaf245af2aae 931 //The operation failed 3 times
el18gs 2:eaf245af2aae 932 deselect();
el18gs 2:eaf245af2aae 933 return false;
el18gs 2:eaf245af2aae 934 }