⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 main.c

📁 基于DALLAS 51单片机的SD/MMC卡驱动程序(C语言源代码)
💻 C
📖 第 1 页 / 共 3 页
字号:
//===========================================================================
//= 
//=  Copyright (C) 2006 MAXIM/Dallas Semiconductor Corporation. 
//=  All rights Reserved. Printed in U.S.A.
//=
//=  Permission is hereby granted, free of charge, to any person obtaining a
//=  copy of this software and associated documentation files (the 
//=  "Software"), to deal in the Software without restriction, including
//=  without limitation the rights to use, copy, modify, merge, publish,
//=  distribute, sublicense, and/or sell copies of the Software, and to
//=  permit persons to whom the Software is furnished to do so, subject to
//=  the following conditions:
//=  
//=  The above copyright notice and this permission notice shall be included
//=  in all copies or substantial portions of the Software source code.
//=  
//=  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
//=  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
//=  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
//=  IN NO EVENT SHALL MAXIM/DALLAS SEMICONDUCTOR BE LIABLE FOR ANY CLAIM, 
//=  DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 
//=  OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR 
//=  THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//=
//=  Except as contained in this notice, the name of MAXIM/Dallas 
//=  Semiconductor shall not be used except as stated in the MAXIM/Dallas 
//=  Semiconductor Branding Policy.
//=
//=     Description: MAXQ2000 Secure Digital (SD) Card Interface via SPI
//=                 
//=        Filename: main.c
//=
//=        Compiler: Rowley CrossWorks C compiler
//=
//=        Hardware: MAXQ2000 Evaluation Kit (Rev B)
//=
//===========================================================================

#include <MAXQ2000.h>
#include <stdio.h>
#include <stdio_c.h>
#include <stdint.h>
#include <string.h>
#include <stdarg.h>

/* ---- Handy utility macros ---- */
/* GETBIT(in,bit) returns bit 0-7 of in to caller */
#define GETBIT(in, bit) ((in & (1<<bit)) >> bit)
/* CLEARARGS(x) clears the 32-bit SD command argument */
#define CLEAR_ARGS(x) x[0] = 0; x[1] = 0; x[2] = 0; x[3] = 0;

/* Common command set */
#define CMD0_GO_IDLE_STATE          0x00
#define CMD1_SEND_OPCOND            0x01
#define CMD9_SEND_CSD               0x09
#define CMD10_SEND_CID              0x0a
#define CMD12_STOP_TRANSMISSION     0x0b
#define CMD13_SEND_STATUS           0x0c
#define CMD16_SET_BLOCKLEN          0x10
#define CMD17_READ_SINGLE_BLOCK     0x11
#define CMD18_READ_MULTIPLE_BLOCK   0x12
#define CMD24_WRITE_BLOCK           0x18
#define CMD25_WRITE_MULTIPLE_BLOCK  0x19
#define CMD27_PROGRAM_CSD           0x1b
#define CMD28_SET_WRITE_PROT        0x1c
#define CMD29_CLR_WRITE_PROT        0x1d
#define CMD30_SEND_WRITE_PROT       0x1e
#define CMD32_ERASE_WR_BLK_START_ADDR 0x20
#define CMD33_ERASE_WR_BLK_END_ADDR   0x21
#define CMD38_ERASE                 0x26
#define CMD55_APP_CMD               0x37
#define CMD56_GEN_CMD               0x38
#define CMD58_READ_OCR              0x3a
#define CMD59_CRC_ON_OFF            0x3b

/* Application-specific commands (always prefixed with CMD55_APP_CMD) */
#define ACMD13_SD_STATUS            0x0d
#define ACMD22_SEND_NUM_WR_BLOCKS   0x16
#define ACMD23_SET_WR_BLK_ERASE_COUNT 0x17
#define ACMD41_SEND_OP_COND         0x29
#define ACMD42_SET_CLR_CARD_DETECT  0x2a
#define ACMD51_SEND_SCR             0x33

/* R1 format responses (ORed together as a bit-field) */
#define R1_NOERROR   0x00
#define R1_IDLE      0x01
#define R1_ERASE     0x02
#define R1_ILLEGAL   0x04
#define R1_CRC_ERR   0x08
#define R1_ERASE_SEQ 0x10
#define R1_ADDR_ERR  0x20
#define R1_PARAM_ERR 0x40

