But are you doing that anyway? Do you need to access the data again after you want it written to the SD? In fact, you can read it again -- access to memory is serialized and therefore safe -- there just can't be multiple readers simultaneously (which of course means "at the same time"
-- verbatim, I just looked it up). How much slower is it if two tasks contend to read the same memory?
It's worth noting that many of the code examples, like for xQueueCreate, say
// Create a queue capable of containing 10 pointers to AMessage structures.
// These should be passed by pointer as they contain a lot of data.
So don't pass big structures. In the example, the (not-packed) struct is 24 bytes; that's "a lot". That means 512 for a sector (plus 2) is ginormous.
Having separate queues for the filename and file data seem problematic. The ideal case would have a single structure, for which you can then allocate some variable amount of space -- as long as you know how much in advance
struct Stuff {
char filename[14]; // up to 13 chars, plus NUL
uint16_t length;
uint8_t data[0];
};
static_assert(offsetof(Stuff, data) == 16); // 32-bit aligned, no space to pack
Stuff *allocStuff(uint16_t length) {
auto ret = static_cast<Stuff*>(malloc(sizeof(Stuff) + length));
if (ret) {
ret->filename[0] = '\0';
ret->length = length;
}
return ret;
}
void setup() {
Serial.begin(115200);
}
void loop() {
Stuff *x = allocStuff(30);
Stuff *y = allocStuff(100);
strcpy(x->filename, "ten");
strcpy(reinterpret_cast<char*>(y->data), "eleven"); // hack to get something visible in there
Serial.println(reinterpret_cast<uintptr_t>(x), HEX);
Serial.println(reinterpret_cast<uintptr_t>(y), HEX);
Serial.println(reinterpret_cast<uintptr_t>(y->data), HEX);
Serial.println(x->filename);
Serial.println(y->length);
Serial.println(reinterpret_cast<char*>(y->data));
free(x);
free(y);
delay(1500);
}
The filename can be empty for "same file"; maybe have a magic value for "done with the current file". You can then push those pointers onto the queue, and the next task can access the data. If the SD writer is the last thing, it can free the block. If it needs to stick around and needs to be managed by the main task (or another cleanup task), then maybe there is a bool or bit in the struct to indicate that the write is done.
The main setup+loop task runs on the "APP" core (core #1). The "PRO"-for-protocol core, core #0, handles the WiFi and Bluetooth (and more). Those high-priority tasks running on the "other" core are grabbing bytes out the air. If you're going to run the SD writer there as well, let us know how it works out if you run it at the the same high priority, where it will be time-sliced with the normal protocol stuff, to make those bytes available on the APP core; or at a lower priority.