B4R Question 8266 RTC Memory/ Other information

RJB

Active Member
Licensed User
Longtime User
The 8266 uses it's RTC to time the DeepSleep function, but it also apparently has some memory associated with it (some information is available here ). This allows storage of data during deep sleep and is, presumably, not limited to the number of changes that EEPROM is.
Does anyone know how to use this in B4R?
Is there also other functionality available such as set/ reset/ read of the RTC itself? Is it where the millis/ micos come from?
Thanks for any help you can give
 

RJB

Active Member
Licensed User
Longtime User
Just found this hidden below the video! Does that help?

Code: https://github.com/SensorsIot/ESP8266...
SDK Documentation: https://espressif.com/en/support/down...

Calculator to calculate running time: http://battery-life.of-things.de/batt...

Supporting Material and Blog Page: http://www.sensorsiot.org
Github: https://www.github.com/sensorsiot
If you want to support the channel and buy from Banggood use this link to start your shopping: https://bit.ly/2jAQEf4 (no additional charges for you)
Official Wemos Store: http://s.click.aliexpress.com/e/jUzBiIq
https://www.facebook.com/SensorsIOT/
https://twitter.com/spiessa

Category
Science & Technology
Show less
 
Upvote 0

RJB

Active Member
Licensed User
Longtime User
Code is:
B4X:
#define RTCMEMORYSTART 65
#define RTCMEMORYLEN 127
extern "C" {
#include "user_interface.h" // this is for the RTC memory read/write functions
}
typedef struct {
int battery;
int other;
} rtcStore;
rtcStore rtcMem;
int i;
int buckets;
bool toggleFlag;
void setup() {
Serial.begin(115200);
Serial.println();
Serial.println("Start");
buckets = (sizeof(rtcMem) / 4);
if (buckets == 0) buckets = 1;
Serial.print("Buckets ");
Serial.println(buckets);
system_rtc_mem_read(64, &toggleFlag, 4);
Serial.print("toggle Flag ");
Serial.println(toggleFlag);
if (toggleFlag) {
Serial.println("Start Writing");
for (i = 0; i < RTCMEMORYLEN / buckets; i++) {
rtcMem.battery = i;
rtcMem.other = i * 11;
int rtcPos = RTCMEMORYSTART + i * buckets;
system_rtc_mem_write(rtcPos, &rtcMem, buckets * 4);
toggleFlag = false;
system_rtc_mem_write(64, &toggleFlag, 4);
Serial.print("i: ");
Serial.print(i);
Serial.print(" Position: ");
Serial.print(rtcPos);
Serial.print(", battery: ");
Serial.print(rtcMem.battery);
Serial.print(", other: ");
Serial.println(rtcMem.other);
yield();
}
Serial.println("Writing done");
}
else {
Serial.println("Start reading");
for (i = 0; i < RTCMEMORYLEN / buckets; i++) {
int rtcPos = RTCMEMORYSTART + i * buckets;
system_rtc_mem_read(rtcPos, &rtcMem, sizeof(rtcMem));
toggleFlag = true;
system_rtc_mem_write(64, &toggleFlag, 4);
Serial.print("i: ");
Serial.print(i);
Serial.print(" Position ");
Serial.print(rtcPos);
Serial.print(", battery: ");
Serial.print(rtcMem.battery);
Serial.print(", other: ");
Serial.println(rtcMem.other);
yield();
}
Serial.println("reading done");
for (i = 0; i < RTCMEMORYLEN / buckets; i++) {
rtcMem.battery = 0;
rtcMem.other = 0;
int rtcPos = RTCMEMORYSTART + i * buckets;
system_rtc_mem_write(rtcPos, &rtcMem, buckets * 4);
}
}
Serial.println("before sleep");
ESP.deepSleep(5000000, WAKE_RFCAL);
}
void loop() {}
 
Upvote 0

RJB

Active Member
Licensed User
Longtime User
Possibly every 5 to 10 seconds, hence not really suitable to use EEPROM. I'm assuming the RTC memory is static RAM so doesn't suffer from the 100,000 limit for writes that EEPROM does.
 
Upvote 0

Erel

B4X founder
Staff member
Licensed User
Longtime User
By default the EEPROM size is 1024 bytes. It can be changed by editing rEEPROM.cpp.

Lets say that you need to write 10 bytes. You can use the first two bytes to write the address and write the value in that address. The address can be changed once a day.
Built it correctly and it can run for years without reaching the limit.
 
Upvote 0

RJB

Active Member
Licensed User
Longtime User
I am using the EEPROM for other things, it is perfect for that as it doesn't change very often.
I'd just like to use the RTC memory for things that change very often. Is that not possible or very difficult or don't we have enough information to do it?
Is it not a good idea for some reason?
An example would be to save some information before going into deep sleep then retrieving it afterwards. It doesn't matter that it will be lost on power off. In fact that solves some of the problems that you get by trying to use EEPROM in that way, i.e. when you don't know if the device is re-starting from power off or from deep sleep.
I think the ability to use the RTC and it's memory would be a useful addition to B4R - if it is indeed possible?
Thanks
 
Upvote 0

RJB

Active Member
Licensed User
Longtime User
After several days reading tutorials, other examples of in-line c and trying every combination I can think of, I think I will have to give up and find another, less efficient, way of doing the job! Not being a C programmer I just don't understand the errors etc. - but then that's why I use B4X!
 
Upvote 0

RJB