/* R2 format responses - second byte only, first is identical to R1 */
#define R2_LOCKED    0x01
#define R2_WP_FAILED 0x02
#define R2_ERROR     0x04
#define R2_CTRL_ERR  0x08
#define R2_ECC_FAIL  0x10
#define R2_WP_VIOL   0x20
#define R2_ERASE_PARAM 0x40
#define R2_RANGE_ERR 0x80

/* CRC-related constants */
#define SD_CRC7         0
#define SD_CRC16        1
#define CRC_OK          0
#define CRC_FAIL       -1

/* Transfer-related return codes */
#define TR_OK           0
#define TR_INVALID_ARG -1
#define TR_TIMEOUT     -2
#define TR_ERROR_TOKEN -3
#define TR_NOT_IDLE    -4
#define TR_FAILURE     -5

/* Misc defines */
#define BLOCK_BUFFER_LEN  515
#define INPUT_BUFFER_LEN   10
/* The following two timeouts should be computed from CSD parameters */
/*  in a fully SD-compliant implementation */
#define WAIT_R1_TIMEOUT    50
#define WAIT_WRITE_TIMEOUT 32768

/* Common globals */
/* rxbuf is the block buffer used for all operations */
/* 515 == 1 R1 response byte + 512 byte block + 2 bytes CRC16 */
uint8_t rxbuf[BLOCK_BUFFER_LEN]; 
/* arg is the 32-bit SD command argument broken into 4 bytes */
uint8_t arg[4] = {0x00, 0x00, 0x00, 0x00};
/* Most SD cards use a blocksize of 512 bytes and is found in the CSD */
uint16_t blocksize = 512; 
/* Buffer used by the cprintf() macro for strings stored in code space */
unsigned char cbuf[80];

/* Prototype definition for the assembly routine in copybuf.asm */
int asm_copybuffer(unsigned char *dstaddr, const __code char *srcaddr, int len);

/* Calls the printf() function after copying code-space string to RAM buffer
 *
 * Comments:
 *
 *   As the MAXQ2000 has limited RAM, copying all of the static string data
 *    into RAM reduces the space for the Rowley soft stack. We, therefore, 
 *    copy only the string needed at the current instant into a single buffer
 *    and pass this buffer to vprintf() along with the variable argument list.
 * 
 * Input arguments:
 *  
 *   format - code-space formatting string
 *   [<arg1> .. <argn>] - additional parameters to printf(str, ...)
 *
 * Returns:
 *
 *   result code from vprintf
 *
 */
int cprintf(const __code char *format, ...)
{
  va_list ap;

  /* Initialize the varaiable argument list pointer */
  va_start(ap, format);

  /* Copy the code space string to RAM */
  asm_copybuffer(cbuf, format, 80);

  /* Call vprintf with our RAM format string plus the varaible argument list */
  return vprintf((char *)cbuf, ap);
}

/* Hook function for Rowley printf() routines to send serial character 
 *
 * Input arguments:      
 *
 *   x - character to send to console held in lower byte
 *
 * Returns:
 *
 *   <none>
 *
 */
int 
__putchar(int x)
{
  SBUF0 = x;
  while (!(SCON0 & 0x02));
  SCON0 &= ~0x02;
}

/* Waits for, and reads, a character over the serial port
 *
 * Input arguments:      
 *
 *   <none>
 *
 * Returns:
 *
 *   character received over serial port
 *
 */
uint8_t readuart(void)
{
  while(!(SCON0 & 1)); /* Wait for RI to go high */
  SCON0 &= ~0x01; /* Clear it */
  return (uint8_t)SBUF0; /* Pass back the receive buffer */
}

/* Waits for, and reads, a character over the serial port
 *
 * Input arguments:      
 *
 *   in - character to transmit out of SPI MOSI pin
 *
 * Returns:
 *
 *   character received via SPI MISO pin
 *
 */
uint8_t xferSPI(uint8_t in)
{
  uint8_t out;
  /* Caveat lector! This may hang on SPICN.6 and SPICN.7 forever */

  while(SPICN & 0x80);           /* Wait for BUSY to be low */
  SPICN &= ~0x40;                /* Clear transfer complete */
  SPIB = in;                     /* Start the transfer */
  while(!(SPICN & 0x40));        /* Wait for Transfer Complete */
  out = SPIB;                    /* Copy off what was sent in */
  SPICN &= ~0x40;                /* Clear transfer complete */

#ifdef SPI_DEBUG
  /* This may help during early debugging of the SPI bus */
  /* Format is "->(transmitted byte) <-(received byte)" */
  cprintf(C"->0x%02x <-0x%02x\r\n", in, out);
#endif

  return out;
}

