![]() |
Forum Index : Microcontroller and PC projects : MM+ E100 with "Not enough memory"
Page 1 of 5 ![]() ![]() |
|||||
Author | Message | ||||
Bowden_P Senior Member ![]() Joined: 20/03/2019 Location: United KingdomPosts: 162 |
Hi Everyone, I'm writing a large program with multiple Pages for the MM+ E100. To save time in the debug-and-download cycle, I am writing this 1 or 2 Pages at a time, and debugging them separately, before then adding them into the full program. Pre the latest 2-Page addition, the current program ran OK. Post addition, I now have a "Not enough memory" error. This error is occurring right at the beginning of the code, where I make a Comms Check between the E100 and its partner - an Explore 28 module. The newly added code has nothing to do with this initial check - nor would have been run at this point. Looking at memory :- Pre-addition after Comms Check :- Flash: 67K (69%) Program (2539 lines) 1K ( 1%) 1 Embedded C Routine 28K (30%) Free RAM: 41K (45%) 417 Variables 31K (33%) General 19K (22%) Free and Post-addition on error:- Flash: 76K (79%) Program (2958 lines) 1K ( 1%) 1 Embedded C Routine 19K (20%) Free RAM: 43K (47%) 470 Variables 42K (46%) General 6K ( 7%) Free Prior to this error, the E100 sends a "Comms Check" command to the E28, which is echoed back successfully. It appears that the error is in building the next message to send - a 25 random-character string. The error message is :- [1355] Tx_Str$="0"+Str$(t_msg_len%,2,0,"0")+t_msg_type$+t_msg_remain$+Space$(25-t_msg_len%) Error : Not enough memory Can anyone help me with identifying what memory is lacking here, as the manuals don't have this information. With best regards, Paul. Nothing so constant as change. |
||||
TassyJim![]() Guru ![]() Joined: 07/08/2011 Location: AustraliaPosts: 6212 |
Try breaking that line up into smaller bites to see which part is causing the error. It 'should' work as is but hard to diagnose with only the one line to go on. You could also put a MEMORY command in just before the faulting line. Jim VK7JH MMedit |
||||
Bowden_P Senior Member ![]() Joined: 20/03/2019 Location: United KingdomPosts: 162 |
Hi TassyJim, Thanks for your reply. The initial message "Comms Check" uses the error-ing line in my "Tx()" sub successfully. Inserting "Memory" immediately before the offending line :- For the "Comms Check" message :- Flash: 76K (79%) Program (2959 lines) 1K ( 1%) 1 Embedded C Routine 19K (20%) Free RAM: 42K (46%) 468 Variables 43K (47%) General 6K ( 7%) Free For the next (error) message :- Flash: 76K (79%) Program (2959 lines) 1K ( 1%) 1 Embedded C Routine 19K (20%) Free RAM: 43K (47%) 470 Variables 45K (49%) General 3K ( 4%) Free [1356] Tx_Str$="0"+Str$(t_msg_len%,2,0,"0")+t_msg_type$+t_msg_remain$+Space$(25-t_msg_len%) Error : Not enough memory And back at the command prompt :- > memory Flash: 76K (79%) Program (2959 lines) 1K ( 1%) 1 Embedded C Routine 19K (20%) Free RAM: 43K (47%) 470 Variables 42K (46%) General 6K ( 7%) Free > Splitting the error-ing line such as :- Tx_Str$="0"+str$(t_msg_len%,2,0,"0")+t_msg_type$ Tx_Str$=Tx_Str$+t_msg_remain$+space$(25-t_msg_len%) or as :- Tx_Str$="0" Tx_Str$=Tx_Str$+str$(t_msg_len%,2,0,"0") Tx_Str$=Tx_Str$+t_msg_type$ Tx_Str$=Tx_Str$+t_msg_remain$ Tx_Str$=Tx_Str$+space$(25-t_msg_len%) The pre-addition program works fine with these mods. The post-addition version woun't even run the initial "Comms Check" message now, with messages scrambled. I'm wondering, if with free RAM at 3K, this simply isn't enough for the interpreter to function ? ( I imagine its demands on RAM are quite dynamic as it processes program lines, especially dealing with strings.) With regards, Paul. Nothing so constant as change. |
||||
disco4now![]() Guru ![]() Joined: 18/12/2014 Location: AustraliaPosts: 966 |
I think you have it. It does need some RAM to work with while interpreting the code. I think you will need to try to free up some RAM in your code. Putting strings into an array so you can set the length less than 255 can help. Latest F4 Latest H7 FotS |
||||
Bowden_P Senior Member ![]() Joined: 20/03/2019 Location: United KingdomPosts: 162 |
Hi disco4now, Thanks for the array suggestion. I wondered about that one too, and will have to seriously work out how to economize on RAM usage. The problem I see with putting variables into string arrays is losing the meaningful names for them! ( i.e Tx_Str$ replaced by Str_Array$(17) or something.) It's a real shame that the LENGTH option doesn't apply to single string variables. I would use that a lot if it did. Would that be possible as an enhancement to MMBasic ? Another option I thought of is to use DIM and ERASE where a variable is only needed in a section of code. At the moment almost all of my variables are declared at start-up. I use a fair number of LOCAL vars in subs, but that might benefit from expanding too. My ideal solution would be an MM+ E100 with the MM Extreme chip on board. I use both CLICK sockets in my project, the 5" touch screen and micro SD socket, so the Backpack format of the E100 suits me very well. I wonder - is anyone considering this as another MM standard ? With regards, Paul. Nothing so constant as change. |
||||
Mixtel90![]() Guru ![]() Joined: 05/10/2019 Location: United KingdomPosts: 7471 |
Always use the LENGTH option when dimensioning strings and keep them as small as practicable, otherwise they will all be 256 bytes long. This is especially true with string arrays - they can guzzle memory. Line 1355 will need enough space for each individual portion of the RHS plus the sum of them to execute. That might be adding up to more than you have available. Can you use some FUNCTIONs with local variables to get rid of some of the complexity? That would force some of the variables to be reused. You can still maintain values as STATIC for subsequent calls, not everything has to be global. Mick Zilog Inside! nascom.info for Nascom & Gemini Preliminary MMBasic docs & my PCB designs |
||||
Mixtel90![]() Guru ![]() Joined: 05/10/2019 Location: United KingdomPosts: 7471 |
DIM a$ LENGTH n is valid. It doesn't have to be an array. I always DIM k$ LENGTH 1 for use in INKEY$ loops. :) It's not worth using LENGTH on a single string variable unless the length is less than 16 bytes as you won't save memory. Mick Zilog Inside! nascom.info for Nascom & Gemini Preliminary MMBasic docs & my PCB designs |
||||
Bowden_P Senior Member ![]() Joined: 20/03/2019 Location: United KingdomPosts: 162 |
Hi Mixtel90, Yes, the LENGTH option use is stressed in the "Getting Started" manual by Geoff, and I have used it for string arrays. Could you expand on your suggestion of using FUNCTIONs ? I have not used them to date, and would welcome some guidance on how they might apply here, especially on how they might reduce RAM usage! I have used SUBs with arguments however, and found the passed-by-reference feature quite useful. With regards, Paul. Nothing so constant as change. |
||||
disco4now![]() Guru ![]() Joined: 18/12/2014 Location: AustraliaPosts: 966 |
Are you programing offline with MMEdit or are you using the MMBasic editor. If using MMEdit then the #REPLACE directive from here might help to use string arrays and keep it readable. eg. #REPLACE TX_STR$ SA$(17) #REPLACE RX_STR$ SA$(18) Latest F4 Latest H7 FotS |
||||
lizby Guru ![]() Joined: 17/05/2016 Location: United StatesPosts: 3299 |
It's valid as syntax, but it has no effect on memory allotment except on arrays. Consider: Dim string a length 1 Dim string b length 1 Dim string c length 1 Dim string d length 1 Dim string e length 1 Dim string f length 1 Dim string g length 1 Dim string h length 1 Dim string i length 1 Dim string j length 1 Dim string k length 1 Dim string l length 1 Dim string m length 1 Dim string n length 1 Dim string o length 1 Dim string p length 1 Dim string q length 1 Dim string r length 1 Dim string s length 1 Dim string t length 1 Dim string u length 1 Dim string v length 1 Dim string w length 1 Dim string x length 1 Dim string y length 1 Dim string z length 1 memory RAM usage: 8K ( 7%) 26 Variables Dim string a length 255 Dim string b length 255 Dim string c length 255 Dim string d length 255 Dim string e length 255 Dim string f length 255 Dim string g length 255 Dim string h length 255 Dim string i length 255 Dim string j length 255 Dim string k length 255 Dim string l length 255 Dim string m length 255 Dim string n length 255 Dim string o length 255 Dim string p length 255 Dim string q length 255 Dim string r length 255 Dim string s length 255 Dim string t length 255 Dim string u length 255 Dim string v length 255 Dim string w length 255 Dim string x length 255 Dim string y length 255 Dim string z length 255 memory RAM usage the same: 8K ( 7%) 26 Variables Dim string a(26) length 1 Memory RAM usage: 1K ( 1%) 1 Variable I don't have an E100, so this is on an F4, but I think behavior is the same across micromites. ~ Edited 2021-04-27 09:13 by lizby PicoMite, Armmite F4, SensorKits, MMBasic Hardware, Games, etc. on fruitoftheshed |
||||
Bowden_P Senior Member ![]() Joined: 20/03/2019 Location: United KingdomPosts: 162 |
I have just done a similar experiment on my E100, with the same conclusion, unfortunately. i.e. As per the manual the LENGTH option doesn't reduce RAM usage for single string variables, only string arrays. With regards, Paul. Nothing so constant as change. |
||||
Mixtel90![]() Guru ![]() Joined: 05/10/2019 Location: United KingdomPosts: 7471 |
Interesting... The manuals for both the Micromite and the CMM2 appear (to me anyway) to suggest that LENGTH works on simple strings. I must admit I hadn't actually tested it. Although it looks messy you could still set up a single dimension length-limited array for short strings though. It might be worth it to save memory. Another approach is to poke into strings. It needs some thought, but it can work really well. Providing you aren't going to output the string or process it in any way (only use it for storage) you can poke it with all characters - even invalid ones. :) My point with using Functions is that, unlike Subs, they can return a value. Function add$(a$,b$,c$) add$ = a$+b$+c$ end function a$, b$ & c$ act like variables but are local to the function. a$ = add$("A","B","C") will set the global variable a$ to "ABC" All the memory space used by a$, b$ and c$ was cleared when the function closed, without affecting any global variables of those names. Calling the same function again with b$ = add$(str$(1),str$(2),str$(3)) will make b$="123" and release all the used memory again, including that used by the string conversions. The less global variables you have the better really. While not in use they simply sit there using up RAM. Mick Zilog Inside! nascom.info for Nascom & Gemini Preliminary MMBasic docs & my PCB designs |
||||
Mixtel90![]() Guru ![]() Joined: 05/10/2019 Location: United KingdomPosts: 7471 |
Ah - found the bit about LENGTH not working with non-array strings in the Micromite manual. Sorry! :) It does work on the CMM2 but doesn't save memory unless the length is less than 16 bytes, in which case it improves performance too. Mick Zilog Inside! nascom.info for Nascom & Gemini Preliminary MMBasic docs & my PCB designs |
||||
lizby Guru ![]() Joined: 17/05/2016 Location: United StatesPosts: 3299 |
Re gaining more memory, if you have a lot of flags (1-bit variables which will occupy 8 bytes on the micromite (maybe 4 bytes on some of them)), you can save space using Captain Boing's Fruit of the Shed bit manipulation routines. They don't save any execution time, and generally aren't worth the trouble if you have enough memory, but if you have 9 flag variables, you could save 2K by using them (with 64-bit integers). If you have 17 of them, you could save 4K. ~ Edited 2021-04-27 21:27 by lizby PicoMite, Armmite F4, SensorKits, MMBasic Hardware, Games, etc. on fruitoftheshed |
||||
Bowden_P Senior Member ![]() Joined: 20/03/2019 Location: United KingdomPosts: 162 |
Hi disco4now Mixtel90 and lizby, Thanks for all your posts. Yes disco4now, I use MMEdit almost exclusively for program preparation, so the #REPLACE feature looks to be very useful for me. Keeping the code readable in the PC environment is a must, but losing some readability if I use the MMBasic editor will be worth it - I have put lots of time into this project, and don't want to leave it incomplete now. Mixtel90 - I'll have to check if FUNCTION usage can help too. Thanks for the examples. The flag manipulation coding is interesting, lizby. I have 67 flags used in 380 odd places and know the RAM they are using is out of proportion to the data stored! I will look at Captain Boing's code for that. I don't quite follow your saving figures however - 9 flag vars will use 72 bytes, 17 - 136 bytes. I guess you save where the name is concerned! Time for some study !! In the past I have cut down name lengths with beneficial effect on Flash usage, but till now left the "_" characters in. i.e t_msg_len%,t_msg_type%, which I find aids readability. Perhaps time to consider removing these, especially with Globals, where I capitalize the first letters. i.e Tx_Str$ to TxStr$. I use all lower case for LOCALs, so this scheme is more awkward there. Usage must run into several thousands ! With all compromises, gains in one place result in losses elsewhere ! In case you were wondering what this "project" is - its a Thrust Meter for measuring the performance of motors for model aircraft, be they electric, I.C. or turbine, but primarily electric. With regards, Paul. Edited 2021-04-28 07:00 by Bowden_P Nothing so constant as change. |
||||
lizby Guru ![]() Joined: 17/05/2016 Location: United StatesPosts: 3299 |
Ah, you're right--I had the 256-bytes per string variable stuck in my mind. PicoMite, Armmite F4, SensorKits, MMBasic Hardware, Games, etc. on fruitoftheshed |
||||
Mixtel90![]() Guru ![]() Joined: 05/10/2019 Location: United KingdomPosts: 7471 |
The actual usable length of a string is 255 bytes. There is one byte allocated to storing the string length. If you are prepared to do some jiggery pokery it's quite possible to use every bit of a string as a flag. Even if you use 1 byte per flag (easy if you poke strings) that's 255 flags stored in one string. a$="" is just a simple 256-byte string you can do things like poke VAR a$,100,1 to set the 100th byte of a$ to 1 p=peek(VAR a$,100) will return the value of the 100th byte Variable names affect how fast your code runs! MMBasic scans the name from the left character (I think it's in groups of 2 characters - Peter did mention it somewhere), so it's not good to use something like screen01 and screen02 as variables, it's faster to use sc1screen and sc2screen as it requires less searching to find them. Mick Zilog Inside! nascom.info for Nascom & Gemini Preliminary MMBasic docs & my PCB designs |
||||
thwill![]() Guru ![]() Joined: 16/09/2019 Location: United KingdomPosts: 4245 |
You can also use INTEGER arrays (or FLOATs if that floats your boat), each element of the former being 8 bytes. Option Base 0 Dim a%((200 \ 8 ) - 1) ' Array of 200 bytes Poke Var a%,100,1 ' Set the 100th byte of a% to 1 p = Peek(Var a%, 100) ' Return the value of the 100th byte I believe this is no longer the case. As mentioned by Peter earlier in this thread MMBasic on the CMM2 uses hash lookup of variable and function/subroutine names. Best wishes, Tom MMBasic for Linux, Game*Mite, CMM2 Welcome Tape, Creaky old text adventures |
||||
matherp Guru ![]() Joined: 11/12/2012 Location: United KingdomPosts: 10008 |
Every variable on a Micromite takes a minimum of 59 bytes for the variable descriptor irrespective of the length of the name. String variables (whether simple or arrays) take a minimum of 315 bytes |
||||
Bowden_P Senior Member ![]() Joined: 20/03/2019 Location: United KingdomPosts: 162 |
Ouch! Peter - that's a revelation on RAM usage! I'm doing my best to follow the discussion on the search for variable names :- Doesn't the interpreter have to match ALL the characters of a variable to ensure accuracy, so the exact order of differences woun't affect finding it ? Apologies if I'm showing my ignorance ! Paul. Nothing so constant as change. |
||||
Page 1 of 5 ![]() ![]() |
![]() |
![]() |
The Back Shed's forum code is written, and hosted, in Australia. | © JAQ Software 2025 |