Skip to content

Commit fe7eb17

Browse files
committed
Add the WebServer test sketch
1 parent 81089c1 commit fe7eb17

File tree

2 files changed

+908
-0
lines changed

2 files changed

+908
-0
lines changed
Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
/*
2+
These are low level functions to aid in detecting whether a card is present or not.
3+
Because of ESP32 v2 core, SdFat can only operate using Shared SPI. This makes the sd.begin test take over 1s
4+
which causes the RTK product to boot slowly. To circumvent this, we will ping the SD card directly to see if it responds.
5+
Failures take 2ms, successes take 1ms.
6+
7+
From Prototype puzzle: https://github.com/sparkfunX/ThePrototype/blob/master/Firmware/TestSketches/sdLocker/sdLocker.ino
8+
License: Public domain. This code is based on Karl Lunt's work: https://www.seanet.com/~karllunt/sdlocker2.html
9+
*/
10+
11+
//Define commands for the SD card
12+
#define SD_GO_IDLE (0x40 + 0) // CMD0 - go to idle state
13+
#define SD_INIT (0x40 + 1) // CMD1 - start initialization
14+
#define SD_SEND_IF_COND (0x40 + 8) // CMD8 - send interface (conditional), works for SDHC only
15+
#define SD_SEND_STATUS (0x40 + 13) // CMD13 - send card status
16+
#define SD_SET_BLK_LEN (0x40 + 16) // CMD16 - set length of block in bytes
17+
#define SD_LOCK_UNLOCK (0x40 + 42) // CMD42 - lock/unlock card
18+
#define CMD55 (0x40 + 55) // multi-byte preface command
19+
#define SD_READ_OCR (0x40 + 58) // read OCR
20+
#define SD_ADV_INIT (0xc0 + 41) // ACMD41, for SDHC cards - advanced start initialization
21+
22+
//Define options for accessing the SD card's PWD (CMD42)
23+
#define MASK_ERASE 0x08 //erase the entire card
24+
#define MASK_LOCK_UNLOCK 0x04 //lock or unlock the card with password
25+
#define MASK_CLR_PWD 0x02 //clear password
26+
#define MASK_SET_PWD 0x01 //set password
27+
28+
//Define bit masks for fields in the lock/unlock command (CMD42) data structure
29+
#define SET_PWD_MASK (1<<0)
30+
#define CLR_PWD_MASK (1<<1)
31+
#define LOCK_UNLOCK_MASK (1<<2)
32+
#define ERASE_MASK (1<<3)
33+
34+
//Begin initialization by sending CMD0 and waiting until SD card
35+
//responds with In Idle Mode (0x01). If the response is not 0x01
36+
//within a reasonable amount of time, there is no SD card on the bus.
37+
//Returns false if not card is detected
38+
//Returns true if a card responds
39+
bool sdPresent(void)
40+
{
41+
byte response = 0;
42+
43+
SPI.begin();
44+
SPI.setClockDivider(SPI_CLOCK_DIV2);
45+
SPI.setDataMode(SPI_MODE0);
46+
SPI.setBitOrder(MSBFIRST);
47+
pinMode(pin_microSD_CS, OUTPUT);
48+
49+
//Sending clocks while card power stabilizes...
50+
deselectCard(); // always make sure
51+
for (byte i = 0; i < 30; i++) // send several clocks while card power stabilizes
52+
xchg(0xff);
53+
54+
//Sending CMD0 - GO IDLE...
55+
for (byte i = 0; i < 0x10; i++) //Attempt to go idle
56+
{
57+
response = sdSendCommand(SD_GO_IDLE, 0); // send CMD0 - go to idle state
58+
if (response == 1) break;
59+
}
60+
if (response != 1) return (false); //Card failed to respond to idle
61+
62+
return (true);
63+
}
64+
65+
/*
66+
sdSendCommand send raw command to SD card, return response
67+
68+
This routine accepts a single SD command and a 4-byte argument. It sends
69+
the command plus argument, adding the appropriate CRC. It then returns
70+
the one-byte response from the SD card.
71+
72+
For advanced commands (those with a command byte having bit 7 set), this
73+
routine automatically sends the required preface command (CMD55) before
74+
sending the requested command.
75+
76+
Upon exit, this routine returns the response byte from the SD card.
77+
Possible responses are:
78+
0xff No response from card; card might actually be missing
79+
0x01 SD card returned 0x01, which is OK for most commands
80+
0x?? other responses are command-specific
81+
*/
82+
byte sdSendCommand(byte command, unsigned long arg)
83+
{
84+
byte response;
85+
86+
if (command & 0x80) // special case, ACMD(n) is sent as CMD55 and CMDn
87+
{
88+
command &= 0x7f; // strip high bit for later
89+
response = sdSendCommand(CMD55, 0); // send first part (recursion)
90+
if (response > 1) return (response);
91+
}
92+
93+
deselectCard();
94+
xchg(0xFF);
95+
selectCard(); // enable CS
96+
xchg(0xFF);
97+
98+
xchg(command | 0x40); // command always has bit 6 set!
99+
xchg((byte)(arg >> 24)); // send data, starting with top byte
100+
xchg((byte)(arg >> 16));
101+
xchg((byte)(arg >> 8));
102+
xchg((byte)(arg & 0xFF));
103+
104+
byte crc = 0x01; // good for most cases
105+
if (command == SD_GO_IDLE) crc = 0x95; // this will be good enough for most commands
106+
if (command == SD_SEND_IF_COND) crc = 0x87; // special case, have to use different CRC
107+
xchg(crc); // send final byte
108+
109+
for (int i = 0; i < 30; i++) // loop until timeout or response
110+
{
111+
response = xchg(0xFF);
112+
if ((response & 0x80) == 0) break; // high bit cleared means we got a response
113+
}
114+
115+
/*
116+
We have issued the command but the SD card is still selected. We
117+
only deselectCard the card if the command we just sent is NOT a command
118+
that requires additional data exchange, such as reading or writing
119+
a block.
120+
*/
121+
if ((command != SD_READ_OCR) &&
122+
(command != SD_SEND_STATUS) &&
123+
(command != SD_SEND_IF_COND) &&
124+
(command != SD_LOCK_UNLOCK))
125+
{
126+
deselectCard(); // all done
127+
xchg(0xFF); // close with eight more clocks
128+
}
129+
130+
return (response); // let the caller sort it out
131+
}
132+
133+
//Select (enable) the SD card
134+
void selectCard(void)
135+
{
136+
digitalWrite(pin_microSD_CS, LOW);
137+
}
138+
139+
//Deselect (disable) the SD card
140+
void deselectCard(void)
141+
{
142+
digitalWrite(pin_microSD_CS, HIGH);
143+
}
144+
145+
//Exchange a byte of data with the SD card via host's SPI bus
146+
byte xchg(byte val)
147+
{
148+
byte receivedVal = SPI.transfer(val);
149+
return receivedVal;
150+
}

0 commit comments

Comments
 (0)