/* Compares R1 expected response with received response
 *
 * Input arguments:      
 *
 *   r1       - received response
 *   expected - expected response
 *
 * Returns:
 *
 *   0 if equal, -1 otherwise
 *
 */
int check_r1(uint8_t r1, uint8_t expected)
{
  if (r1 != expected) {
    cprintf(C"WARNING: R1 status 0x%02x, expecting 0x%02x\r\n", 
	   rxbuf[0], expected);
    return -1;
  }
  return 0;
}

/* Sends idle bytes to card, and waits for 5 consecutive idles from card 
 *
 * Input arguments:      
 *
 *   timeout - number of characters to wait before giving up
 *
 * Returns:
 *
 *   TR_OK if equal, TR_TIMEOUT otherwise
 *
 */
int flush_spi(int timeout)
{
  uint8_t recv;
  int i = 0;

  /* We unroll the loop to save on variable space. */
  while ((i < timeout) && (recv != 0xff)) {
    recv = xferSPI(0xff);
    if (recv == 0xff) { /* Got 1 so far */
      recv = xferSPI(0xff);
      if (recv == 0xff) { /* Got 2 so far */
	recv = xferSPI(0xff);
	if (recv == 0xff) { /* Got 3 so far */
	  recv = xferSPI(0xff);
	  if (recv == 0xff) { /* Got 4 so far */
	    recv = xferSPI(0xff);
	  }
	}
      }
    }
    i++;
  }

  if (recv != 0xff) { 
    /* Only way to reach this is if we timed-out and didn't get 0xff */
    return TR_TIMEOUT;
  }

  return TR_OK;
}

/* Wait for the start of transmission from the SD card 
 *
 * Input arguments:      
 *
 *   b      - pointer to buffer of AT LEAST length+1 size
 *   length - 0 to read only R1, otherwise > 0 to read data response
 *
 * Returns:
 *
 *   TR_TIMEOUT for timeout, TR_INVALID_ARG for null pointer
 *   TR_ERROR_TOKEN for length > 0 and error token received
 *   TR_NOT_IDLE if idle bus was not detected after transfer complete
 *
 *   (side effects: b[0] is R1 byte, b[1..length] is data if length > 0)
 *   (              b[1] is error token if return is TR_ERROR_TOKEN)
 *
 */

/* Length is # of data bytes to follow R1 response. Status will be in b[0] */
int waitForR1(uint8_t *b, uint32_t length)
{
  uint8_t recv = 0xff;
  int i = 0;

  /* No null pointers allowed */
  if (b == NULL) {
    return TR_INVALID_ARG;
  }

  /* Wait for start bit on R1 */
  while (GETBIT(recv,7) == 1) {
    if (i > WAIT_R1_TIMEOUT) {
      return TR_TIMEOUT;
    }
    recv = xferSPI(0xff);
    i++;
  }

  *b = recv; /* Copy in status */

  if (length > 0) {
    /* Wait for start token on data portion, if any */
    recv = 0xff; i = 0;
    while (recv != 0xfe) {
      if (i > 50) {
	return TR_TIMEOUT;
      }
      recv = xferSPI(0xff);

      if ((recv != 0xff) && (recv != 0xfe)) {
	/* Not idle bus and not start token, something else. Bus issue?! */
	/* Copy other token into buffer for program to examine */
	*(b+1) = recv;
	return TR_ERROR_TOKEN;
      }
      i++;
    }
    
    /* Read all bytes */
    for (i = 1; i <= length; i++) {
      *(b+i) = xferSPI(0xff);
    }
  }
  
/* Eight more bit clocks to finish internal SD operations */
  recv = xferSPI(0xff); 
  if (recv != 0xff) {
    /* Bus is not idle .. should not happen for single block transfers */
    return TR_NOT_IDLE;
  }

  return 0;
}

/* CRC-7 as described in the Secure Digital spec 
 *
 * Input arguments:      
 *
 *   old_crc - 0x00 to start new CRC, or value from previous call to continue
 *   data    - data byte to add to CRC computation
 *
 * Returns:
 *
 *   CRC-7 checksum which MUST be augmented by crc_7augment() before use
 *
 */
uint8_t crc_7(uint8_t old_crc, uint8_t data)
{
  unsigned char new_crc;
  int x;

  /* CRC-7's polynomial is x^7 + x^3 + 1 */

  /* How this works:
   *
   *  - Feed the bits into the loop MSB first
   *  - Shift contents of register left by one, top bit of 
   *     register becomes x^7 term
   *  - If top bit is set, XOR in the poly

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -