Skip to content

Commit 35dd992

Browse files
Dynamically allocate the SD sector cache on use
The SD library includes a 512-byte cache array as a static class member to hold a copy of a sector on the SD card. Because it was statically allocated, the mere act of including <SD.h> in either your own application or *any library* you use--even if you didn't ever use any of the SD objects--would cause the linker to allocate a 512 byte array in BSS out of heap. Replace this static allocation with a static pointer, and only allocate that pointer on the instantiation of a SdVolume object. Free it when the SdVolume is destroyed.
1 parent b08ff10 commit 35dd992

File tree

4 files changed

+26
-24
lines changed

4 files changed

+26
-24
lines changed

libraries/SD/src/utility/SdFat.h

+5-3
Original file line numberDiff line numberDiff line change
@@ -431,14 +431,16 @@ union cache_t {
431431
class SdVolume {
432432
public:
433433
/** Create an instance of SdVolume */
434-
SdVolume(void) :allocSearchStart_(2), fatType_(0) {}
434+
SdVolume(void) :allocSearchStart_(2), fatType_(0) { if (!cacheBuffer_) cacheBuffer_ = (cache_t *)malloc(sizeof(cache_t)); }
435+
/** Delete an instance of SdVolume */
436+
~SdVolume() { free(cacheBuffer_); cacheBuffer_ = NULL; }
435437
/** Clear the cache and returns a pointer to the cache. Used by the WaveRP
436438
* recorder to do raw write to the SD card. Not for normal apps.
437439
*/
438440
static uint8_t* cacheClear(void) {
439441
cacheFlush();
440442
cacheBlockNumber_ = 0XFFFFFFFF;
441-
return cacheBuffer_.data;
443+
return cacheBuffer_->data;
442444
}
443445
/**
444446
* Initialize a FAT volume. Try partition one first then try super
@@ -499,7 +501,7 @@ class SdVolume {
499501
// value for action argument in cacheRawBlock to indicate cache dirty
500502
static uint8_t const CACHE_FOR_WRITE = 1;
501503

502-
static cache_t cacheBuffer_; // 512 byte cache for device blocks
504+
static cache_t *cacheBuffer_; // 512 byte cache for device blocks
503505
static uint32_t cacheBlockNumber_; // Logical number of block in the cache
504506
static Sd2Card* sdCard_; // Sd2Card object for cache
505507
static uint8_t cacheDirty_; // cacheFlush() will write block if true

libraries/SD/src/utility/SdFile.cpp

+8-8
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ uint8_t SdFile::addDirCluster(void) {
6363
// return pointer to cached entry or null for failure
6464
dir_t* SdFile::cacheDirEntry(uint8_t action) {
6565
if (!SdVolume::cacheRawBlock(dirBlock_, action)) return NULL;
66-
return SdVolume::cacheBuffer_.dir + dirIndex_;
66+
return SdVolume::cacheBuffer_->dir + dirIndex_;
6767
}
6868
//------------------------------------------------------------------------------
6969
/**
@@ -323,7 +323,7 @@ uint8_t SdFile::makeDir(SdFile* dir, const char* dirName) {
323323
if (!SdVolume::cacheRawBlock(block, SdVolume::CACHE_FOR_WRITE)) return false;
324324

325325
// copy '.' to block
326-
memcpy(&SdVolume::cacheBuffer_.dir[0], &d, sizeof(d));
326+
memcpy(&SdVolume::cacheBuffer_->dir[0], &d, sizeof(d));
327327

328328
// make entry for '..'
329329
d.name[1] = '.';
@@ -335,7 +335,7 @@ uint8_t SdFile::makeDir(SdFile* dir, const char* dirName) {
335335
d.firstClusterHigh = dir->firstCluster_ >> 16;
336336
}
337337
// copy '..' to block
338-
memcpy(&SdVolume::cacheBuffer_.dir[1], &d, sizeof(d));
338+
memcpy(&SdVolume::cacheBuffer_->dir[1], &d, sizeof(d));
339339

340340
// set position after '..'
341341
curPosition_ = 2 * sizeof(d);
@@ -442,7 +442,7 @@ uint8_t SdFile::open(SdFile* dirFile, const char* fileName, uint8_t oflag) {
442442

443443
// use first entry in cluster
444444
dirIndex_ = 0;
445-
p = SdVolume::cacheBuffer_.dir;
445+
p = SdVolume::cacheBuffer_->dir;
446446
}
447447
// initialize as empty file
448448
memset(p, 0, sizeof(dir_t));
@@ -510,7 +510,7 @@ uint8_t SdFile::open(SdFile* dirFile, uint16_t index, uint8_t oflag) {
510510
// open a cached directory entry. Assumes vol_ is initializes
511511
uint8_t SdFile::openCachedEntry(uint8_t dirIndex, uint8_t oflag) {
512512
// location of entry in cache
513-
dir_t* p = SdVolume::cacheBuffer_.dir + dirIndex;
513+
dir_t* p = SdVolume::cacheBuffer_->dir + dirIndex;
514514

515515
// write or truncate is an error for a directory or read-only file
516516
if (p->attributes & (DIR_ATT_READ_ONLY | DIR_ATT_DIRECTORY)) {
@@ -709,7 +709,7 @@ int16_t SdFile::read(void* buf, uint16_t nbyte) {
709709
} else {
710710
// read block to cache and copy data to caller
711711
if (!SdVolume::cacheRawBlock(block, SdVolume::CACHE_FOR_READ)) return -1;
712-
uint8_t* src = SdVolume::cacheBuffer_.data + offset;
712+
uint8_t* src = SdVolume::cacheBuffer_->data + offset;
713713
uint8_t* end = src + n;
714714
while (src != end) *dst++ = *src++;
715715
}
@@ -763,7 +763,7 @@ dir_t* SdFile::readDirCache(void) {
763763
curPosition_ += 31;
764764

765765
// return pointer to entry
766-
return (SdVolume::cacheBuffer_.dir + i);
766+
return (SdVolume::cacheBuffer_->dir + i);
767767
}
768768
//------------------------------------------------------------------------------
769769
/**
@@ -1196,7 +1196,7 @@ size_t SdFile::write(const void* buf, uint16_t nbyte) {
11961196
goto writeErrorReturn;
11971197
}
11981198
}
1199-
uint8_t* dst = SdVolume::cacheBuffer_.data + blockOffset;
1199+
uint8_t* dst = SdVolume::cacheBuffer_->data + blockOffset;
12001200
uint8_t* end = dst + n;
12011201
while (dst != end) *dst++ = *src++;
12021202
}

libraries/SD/src/utility/SdVolume.cpp

+12-12
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
// raw block cache
2323
// init cacheBlockNumber_to invalid SD block number
2424
uint32_t SdVolume::cacheBlockNumber_ = 0XFFFFFFFF;
25-
cache_t SdVolume::cacheBuffer_; // 512 byte cache for Sd2Card
25+
cache_t* SdVolume::cacheBuffer_; // 512 byte cache for Sd2Card
2626
Sd2Card* SdVolume::sdCard_; // pointer to SD card object
2727
uint8_t SdVolume::cacheDirty_ = 0; // cacheFlush() will write block if true
2828
uint32_t SdVolume::cacheMirrorBlock_ = 0; // mirror block for second FAT
@@ -98,12 +98,12 @@ uint8_t SdVolume::allocContiguous(uint32_t count, uint32_t* curCluster) {
9898
//------------------------------------------------------------------------------
9999
uint8_t SdVolume::cacheFlush(void) {
100100
if (cacheDirty_) {
101-
if (!sdCard_->writeBlock(cacheBlockNumber_, cacheBuffer_.data)) {
101+
if (!sdCard_->writeBlock(cacheBlockNumber_, cacheBuffer_->data)) {
102102
return false;
103103
}
104104
// mirror FAT tables
105105
if (cacheMirrorBlock_) {
106-
if (!sdCard_->writeBlock(cacheMirrorBlock_, cacheBuffer_.data)) {
106+
if (!sdCard_->writeBlock(cacheMirrorBlock_, cacheBuffer_->data)) {
107107
return false;
108108
}
109109
cacheMirrorBlock_ = 0;
@@ -116,7 +116,7 @@ uint8_t SdVolume::cacheFlush(void) {
116116
uint8_t SdVolume::cacheRawBlock(uint32_t blockNumber, uint8_t action) {
117117
if (cacheBlockNumber_ != blockNumber) {
118118
if (!cacheFlush()) return false;
119-
if (!sdCard_->readBlock(blockNumber, cacheBuffer_.data)) return false;
119+
if (!sdCard_->readBlock(blockNumber, cacheBuffer_->data)) return false;
120120
cacheBlockNumber_ = blockNumber;
121121
}
122122
cacheDirty_ |= action;
@@ -127,9 +127,9 @@ uint8_t SdVolume::cacheRawBlock(uint32_t blockNumber, uint8_t action) {
127127
uint8_t SdVolume::cacheZeroBlock(uint32_t blockNumber) {
128128
if (!cacheFlush()) return false;
129129

130-
// loop take less flash than memset(cacheBuffer_.data, 0, 512);
130+
// loop take less flash than memset(cacheBuffer_->data, 0, 512);
131131
for (uint16_t i = 0; i < 512; i++) {
132-
cacheBuffer_.data[i] = 0;
132+
cacheBuffer_->data[i] = 0;
133133
}
134134
cacheBlockNumber_ = blockNumber;
135135
cacheSetDirty();
@@ -156,9 +156,9 @@ uint8_t SdVolume::fatGet(uint32_t cluster, uint32_t* value) const {
156156
if (!cacheRawBlock(lba, CACHE_FOR_READ)) return false;
157157
}
158158
if (fatType_ == 16) {
159-
*value = cacheBuffer_.fat16[cluster & 0XFF];
159+
*value = cacheBuffer_->fat16[cluster & 0XFF];
160160
} else {
161-
*value = cacheBuffer_.fat32[cluster & 0X7F] & FAT32MASK;
161+
*value = cacheBuffer_->fat32[cluster & 0X7F] & FAT32MASK;
162162
}
163163
return true;
164164
}
@@ -180,9 +180,9 @@ uint8_t SdVolume::fatPut(uint32_t cluster, uint32_t value) {
180180
}
181181
// store entry
182182
if (fatType_ == 16) {
183-
cacheBuffer_.fat16[cluster & 0XFF] = value;
183+
cacheBuffer_->fat16[cluster & 0XFF] = value;
184184
} else {
185-
cacheBuffer_.fat32[cluster & 0X7F] = value;
185+
cacheBuffer_->fat32[cluster & 0X7F] = value;
186186
}
187187
cacheSetDirty();
188188

@@ -232,7 +232,7 @@ uint8_t SdVolume::init(Sd2Card* dev, uint8_t part) {
232232
if (part) {
233233
if (part > 4)return false;
234234
if (!cacheRawBlock(volumeStartBlock, CACHE_FOR_READ)) return false;
235-
part_t* p = &cacheBuffer_.mbr.part[part-1];
235+
part_t* p = &cacheBuffer_->mbr.part[part-1];
236236
if ((p->boot & 0X7F) !=0 ||
237237
p->totalSectors < 100 ||
238238
p->firstSector == 0) {
@@ -242,7 +242,7 @@ uint8_t SdVolume::init(Sd2Card* dev, uint8_t part) {
242242
volumeStartBlock = p->firstSector;
243243
}
244244
if (!cacheRawBlock(volumeStartBlock, CACHE_FOR_READ)) return false;
245-
bpb_t* bpb = &cacheBuffer_.fbs.bpb;
245+
bpb_t* bpb = &cacheBuffer_->fbs.bpb;
246246
if (bpb->bytesPerSector != 512 ||
247247
bpb->fatCount == 0 ||
248248
bpb->reservedSectorCount == 0 ||

platform.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ recipe.S.o.pattern="{compiler.path}{compiler.c.cmd}" {compiler.cpreprocessor.fla
8686
recipe.ar.pattern="{compiler.path}{compiler.ar.cmd}" {compiler.ar.flags} {compiler.ar.extra_flags} "{build.path}/arduino.ar" "{object_file}"
8787

8888
## Combine gc-sections, archives, and objects
89-
recipe.c.combine.pattern="{compiler.path}{compiler.c.elf.cmd}" {compiler.c.elf.flags} {compiler.c.elf.extra_flags} -o "{build.path}/{build.project_name}.elf" -Wl,--start-group {object_files} "{build.path}/arduino.ar" {compiler.c.elf.libs} -Wl,--end-group "-L{build.path}"
89+
recipe.c.combine.pattern="{compiler.path}{compiler.c.elf.cmd}" -Wl,-M -Wl,-Map "-Wl,{build.path}/{build.project_name}.map" {compiler.c.elf.flags} {compiler.c.elf.extra_flags} -o "{build.path}/{build.project_name}.elf" -Wl,--start-group {object_files} "{build.path}/arduino.ar" {compiler.c.elf.libs} -Wl,--end-group "-L{build.path}"
9090

9191
## Create eeprom
9292
recipe.objcopy.eep.pattern=

0 commit comments

Comments
 (0)