📄 main.c
字号:
//===========================================================================
//=
//= 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 + -