As it says in the title - my project is running out of ram for global variables. I can send a signal back to the Arduino to serve up data to local vars on page change, which works well except can see them pop into place. I would ideally like to send a page turn signal to the arduino, have the arduino send the values, then have the arduino set a var to 1 or something to signal that the data has been sent before revealing the page. Is this possible?
Hide the controls then make them visible?
Simply put the code in the routine which is sending the page turn signal:
Send data request for next page
Send varDataSent = 1
set varDataSent=0 in page xxx preinitialization
Hi guys, thanks for the responses - I am still having some trouble with this.
me21 - just as the nextion behaves when loading lots of global variables on a new page, I would like it to simply display the last page until everything is loaded properly and then “pop” into the new page.
I may be confused with this solution. Here is what I have:
- When a button on the nextion is pressed, it switches to a new page.
- In the preinitialization of that page, I have “printh 23 02 54 3E” (which is my trigger to send data to the nextion from the Arduino)
- On the arduino, when the trigger from step 2 is received, it sends over serial some values. I don’t want the preinitialization to continue until the nextion has all those values.
- At the end of the arduino instructions I have included as you said varDataSent = 1
- After Nextion receives varDataSent = 1, I want it to then display the page and go past preinitialization so that everything pops into place at the same time.
the instructions you gave me didnt seem to do that. Where do I put the following code? if(varDataSent=1)
The problem is that, if I have that code in the program.s - since the variables on the nextion are local, won’t it not write to them unless the page is in preinitialization?
In the button where you’re switching to another page. You populate the global variables on the next page before calling the code to change to the next page.
printh 23 02 54 3E
delay 10 (or loop until varDataSent changes value from 0 to 1)
In case you’re not already doing this: you can save a lot of RAM by using variables instead of on-screen objects like numbers, text boxes, etc. I explained the details over here: Updating fields before page is displayed - #5 by Max
Another trick I use to reduce memory footprint is to pack multiple values into one variable. F.ex. let’s assume you want to store the state of 10 dual state buttons. Here are three ways of doing it with increasing complexity and decreasing memory footprint:
- Make them global. 1-click solution and 10 * 24 = 240 bytes of RAM used.
- Store each state in a global variable (buttons remain local). Still pretty easy to load/save values. 10 * 4 = 40 bytes of RAM used.
- Store all states in 1 global variable. 1 * 4 = 4 bytes of RAM. Since each state can only be 0 or 1 you don’t need a full 32 bit variable, that can cover values from <-2000000000 to >2000000000. You only need 1 bit. That’s right, 1 global variable can store the state of up to 32 local buttons! Or in other words: you can store the state of all buttons you could possibly put on a page (255) in only 8 global variables, occupying 8 * 4 = 32 bytes of RAM.
While buttons are for sure the type of objects where you can save the most, the tricks work for many other components, too.
Edit: formatting fixed
Edit2: readability and typos
You are a wealth of information - thank you for pointing me in the right direction here (yourself as well, ELF!)
I did try to use local buttons attached to global variables that I created on the page, but the problem I ran into was that the state of the button would not update as the global variable was updated if the page was already loaded - is there a proper way to do this or a best practice that I am missing? Ideally, what I need to do is update the PCO and BCO (and sometimes text) of the buttons as they are pressed - currently I have the arduino doing this with commands. I tried writing some statements on the Nextion IDE but again once the page is loaded I can’t get things to update properly.
Also - would you be able to provide a short example of how to parse the states of those buttons from one single global variable? I understand how it works, but i’m not sure how to flesh it out properly and get it to update in real time.
The trick is, do not touch those global variables as far as possible. Let them do their magic in the background. if the page is already loaded, then simply update the buttons directly. The new state will automatically be stored to the global variables on page exit. Especially when you pack multiple values into one global variable this is a lot easier, too.
An example of how to load two numbers with 16 bit resolution from 1 global variable, and how to store 4 button states in another one can be found here: https://github.com/MMMZZZZ/Syntherrupter/blob/95e63a165aa0b0aaff50a823802cf4c302f6e164/Syntherrupter_Nextion/Source_as_Text/Lightsaber.txt#L147
In the page exit event is the code that saves them to the global variables: https://github.com/MMMZZZZ/Syntherrupter/blob/95e63a165aa0b0aaff50a823802cf4c302f6e164/Syntherrupter_Nextion/Source_as_Text/Lightsaber.txt#L222
(Source code as text generated from the Nextion file with this tool: https://unofficialnextion.com/t/convert-nextion-to-text/ )
This trick has one limitation though: It does not work if you have to modify something unrelated on another page. Now what does unrelated mean? Imagine you want to keep the colors of multiple textboxes on different pages identical. Then you simply use the same global variable for all those components instead of writing code to sync them. And magically you have less RAM usage and can stick with the easier code from above.
In case this is really not possible, then of course you have to directly modify the data in the global variables. And good coding practices say you shouldn’t write two different codes for doing the same thing, so it would be great if you could use that same code to update the values even while the page is loaded.
My solution would be to put the whole load/save code in the touch press and touch release event of a component that’s invisible. Then you can f.ex. load all states from the global variables with
click loadSave,0, and save all of them with
click loadSave,1. The only thing to remember is that you have to do those
click events at the very end of your preinit event or in the postinit event, because they force the screen to be updated. I currently have no good example of this - and not the time to write one. Hope it helps anyways.
One note about text: text is expensive; it needs lots of ram (1 Byte per character). Often you don’t have to display completely random texts but only switch between texts that are already known. in this case you can create local strings with those texts and assign them a number (string1, string2, string3). Then, in your global variable you only store the string number which only costs you 4 bytes or less - no matter how long your strings are. On page preinit of course, you load the right string into the component based on the number.
This keeps the whole string data inside of the local memory, and doesn’t occupy valuable memory on other pages. The value of the local strings is set in the Editor (so they will always have that value when the page loads).
If however it is a completely unknown string, there’s no such trick.
Edit (since this post isn‘t already long enough): I personally prefer to keep the whole GUI stuff running on the Nextion itself. Meaning I don‘t use the Arduino to transfer data from one page to another. Nextion runs the GUI, no more, no less. Arduino (or any other microcontroller) does the control stuff. Reading sensors, etc. This keeps the time consuming communication between both devices at a minimum. Nextion only talks to Arduino if the user changes settings, and Arduino only talks to Nextion if some monitoring needs to be updated.
Thanks for those great examples. My main issue is that my device is ALL about updating data from the Arduino so not much can be stored on the Nextion for reuse later as the data is constantly updated.
My other question would be how to reduce screen loading time - is that just a factor of having to load several global variables? Would for example, using local variables and serving the data from the Arduino on page load speed up the process? The issue with that I am having is that when I start using Variables (the ones at the bottom of the screen) and writing to / recalling from them, the responsiveness seems to slow down because I am writing to both onscreen variables and global vars simultaneously.
hmmm… if you continuously need to update the on-screen data anyways, then I’d suggest to not store anything on the Nextion screen at all. Let your Arduino send the data x times per second and it will be at most 1 second until the next update and for 1 second I don’t think you need to store and display outdated data.
On preinit you could send to the Arduino what page has just been opened. The Arduino then knows what values it has to update and does this. My goto solution for this would be to use the Arduino Taskscheduler library which allows you with a few lines of code to periodically (or not, if you want) execute whatever tasks.
If you absolutely want to prevent that anything is displayed before the Arduino sends its data on a page load event (and now we’re coming to your original question), you could write
vis 255,0 in your preinit event. It hides everything on the page (blank background) Your Arduino could send the opposite (
vis 255,1) once the update is done.
A trick to keep your (Arduino) code simpler: if you have a value that should be displayed on multiple pages, you can give it the same name on each of those pages. Then the same command on the arduino side can be used for all of those pages.
Yet another idea: If most pages share the same variables - and/or if you can create enough global variables to store everything that needs to be displayed - it could make sense to store all the data in global variables which are updated by the Arduino. This simplifies your Arduino code quite a bit because it doesn’t need to know about what page is currently loaded on the nextion.
Each page would have a timer, which runs twice as fast as the Arduino sends data (twice as fast? Yes, to prevent aliasing. If it runs at a similar update frequency, the effective update frequency will slowly oscillare. Faster updates… slower updates… etc. More generally this is known as nyquist sampling theorem). This timer will load the data from those global variables into the local page components. At this point you could use the packing techniques described above.
Hope this helps,