Active Member
Licensed User
Longtime User
Yes that's true but then that's why B4X, Visual Studio etc. are so useful and popular. It's just these little problems that detract from that usefulness.
I can usually workout how to modify examples to do what I need in C, Java etc. not in this case.
It seems so simple in principle but …….
 
Upvote 0

RJB

Active Member
Licensed User
Longtime User
I decided to abandon b4r for the 'C' experimentation and use the Arduino IDE instead. It proved to be very easy to use and understand, with good error messages and help available. Using that I managed to take the above code from GitHub and modify/ check that it ran on the 8266.
I've now put it back into b4r as below and it seems to be writing/ reading. By commenting out lines then re-running it you can prove that the value is saved through the re-load. Next will be to modify it to what I need and then see if it retains data through deep sleep.

B4X:
Public Sub RTCWrite(WrVal As ULong)
 RunNative("rtc_Write", Null) ', WriteLong) 'WrVal)
 Log("Result: ", Result)
End Sub
#if C
#define RTCMEMORYSTART 65
#define RTCMEMORYLEN 127
#include "user_interface.h" // this is for the RTC memory read/write functions
typedef struct {
  int battery;
  int other;
} rtcStore;
rtcStore rtcMem;
bool toggleFlag;
int rtcPos = 65;
bool rtc_Write(B4R::Object* u){
Serial.begin(9600); //115200);
toggleFlag = false;
system_rtc_mem_write(64, &toggleFlag, 4);
yield();
system_rtc_mem_read(64, &toggleFlag, 4);
b4r_main::_result = toggleFlag;
yield();
system_rtc_mem_write(rtcPos, &rtcMem, 4);
yield();
system_rtc_mem_read(rtcPos, &rtcMem, 4);
yield();
}
#end if

As I've mentioned before I don't 'C' so any helpful comments would be welcome.
 
Upvote 0

RJB

Active Member
Licensed User
Longtime User
Some code to experiment with:
B4X:
Sub Process_Globals
 'These global variables will be declared once when the application starts.
 'Public variables can be accessed from all modules.
 Public Serial1 As Serial
 Public const rtcWr As Int = 1   'write to rtc memory
 Public const rtcRd As Int = 2   'read from rtc memory
 Public const rtcGetTime As Int = 3  'get RTC clock periods
 Public const rtcGetPeriod As Int = 4 'get RTC clock period
 Public Const DSleep As Int = 5
 Public varLocation As Int
 Public VarLong As Long
 Public rtcTimeLong As Long
 Public rtcPeriodLong As Long
 Dim esp As ESP8266
End Sub

Private Sub AppStart
 Serial1.Initialize(9600) '115200)
 Delay(2000)   'so that logs work!
 Log("AppStart")
 RTC(rtcRd,0,1)
 Log("Read: ", VarLong)
 VarLong = VarLong + 1
 RTC(rtcWr, VarLong, 1)
 Log("Written: ", VarLong)
 
 RTC(rtcGetPeriod, 0, 0)
 Log("Period: ", rtcPeriodLong)
 
 RTC(rtcGetTime, 0, 0)
 Log("get rtc time: ", rtcTimeLong)
' esp.restart    'rtc timer persists, rtc memory persists
 RTC(DSleep, 3000, 0) 'rtc timer resets, rtc memory persists
End Sub
'there are 128 x 4byte user memory locations for storage (at = 0 to 127)
'val holds the value to write or is ignored for the other 4 cases or is the deepsleep period in mS
'action is 0 - 3 for the 4 rtc functions available
Public Sub RTC(Action As Int, Val As ULong, At As ULong)
 varLocation = 64 + (At * 4)
 Select Action
  Case rtcWr
   If (varLocation < 64) Or (varLocation > 191) Then Return
   VarLong = Val
   RunNative("rtc_Write", Action)
  Case rtcRd
   If (varLocation < 64) Or (varLocation > 191) Then Return
   RunNative("rtc_Read", Action)
  Case rtcGetTime
   RunNative("rtc_GetTime", Action)
  Case rtcGetPeriod
   RunNative("rtc_GetPeriod", Action)
  Case DSleep
   RunNative("deepSleep", Val * 1000)
  Case Else
 End Select
End Sub
#if C
//#define RTCMEMORYSTART 64
//#define RTCMEMORYLEN 128
#include "user_interface.h" // this is for the RTC memory read/write functions
Long varLong;
ulong varlocation;
bool rtc_Write(B4R::Object* u){
   varLong = b4r_main::_varlong;
   varlocation = b4r_main::_varlocation;
   system_rtc_mem_write(varlocation, &varLong, sizeof(varLong));
   yield();
   }
bool rtc_Read(B4R::Object* u){
   varlocation = b4r_main::_varlocation;
   system_rtc_mem_read(varlocation, &varLong, sizeof(varLong));
   b4r_main::_varlong = varLong;
   yield();
   }
bool rtc_GetTime(B4R::Object* u){
   b4r_main::_rtctimelong = system_get_rtc_time();
   yield();
   }
bool rtc_GetPeriod(B4R::Object* u){ 
   b4r_main::_rtcperiodlong = system_rtc_clock_cali_proc();
   yield();
   }
void deepSleep(B4R::Object* o) {
     ESP.deepSleep(o->toULong());
   }
#end if

The use of variable to pass parameters doesn't seem very elegant so perhaps I need to look at that.
Some things I don't understand, like why the RTC is reset by deepsleep, but it does seem to work. Note that the memory read/ write will start from a random value at power on.
 
Upvote 0
Top