<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; line-break: after-white-space;" class="">Here is the Espressif document on it:<div class=""><br class=""></div><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><div class=""><a href="http://esp-idf.readthedocs.io/en/latest/api-guides/external-ram.html" class="">http://esp-idf.readthedocs.io/en/latest/api-guides/external-ram.html</a></div><div class=""><br class=""></div><div class=""><h3 style="box-sizing: border-box; margin-top: 0px; font-family: "Roboto Slab", ff-tisa-web-pro, Georgia, Arial, sans-serif; font-size: 20px; color: rgb(64, 64, 64); font-variant-ligatures: normal; orphans: 2; widows: 2; background-color: rgb(252, 252, 252);" class="">Restrictions</h3><dl class="docutils" style="box-sizing: border-box; margin: 0px 0px 24px; padding: 0px; list-style: none none; color: rgb(64, 64, 64); font-family: Lato, proxima-nova, "Helvetica Neue", Arial, sans-serif; font-size: 16px; font-variant-ligatures: normal; orphans: 2; widows: 2; background-color: rgb(252, 252, 252);"><dt style="box-sizing: border-box; font-weight: bold;" class="">The use of external RAM has a few restrictions:</dt><dd style="box-sizing: border-box; margin: 0px 0px 12px 24px;" class=""><ul class="first last simple" style="box-sizing: border-box; margin: 0px 0px 24px; padding: 0px; list-style-position: initial; list-style-image: initial; line-height: 24px;"><li style="box-sizing: border-box; list-style: disc; margin-left: 24px;" class="">When disabling flash cache (for example, because the flash is being written to), the external RAM also becomes inaccessible; any reads from or writes to it will lead to an illegal cache access exception. This is also the reason that ESP-IDF will never allocate a tasks stack in external RAM.</li><li style="box-sizing: border-box; list-style: disc; margin-left: 24px;" class="">External RAM cannot be used as a place to store DMA transaction descriptors or as a buffer for a DMA transfer to read from or write into. Any buffers that will be used in combination with DMA must be allocated using <code class="literal docutils" style="box-sizing: border-box; font-family: Consolas, "Andale Mono WT", "Andale Mono", "Lucida Console", "Lucida Sans Typewriter", "DejaVu Sans Mono", "Bitstream Vera Sans Mono", "Liberation Mono", "Nimbus Mono L", Monaco, "Courier New", Courier, monospace; font-size: 12px; white-space: nowrap; max-width: 100%; background: rgb(255, 255, 255); border: 1px solid rgb(225, 228, 229); padding: 2px 5px; color: rgb(231, 76, 60); overflow-x: auto;"><span class="pre" style="box-sizing: border-box;">heap_caps_malloc(size,</span> <span class="pre" style="box-sizing: border-box;">MALLOC_CAP_DMA)</span></code> (and can be freed using a standard <code class="literal docutils" style="box-sizing: border-box; font-family: Consolas, "Andale Mono WT", "Andale Mono", "Lucida Console", "Lucida Sans Typewriter", "DejaVu Sans Mono", "Bitstream Vera Sans Mono", "Liberation Mono", "Nimbus Mono L", Monaco, "Courier New", Courier, monospace; font-size: 12px; white-space: nowrap; max-width: 100%; background: rgb(255, 255, 255); border: 1px solid rgb(225, 228, 229); padding: 2px 5px; color: rgb(231, 76, 60); overflow-x: auto;"><span class="pre" style="box-sizing: border-box;">free()</span></code> call.)</li><li style="box-sizing: border-box; list-style: disc; margin-left: 24px;" class="">External RAM uses the same cache region as the external flash. This means that often accessed variables in external RAM can be read and modified almost as quickly as in internal ram. However, when accessing large chunks of data (>32K), the cache can be insufficient and speeds will fall back to the access speed of the external RAM. Moreover, accessing large chunks of data can ‘push out’ cached flash, possibly making execution of code afterwards slower.</li><li style="box-sizing: border-box; list-style: disc; margin-left: 24px;" class="">External RAM cannot be used as task stack memory; because of this, xTaskCreate and similar functions will always allocate internal memory for stack and task TCBs and xTaskCreateStatic-type functions will check if the buffers passed are internal. However, for tasks not calling on code in ROM in any way, directly or indirectly, the menuconfig option <a class="internal reference" href="http://esp-idf.readthedocs.io/en/latest/api-reference/kconfig.html#config-spiram-allow-stack-external-memory" style="box-sizing: border-box; color: rgb(155, 89, 182); text-decoration: none; cursor: pointer;">SPIRAM_ALLOW_STACK_EXTERNAL_MEMORY</a> will eliminate the check in xTaskCreateStatic, allowing task stack in external RAM. Using this is not advised, however.</li></ul></dd></dl></div></blockquote><div class=""><div><br class=""></div><div>The way it works is that SPIRAM is accessed using SPI protocol at 40Mhz. The same speed and protocol as for flash memory for code. Then, a portion of internal ram is reserved as a cache (for both SPI ram and flash). Think of it as something like swap.</div><div><br class=""></div><div>Hard to guess as to performance impact, as it depends on cache hit rates. I would expect it to behave approximately the same as flash code access (same protocol, same bus speed).</div><div><br class=""></div><div>Regards, Mark.</div><div><br class=""><blockquote type="cite" class=""><div class="">On 20 Feb 2018, at 10:36 AM, Greg D. <<a href="mailto:gregd2350@gmail.com" class="">gregd2350@gmail.com</a>> wrote:</div><br class="Apple-interchange-newline"><div class="">
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" class="">
<div text="#000000" bgcolor="#FFFFFF" class="">
Probably worth trying, at least. That was kind of what I was
thinking we would do. <br class="">
<br class="">
I think the only storage I access really frequently is already
procedure-local, so should be on the stack. Are there any
restrictions on doing I/O to/from SPIRAM? For example, I/O buffers
aimed at a CAN bus?<br class="">
<br class="">
For the proverbial back-of-the-envelope purposes, what is the access
speed for SPIRAM? Also, what access granularity (i.e. is there a
fundamental "block" that gets transacted, or is this a sizeof-level
thing)?<br class="">
<br class="">
Greg<br class="">
<br class="">
<br class="">
<div class="moz-cite-prefix">Mark Webb-Johnson wrote:<br class="">
</div>
<blockquote type="cite" cite="mid:BFFE55DE-5E2E-450D-A16B-FB2BFCE3579C@webb-johnson.net" class="">
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" class="">
<div class=""><br class="">
</div>
Another interesting approach:
<div class=""><br class="">
</div>
<blockquote style="margin: 0 0 0 40px; border: none; padding:
0px;" class="">
<div class="">
<div class=""><font class="" face="Andale Mono"><span style="font-size: 18px;" class="">main/ovms.cpp:</span></font></div>
<div class=""><font class="" face="Andale Mono"><span style="font-size: 18px;" class=""><br class="">
</span></font></div>
<div class=""><font class="" face="Andale Mono"><span style="font-size: 18px;" class="">
<div class="">void* operator new(std::size_t sz)</div>
<div class=""> {</div>
<div class=""> return ExternalRamMalloc(sz);</div>
<div class=""> }</div>
</span></font></div>
<div class=""><font class="" face="Andale Mono"><span style="font-size: 18px;" class=""><br class="">
</span></font></div>
<div class=""><font class="" face="Andale Mono"><span style="font-size: 18px;" class="">OVMS > module
memory</span></font></div>
<div class=""><font class="" face="Andale Mono"><span style="font-size: 18px;" class="">Free 8-bit
197400/282424, 32-bit 424/27596, SPIRAM 4113632/4194252</span></font></div>
<div class=""><font class="" face="Andale Mono"><span style="font-size: 18px;" class="">--Task-- Total
DRAM D/IRAM IRAM SPIRAM +/- DRAM D/IRAM IRAM
SPIRAM</span></font></div>
<div class=""><font class="" face="Andale Mono"><span style="font-size: 18px;" class="">esp_timer
17068 0 644 35676 +17068 +0 +644
+35676</span></font></div>
<div class=""><font class="" face="Andale Mono"><span style="font-size: 18px;" class="">main
12452 0 0 5352 +12452 +0 +0
+5352</span></font></div>
<div class=""><font class="" face="Andale Mono"><span style="font-size: 18px;" class="">Housekeeping
28404 0 0 17292 +28404 +0 +0
+17292</span></font></div>
<div class=""><font class="" face="Andale Mono"><span style="font-size: 18px;" class="">tiT
0 0 0 132 +0 +0 +0 +132</span></font></div>
<div class=""><font class="" face="Andale Mono"><span style="font-size: 18px;" class="">AsyncConsole
0 0 26404 20 +0 +0 +26404 +20</span></font></div>
<div class=""><font class="" face="Andale Mono"><span style="font-size: 18px;" class="">no task
5348 0 0 0 +5348 +0 +0
+0</span></font></div>
<div class=""><font class="" face="Andale Mono"><span style="font-size: 18px;" class="">ipc0
10848 0 0 0 +10848 +0 +0
+0</span></font></div>
<div class=""><font class="" face="Andale Mono"><span style="font-size: 18px;" class="">ipc1
12 0 0 0 +12 +0 +0 +0</span></font></div>
<div class=""><font class="" face="Andale Mono"><span style="font-size: 18px;" class="">Tmr Svc
7328 0 0 0 +7328 +0 +0
+0</span></font></div>
</div>
<div class=""><font class="" face="Andale Mono"><span style="font-size: 18px;" class=""><br class="">
</span></font></div>
<div class=""><font class="" face="Andale Mono"><span style="font-size: 18px;" class="">With WIFI enabled and
connected to an access point:</span></font></div>
<div class=""><font class="" face="Andale Mono"><span style="font-size: 18px;" class=""><br class="">
</span></font></div>
<div class=""><font class="" face="Andale Mono"><span style="font-size: 18px;" class="">
<div class="">OVMS > module memory</div>
<div class="">Free 8-bit 163600/282424, 32-bit 424/27596,
SPIRAM 4110952/4194252</div>
</span></font></div>
</blockquote>
<div class="">
<div class=""><br class="">
</div>
<div class="">That is a global override for all C++ objects to be
allocated from SPIRAM. I bet you haven’t seen so much free
internal RAM on an ESP32 before...</div>
<div class=""><br class="">
</div>
<div class="">There are also some C code malloc’s that we could move over
as well (the most obvious being javascript duktape, of course,
but also mongoose).</div>
<div class=""><br class="">
</div>
<div class="">I’m wondering if there is any reason not to simply do this
global override for C++ code? Any stuff that won’t work in
SPIRAM could explicitly malloc what it needs.</div>
<div class=""><br class="">
</div>
<div class="">Regards, Mark.</div>
<div class=""><br class="">
<blockquote type="cite" class="">
<div class="">On 17 Feb 2018, at 9:41 PM, Mark Webb-Johnson
<<a href="mailto:mark@webb-johnson.net" class="" moz-do-not-send="true">mark@webb-johnson.net</a>>
wrote:</div>
<br class="Apple-interchange-newline">
<div class="">
<div class="">There is a significant performance hit using
SPI vs internal ram. There are also restrictions (such
as no stacks, no dma targets, ISRs, etc). I’ve tried
just changing Malloc to use SPI ram but the Espressif
idf libraries don’t work. Maybe in 3-6 months, but not
today.<br class="">
<br class="">
I still have to solve the problem of std:: objects
(strings, etc). I think a new c++ memory allocator
should work.<br class="">
<br class="">
Regards, Mark<br class="">
<br class="">
<blockquote type="cite" class="">On 17 Feb 2018, at 9:33
AM, Stephen Casner <<a href="mailto:casner@acm.org" class="" moz-do-not-send="true">casner@acm.org</a>>
wrote:<br class="">
<br class="">
Mark,<br class="">
<br class="">
This looks good to me (LGTM), but there might be cases
where we need<br class="">
to avoid adding the new ExternalRamAllocated class as
a base for a<br class="">
building-block class and instead add it as a base of a
subset of the<br class="">
classes that derive from the building-block class.<br class="">
<br class="">
If there isn't any significant performance hit going
to SPIRAM, then I<br class="">
expect most allocations other than stacks and DMA
buffers can go<br class="">
there.<br class="">
<br class="">
-- Steve<br class="">
<br class="">
<blockquote type="cite" class="">On Fri, 16 Feb 2018,
Mark Webb-Johnson wrote:<br class="">
<br class="">
<br class="">
I’ve committed (and pushed) an experimental
extension to allow C++ objects to be optionally
moved to SPI RAM.<br class="">
<br class="">
The code is in ovms.h, so should be easily
accessible to everything. It is pretty simple:<br class="">
<br class="">
We have a new class ‘ExternalRamAllocated’. That
does nothing except override the new and new[]
operators.<br class="">
<br class="">
Those operators try to malloc from SPI RAM first. If
that doesn’t succeed then they fall back to standard
internal RAM.<br class="">
<br class="">
The definition of a C++ class can then be changed to
make it “: public ExternalRamAllocated”. Once that
is done, any objects of that class allocated will
try to be placed in external (SPI) RAM.<br class="">
<br class="">
For other malloc uses, a general purpose 'void*
ExternalRamMalloc(std::size_t sz)’ function is also
provided.<br class="">
<br class="">
To test this, I’ve made a one line change to the
OvmsCommand class:<br class="">
<br class="">
-class OvmsCommand<br class="">
+class OvmsCommand : public ExternalRamAllocated<br class="">
<br class="">
Here is what the memory usage looks like:<br class="">
<br class="">
With SPI RAM disabled (in menuconfig):<br class="">
<br class="">
Free 8-bit 120844/284304, 32-bit 30508/57680, SPIRAM
0/0<br class="">
--Task-- Total DRAM D/IRAM IRAM SPIRAM +/-
DRAM D/IRAM IRAM SPIRAM<br class="">
no task 5312 0 0 0
+5312 +0 +0 +0<br class="">
esp_timer 52328 0 644 0
+52328 +0 +644 +0<br class="">
main 16448 0 0 0
+16448 +0 +0 +0<br class="">
ipc0 11096 0 0 0
+11096 +0 +0 +0<br class="">
Housekeeping 40576 5120 0 0
+40576 +5120 +0 +0<br class="">
tiT 128 0 0 0
+128 +0 +0 +0<br class="">
Tmr Svc 884 6444 0 0
+884 +6444 +0 +0<br class="">
ipc1 12 0 0 0
+12 +0 +0 +0<br class="">
AsyncConsole 20 0 26404 0
+20 +0 +26404 +0<br class="">
<br class="">
Without deriving OvmsCommand from
ExternalRamAllocated:<br class="">
<br class="">
Free 8-bit 119240/282436, 32-bit 424/27596, SPIRAM
4193924/4194252<br class="">
--Task-- Total DRAM D/IRAM IRAM SPIRAM +/-
DRAM D/IRAM IRAM SPIRAM<br class="">
tiT 0 0 0 128
+0 +0 +0 +128<br class="">
Housekeeping 40564 5120 0 12
+40564 +5120 +0 +12<br class="">
no task 5348 0 0 0
+5348 +0 +0 +0<br class="">
esp_timer 52328 0 644 0
+52328 +0 +644 +0<br class="">
main 16448 0 0 0
+16448 +0 +0 +0<br class="">
ipc0 11096 0 0 0
+11096 +0 +0 +0<br class="">
ipc1 12 0 0 0
+12 +0 +0 +0<br class="">
Tmr Svc 884 6444 0 0
+884 +6444 +0 +0<br class="">
AsyncConsole 20 0 26404 0
+20 +0 +26404 +0<br class="">
<br class="">
After deriving OvmsCommand from
ExternalRamAllocated:<br class="">
<br class="">
OVMS > module memory<br class="">
Free 8-bit 152308/282432, 32-bit 424/27596, SPIRAM
4160852/4194252<br class="">
--Task-- Total DRAM D/IRAM IRAM SPIRAM +/-
DRAM D/IRAM IRAM SPIRAM<br class="">
esp_timer 31664 0 644 20664
+31664 +0 +644 +20664<br class="">
tiT 0 0 0 128
+0 +0 +0 +128<br class="">
Housekeeping 39636 0 0 6060
+39636 +0 +0 +6060<br class="">
no task 5348 0 0 0
+5348 +0 +0 +0<br class="">
main 16448 0 0 0
+16448 +0 +0 +0<br class="">
ipc0 11096 0 0 0
+11096 +0 +0 +0<br class="">
ipc1 12 0 0 0
+12 +0 +0 +0<br class="">
Tmr Svc 7328 0 0 0
+7328 +0 +0 +0<br class="">
AsyncConsole 20 0 26404 0
+20 +0 +26404 +0<br class="">
<br class="">
The advantage of SPI RAM is obvious. 30KB of
internal RAM saved with just one line changed in a
header file. Most of our other objects like that
(metrics, configs, etc) could be equally easily
moved to SPI RAM. We can make the decision on a
class-by-class basis.<br class="">
<br class="">
I think this is a pretty good solution. It puts the
onus of the decision of whether to put into SPI RAM
into the object itself (as presumably the object
knows best whether it can actually be put in SPI
RAM). It is also extremely simple to define that.<br class="">
<br class="">
But, it is an experiment. Please let me know what
you think.<br class="">
<br class="">
Regards, Mark.<br class="">
<br class="">
</blockquote>
_______________________________________________<br class="">
OvmsDev mailing list<br class="">
<a href="mailto:OvmsDev@lists.teslaclub.hk" class="" moz-do-not-send="true">OvmsDev@lists.teslaclub.hk</a><br class="">
<a class="moz-txt-link-freetext" href="http://lists.teslaclub.hk/mailman/listinfo/ovmsdev">http://lists.teslaclub.hk/mailman/listinfo/ovmsdev</a><br class="">
</blockquote>
<br class="">
_______________________________________________<br class="">
OvmsDev mailing list<br class="">
<a href="mailto:OvmsDev@lists.teslaclub.hk" class="" moz-do-not-send="true">OvmsDev@lists.teslaclub.hk</a><br class="">
<a class="moz-txt-link-freetext" href="http://lists.teslaclub.hk/mailman/listinfo/ovmsdev">http://lists.teslaclub.hk/mailman/listinfo/ovmsdev</a><br class="">
</div>
</div>
</blockquote>
</div>
<br class="">
</div>
<br class="">
<fieldset class="mimeAttachmentHeader"></fieldset>
<br class="">
<pre wrap="" class="">_______________________________________________
OvmsDev mailing list
<a class="moz-txt-link-abbreviated" href="mailto:OvmsDev@lists.teslaclub.hk">OvmsDev@lists.teslaclub.hk</a>
<a class="moz-txt-link-freetext" href="http://lists.teslaclub.hk/mailman/listinfo/ovmsdev">http://lists.teslaclub.hk/mailman/listinfo/ovmsdev</a>
</pre>
</blockquote>
<br class="">
</div>
_______________________________________________<br class="">OvmsDev mailing list<br class=""><a href="mailto:OvmsDev@lists.teslaclub.hk" class="">OvmsDev@lists.teslaclub.hk</a><br class="">http://lists.teslaclub.hk/mailman/listinfo/ovmsdev<br class=""></div></blockquote></div><br class=""></div></body></html>