| Line No. | Rev | Author | Line |
|---|---|---|---|
| 1 | 6 | kaklik | /*! \file mmc.c \brief MultiMedia and SD Flash Card Interface. */ |
| 2 | //***************************************************************************** |
||
| 3 | // |
||
| 4 | // File Name : 'mmc.c' |
||
| 5 | // Title : MultiMedia and SD Flash Card Interface |
||
| 6 | // Author : Pascal Stang - Copyright (C) 2004 |
||
| 7 | // Created : 2004.09.22 |
||
| 8 | // Revised : 2006.06.12 |
||
| 9 | // Version : 0.1 |
||
| 10 | // Target MCU : Atmel AVR Series |
||
| 11 | // Editor Tabs : 4 |
||
| 12 | // |
||
| 13 | // NOTE: This code is currently below version 1.0, and therefore is considered |
||
| 14 | // to be lacking in some functionality or documentation, or may not be fully |
||
| 15 | // tested. Nonetheless, you can expect most functions to work. |
||
| 16 | // |
||
| 17 | // This code is distributed under the GNU Public License |
||
| 18 | // which can be found at http://www.gnu.org/licenses/gpl.txt |
||
| 19 | // |
||
| 20 | //***************************************************************************** |
||
| 21 | |||
| 22 | //----- Include Files --------------------------------------------------------- |
||
| 23 | #include <avr/io.h> // include I/O definitions (port names, pin names, etc) |
||
| 24 | #include <avr/interrupt.h> // include interrupt support |
||
| 25 | |||
| 26 | #include "global.h" // include our global settings |
||
| 27 | #include "spi.h" // include spi bus support |
||
| 28 | |||
| 29 | #include "rprintf.h" |
||
| 30 | |||
| 31 | #include "mmc.h" |
||
| 32 | |||
| 33 | // include project-specific hardware configuration |
||
| 34 | #include "mmcconf.h" |
||
| 35 | |||
| 36 | // Global variables |
||
| 37 | |||
| 38 | // Functions |
||
| 39 | |||
| 40 | void mmcInit(void) |
||
| 41 | { |
||
| 42 | // initialize SPI interface |
||
| 43 | spiInit(); |
||
| 44 | // release chip select |
||
| 45 | sbi(MMC_CS_DDR, MMC_CS_PIN); |
||
| 46 | sbi(MMC_CS_PORT,MMC_CS_PIN); |
||
| 47 | } |
||
| 48 | |||
| 49 | u08 mmcReset(void) |
||
| 50 | { |
||
| 51 | u08 i; |
||
| 52 | u08 retry; |
||
| 53 | u08 r1=0; |
||
| 54 | |||
| 55 | retry = 0; |
||
| 56 | do |
||
| 57 | { |
||
| 58 | // send dummy bytes with CS high before accessing |
||
| 59 | for(i=0;i<10;i++) spiTransferByte(0xFF); |
||
| 60 | // resetting card, go to SPI mode |
||
| 61 | r1 = mmcSendCommand(MMC_GO_IDLE_STATE, 0); |
||
| 62 | #ifdef MMC_DEBUG |
||
| 63 | rprintf("MMC_GO_IDLE_STATE: R1=0x%x\r\n", r1); |
||
| 64 | #endif |
||
| 65 | // do retry counter |
||
| 66 | retry++; |
||
| 67 | if(retry>10) return -1; |
||
| 68 | } while(r1 != 0x01); |
||
| 69 | |||
| 70 | // TODO: check card parameters for voltage compliance |
||
| 71 | // before issuing initialize command |
||
| 72 | |||
| 73 | retry = 0; |
||
| 74 | do |
||
| 75 | { |
||
| 76 | // initializing card for operation |
||
| 77 | r1 = mmcSendCommand(MMC_SEND_OP_COND, 0); |
||
| 78 | #ifdef MMC_DEBUG |
||
| 79 | rprintf("MMC_SEND_OP_COND: R1=0x%x\r\n", r1); |
||
| 80 | #endif |
||
| 81 | // do retry counter |
||
| 82 | retry++; |
||
| 83 | if(retry>100) return -1; |
||
| 84 | } while(r1); |
||
| 85 | |||
| 86 | // turn off CRC checking to simplify communication |
||
| 87 | r1 = mmcSendCommand(MMC_CRC_ON_OFF, 0); |
||
| 88 | #ifdef MMC_DEBUG |
||
| 89 | rprintf("MMC_CRC_ON_OFF: R1=0x%x\r\n", r1); |
||
| 90 | #endif |
||
| 91 | |||
| 92 | // set block length to 512 bytes |
||
| 93 | r1 = mmcSendCommand(MMC_SET_BLOCKLEN, 512); |
||
| 94 | #ifdef MMC_DEBUG |
||
| 95 | rprintf("MMC_SET_BLOCKLEN: R1=0x%x\r\n", r1); |
||
| 96 | #endif |
||
| 97 | |||
| 98 | // return success |
||
| 99 | return 0; |
||
| 100 | } |
||
| 101 | |||
| 102 | u08 mmcSendCommand(u08 cmd, u32 arg) |
||
| 103 | { |
||
| 104 | u08 r1; |
||
| 105 | |||
| 106 | // assert chip select |
||
| 107 | cbi(MMC_CS_PORT,MMC_CS_PIN); |
||
| 108 | // issue the command |
||
| 109 | r1 = mmcCommand(cmd, arg); |
||
| 110 | // release chip select |
||
| 111 | sbi(MMC_CS_PORT,MMC_CS_PIN); |
||
| 112 | |||
| 113 | return r1; |
||
| 114 | } |
||
| 115 | |||
| 116 | u08 mmcRead(u32 sector, u08* buffer) |
||
| 117 | { |
||
| 118 | u08 r1; |
||
| 119 | u16 i; |
||
| 120 | |||
| 121 | // assert chip select |
||
| 122 | cbi(MMC_CS_PORT,MMC_CS_PIN); |
||
| 123 | // issue command |
||
| 124 | r1 = mmcCommand(MMC_READ_SINGLE_BLOCK, sector<<9); |
||
| 125 | #ifdef MMC_DEBUG |
||
| 126 | rprintf("MMC Read Block R1=0x%x\r\n", r1); |
||
| 127 | #endif |
||
| 128 | // check for valid response |
||
| 129 | if(r1 != 0x00) |
||
| 130 | return r1; |
||
| 131 | // wait for block start |
||
| 132 | while(spiTransferByte(0xFF) != MMC_STARTBLOCK_READ); |
||
| 133 | // read in data |
||
| 134 | for(i=0; i<0x200; i++) |
||
| 135 | { |
||
| 136 | *buffer++ = spiTransferByte(0xFF); |
||
| 137 | } |
||
| 138 | // read 16-bit CRC |
||
| 139 | spiTransferByte(0xFF); |
||
| 140 | spiTransferByte(0xFF); |
||
| 141 | // release chip select |
||
| 142 | sbi(MMC_CS_PORT,MMC_CS_PIN); |
||
| 143 | // return success |
||
| 144 | return 0; |
||
| 145 | } |
||
| 146 | |||
| 147 | u08 mmcWrite(u32 sector, u08* buffer) |
||
| 148 | { |
||
| 149 | u08 r1; |
||
| 150 | u16 i; |
||
| 151 | |||
| 152 | // assert chip select |
||
| 153 | cbi(MMC_CS_PORT,MMC_CS_PIN); |
||
| 154 | // issue command |
||
| 155 | r1 = mmcCommand(MMC_WRITE_BLOCK, sector<<9); |
||
| 156 | #ifdef MMC_DEBUG |
||
| 157 | rprintf("MMC Write Block R1=0x%x\r\n", r1); |
||
| 158 | #endif |
||
| 159 | // check for valid response |
||
| 160 | if(r1 != 0x00) |
||
| 161 | return r1; |
||
| 162 | // send dummy |
||
| 163 | spiTransferByte(0xFF); |
||
| 164 | // send data start token |
||
| 165 | spiTransferByte(MMC_STARTBLOCK_WRITE); |
||
| 166 | // write data |
||
| 167 | for(i=0; i<0x200; i++) |
||
| 168 | { |
||
| 169 | spiTransferByte(*buffer++); |
||
| 170 | } |
||
| 171 | // write 16-bit CRC (dummy values) |
||
| 172 | spiTransferByte(0xFF); |
||
| 173 | spiTransferByte(0xFF); |
||
| 174 | // read data response token |
||
| 175 | r1 = spiTransferByte(0xFF); |
||
| 176 | if( (r1&MMC_DR_MASK) != MMC_DR_ACCEPT) |
||
| 177 | return r1; |
||
| 178 | #ifdef MMC_DEBUG |
||
| 179 | rprintf("Data Response Token=0x%x\r\n", r1); |
||
| 180 | #endif |
||
| 181 | // wait until card not busy |
||
| 182 | while(!spiTransferByte(0xFF)); |
||
| 183 | // release chip select |
||
| 184 | sbi(MMC_CS_PORT,MMC_CS_PIN); |
||
| 185 | // return success |
||
| 186 | return 0; |
||
| 187 | } |
||
| 188 | |||
| 189 | u08 mmcCommand(u08 cmd, u32 arg) |
||
| 190 | { |
||
| 191 | u08 r1; |
||
| 192 | u08 retry=0; |
||
| 193 | // send command |
||
| 194 | spiTransferByte(cmd | 0x40); |
||
| 195 | spiTransferByte(arg>>24); |
||
| 196 | spiTransferByte(arg>>16); |
||
| 197 | spiTransferByte(arg>>8); |
||
| 198 | spiTransferByte(arg); |
||
| 199 | spiTransferByte(0x95); // crc valid only for MMC_GO_IDLE_STATE |
||
| 200 | // end command |
||
| 201 | // wait for response |
||
| 202 | // if more than 8 retries, card has timed-out |
||
| 203 | // return the received 0xFF |
||
| 204 | while((r1 = spiTransferByte(0xFF)) == 0xFF) |
||
| 205 | if(retry++ > 8) break; |
||
| 206 | // return response |
||
| 207 | return r1; |
||
| 208 | } |
Powered by WebSVN v2.8.3