No announcement yet.

File_Mount fails (resolved - insufficient memory)

  • Filter
  • Time
  • Show
Clear All
new posts

  • File_Mount fails (resolved - insufficient memory)

    I am having a bizarre problem with file_Mount() failing. I know my uSD card is working because the musical scales demo works fine in loading .wav files.

    In my application shown below, the file_Mount() is the very first thing done in main(). As shown, the mount fails. But if you comment-out the call to beatHeart(), near the bottom of main(), then the mount will succeed. That is code that does not even get a chance to be called, and yet it's presence keeps the mount from working!

    This seems like it might be a compiler bug, unless I am missing something. Like a symbol table is overflowing it's bounds, or something. Can someone at 4D try this code and tell me what's going on? I am using R22 firmware.
    #platform "uLCD-32PT_GFX2"/************************************************** Filename: ECG.4dg* Created: 2010/12/19* Author: Greg Glenn* Description: ElectroCardiogram for uLCD-32PT***************************************************/#inherit "4DGL_16bitColours.fnc"#inherit "FONT4.FNT"/*************************************************************************************The AD799X ADC chips come in a version-0 and version-1, where the differenceis the LSB of the I2C address. See table in datasheet for I2C addresses. This codeis for the version-0 of the AD7995 chip**************************************************************************************/#CONSTADC_WRITE 0b01010000 // AD7995-0 is 0101000X, AD7995-1 is 0101001XADC_READ 0b01010001 //ADC_CONFIG 0b00010000 // channel 0 only, Reference=Vdd, SDA and SCL are FilteredADC_RESOLUTION 4096OFF_BUTTON_X 6 // Locations of buttonsOFF_BUTTON_Y 210MODE_BUTTON_X 80MODE_BUTTON_Y 210SCALE_BUTTON_X 160SCALE_BUTTON_Y 210PAUSE_BUTTON_X 260PAUSE_BUTTON_Y 210GRAPH_PLOT_COLOR YELLOW // ColorsGRAPH_BORDER_COLOR REDGRAPH_BACKGROUND_COLOR BLACKGRAPH_GRID_COLOR REDGRAPH_MIN_X 3 // Graph boundariesGRAPH_MIN_Y 11GRAPH_MAX_X 310GRAPH_MAX_Y 138GRAPH_Y_RANGE (GRAPH_MAX_Y - GRAPH_MIN_Y)MIDLINE_Y ((GRAPH_MAX_Y - GRAPH_MIN_Y)/2)+GRAPH_MIN_Y)SIGNAL_BUFFER_LENGTH 4096SAMPLE_INTERVAL 2 //milliseconds, 2ms = 500 samples/sec is minimum recommended rateSTARTR 760/SAMPLE_INTERVAL;ENDR STARTR + 20; // 0 to ENDT is approx 1 secondSTARTT 960/SAMPLE_INTERVAL; // to give pulse rate of 60 beats/minuteENDT STARTT + 20; // in simulation modeSCREENTIMEOUT 100000 // Screen saver timeout in MillisecondsRATE_SAMPLES 5CONT_MODE 1 // ModesRTRIG_MODE 2SIM_MODE 3RTRIG_REWIND 200 // Amount to rewind pointer on rtrigRTRIG_LOOK_AHEAD 20 // Points we check for R wave before graphing them#ENDvar state, x, y; // Used by touch code in mainvar simIndex, simt1; // Used by simulation signal generator functionvar mode; // Mode of displayvar r1,r2; // MSB, LSB from ADCvar timescale, timescaleIndex; // Timescale settingvar signalBuffer[SIGNAL_BUFFER_LENGTH]; // Buffer to store ADC datavar rateBuffer[RATE_SAMPLES]; // Buffer of timestamps for computing pulse ratevar dataInIndex, dataOutIndex; // Indices for ring buffervar rateIndex; // Index to rate buffervar graphX, graphY; // Current xy point to plotvar oldgraphX, oldgraphY; // Last point plottedvar rTriggerLevel; // Minimum amplitude that indicates R wavevar rTriggered; // In R wavevar paused; // 1= paused, 0=runningvar pulseRate; // Averaged pulse ratevar lastRIndex; // Buffer index of last R wave seenvar sdPresent; // MicroSD card is present and mountable/******************************************Main routineInitialize screen and dataOn each loop,Check for touch of any buttonTurn display off if button touchedChange mode if mode button touchedChange scale if scale button touchedPause/Unpause if pause button touchedGraph any buffered data*******************************************/func main()putstr("Mounting drive...\n");pause(1000);if (!file_Mount())while(!file_Mount())putstr("Drive not mounted...\n");pause(200);wendendifputstr("Mounted.\n");pause(20000);repeatscreenTimerCheck();touch_Set(TOUCH_ENABLE);state := touch_Get(TOUCH_STATUS); // get touchscreen statusx := touch_Get(TOUCH_GETX); // get touch x,yy := touch_Get(TOUCH_GETY);if(state == TOUCH_PRESSED) // if user touches screeninitScreenTimer(); // reset screensaver timerif ((x > OFF_BUTTON_X &amp;&amp; (x < OFF_BUTTON_X + 40))&amp;&amp; (y > OFF_BUTTON_Y &amp;&amp; y < OFF_BUTTON_Y + 30)) // Off button touched?gfx_Set(CONTRAST,0); // Turn Display offsys_Sleep(0); // Put processor to sleependifif (((x > MODE_BUTTON_X ) &amp;&amp; (x < MODE_BUTTON_X + 70))&amp;&amp; ((y > MODE_BUTTON_Y -10) &amp;&amp; y < MODE_BUTTON_Y + 30)) // Mode button touched?changeMode();endifif (((x > SCALE_BUTTON_X ) &amp;&amp; (x < (SCALE_BUTTON_X + 70)))&amp;&amp; ((y > SCALE_BUTTON_Y -10) &amp;&amp; y < (SCALE_BUTTON_Y + 30))) // Scale button touched?changeTimescale();endifif ((x > PAUSE_BUTTON_X &amp;&amp; (x < (PAUSE_BUTTON_X + 50)))&amp;&amp; ((y > PAUSE_BUTTON_Y -10) &amp;&amp; y < (PAUSE_BUTTON_Y + 30))) // Pause button touched?togglePause();endifwhile (touch_Get(TOUCH_STATUS) != TOUCH_RELEASED); // wait for touch releaseendifif(!paused &amp;&amp; (dataOutIndex != dataOutStopPoint()))graphBufferedData(); // Plot any unplotted databeatHeart();endifforeverendfunc/*********************************************GraphBufferedDataIf not paused, and we have notcaught up to the input buffer pointer yet,compute the proper increment of x-axisand draw a line from the previous pointto the current one.*********************************************/func graphBufferedData()var scaledY;oldgraphX := graphX;oldgraphY := graphY;graphY := GRAPH_MAX_Y - signalBuffer[dataOutIndex++];if(dataOutIndex == SIGNAL_BUFFER_LENGTH) // Wrap to beginningdataOutIndex := 0;endif//-------------------------------------------// Increment x for every timescale points on// the x axis//-------------------------------------------if(--timescaleIndex == 0)timescaleIndex := timescale * 2;graphX++;clearPreviousPoint();endifif(graphX >= GRAPH_MAX_X) //Increment time tick for X axisgraphX := GRAPH_MIN_X;clearPreviousPoint();oldgraphX := graphX; // Don't draw line at leftmost pointoldgraphY := graphY;endifgfx_Line(graphX,graphY,oldgraphX,oldgraphY,GRAPH_PLOT_COLOR); // Plotendfunc/********************************Determine point in data bufferto stop graphing so that thelookahead can work*********************************/func dataOutStopPoint()var margin;margin := dataInIndex - RTRIG_LOOK_AHEAD;if(margin >= 0)return margin;elsereturn (SIGNAL_BUFFER_LENGTH + margin);endifendfunc/***************************************Display a heart iconduring the time when the R waveis above the rTriggerLevelAlso record index in rate bufferand compute pulse rate usingaverage of 5 pulses****************************************/func beatHeart()var index, interval;if((r1 >= rTriggerLevel) &amp;&amp; !rTriggered)if(sdPresent &amp;&amp; file_Exists("ding.wav"))snd_Pitch(15874<<2);file_PlayWAV("ding.wav");endifgfx_CircleFilled(20,166,7,RED);gfx_CircleFilled(35,166,7,RED);gfx_CircleFilled(28,168,3,RED);gfx_TriangleFilled(14,170,42,170,28,188,RED);// Accumulate 5 R-to-R time intervals in the rateBuffer,// and compute average pulse rate each time another// R wave comes ininterval := dataOutIndex - lastRIndex;if(interval >= 0)rateBuffer[rateIndex] := interval;elserateBuffer[rateIndex] := (SIGNAL_BUFFER_LENGTH - lastRIndex) + dataOutIndex;endifrateIndex++;if(rateIndex >= RATE_SAMPLES)rateIndex := 0;endifrTriggered := 1;lastRIndex := dataOutIndex;index := 0;pulseRate := 0;while (index < RATE_SAMPLES)pulseRate := pulseRate + rateBuffer[index];index++;wend// Find beats per minute, and display itpulseRate := ((1000 / SAMPLE_INTERVAL) * 60 / (pulseRate / RATE_SAMPLES));showPulseRate();// Reset to beginning of graph and rewind buffer pointer some,// if we are in Rtrig mode, so the data leading up to the R// wave will be displayedif(mode == RTRIG_MODE)graphX := GRAPH_MAX_X;if((dataOutIndex - RTRIG_REWIND) >= 0)dataOutIndex := dataOutIndex - RTRIG_REWIND;elsedataOutIndex := dataOutIndex - RTRIG_REWIND + SIGNAL_BUFFER_LENGTH;endifendifendifif(r1 < rTriggerLevel)gfx_RectangleFilled(13,157,42,188, BLACK);rTriggered := 0;endifendfuncfunc showPulseRate()txt_Set(TEXT_COLOUR, CYAN);txt_MoveCursor(13,11);print(pulseRate," BPM ");endfunc/***********************************Restore background to howit was before a pointwas plotted************************************/func clearPreviousPoint()gfx_RectangleFilled(graphX,GRAPH_MIN_Y,graphX+2,GRAPH_MAX_Y, GRAPH_BACKGROUND_COLOR);endfunc/*********************************Get a real sample, or simulatedsample if mode = sim**********************************/func getSample()if(!paused)//if ((mode == RTRIG_MODE) || (mode == SIM_MODE))if (mode == SIM_MODE)getSimulatedSample();elsereadSample();endif// Assemble r1 and r2 into an integer value, then shift right to remove trailing 0's// from ADC, and to scale value for displaysignalBuffer[dataInIndex++] := ((r2 + ((r1 << 8))) >> 5);if(dataInIndex == SIGNAL_BUFFER_LENGTH)dataInIndex := 0; // Wrap around to beginningendifendifsys_SetTimer(TIMER1,SAMPLE_INTERVAL); //Reset timer for next tickendfuncfunc getSimulatedSample()simIndex++;r2 := 150;r1 := 4;if((simIndex >= STARTR) &amp;&amp; (simIndex < ENDR))r1 := 13;endifif((simIndex >= STARTT) &amp;&amp; (simIndex < ENDT))r1 := 6;endifif(simIndex == ENDT)r1 := 4;simIndex := 0;endifendfunc/**********************Configure the ADC chip***********************/func initADC()I2C_Open(I2C_MED); //Medium speed (slow or fast work also)I2C_Idle(); //Wait for bus IdleI2C_Start(); //StartI2C_Write(ADC_WRITE); //send control byte for writeI2C_Idle(); //Wait for bus IdleI2C_Write(ADC_CONFIG); //Send Config byteI2C_Stop();endfunc/**********************Pull a sample fromthe ADC chip***********************/func readSample()r1 := 0;r2 := 0;I2C_Idle(); //Wait for bus IdleI2C_Start(); //RestartI2C_Write(ADC_READ); //send control byte for ReadI2C_Idle(); //Wait for bus Idler1 := I2C_Read(); //Read DataI2C_Ack();r2 := I2C_Read();I2C_Nack(); //send Not AckI2C_Stop();endfunc/**********************Prepare the display***********************/func initScreen()gfx_Set(SCREEN_MODE,LANDSCAPE_R); // Remove this if you don't want landscapetxt_Set(FONT_SIZE, FONT1);txt_Set(TEXT_COLOUR, YELLOW);txt_Set(FONT_SIZE, FONT3);gfx_Set(BEVEL_WIDTH,2);gfx_Set(BEVEL_SHADOW,2);gfx_Cls();gfx_Button(UP, OFF_BUTTON_X, OFF_BUTTON_Y, CRIMSON, WHITE, FONT3, 1, 1, "OFF");gfx_Button(UP, MODE_BUTTON_X, MODE_BUTTON_Y, GREEN, WHITE, FONT3, 1, 1, " MODE ");gfx_Button(UP, SCALE_BUTTON_X, SCALE_BUTTON_Y, BLUE, WHITE, FONT3, 1, 1, "TIMESCALE");gfx_Button(UP, PAUSE_BUTTON_X, PAUSE_BUTTON_Y, GOLD, BLACK, FONT3, 1, 1, "PAUSE");initGraph();showTimescale();showMode();showPaused();endfunc/*************************************Prepare the graph part of thedisplay************************************/func initGraph()gfx_Rectangle(GRAPH_MIN_X-1,GRAPH_MIN_Y-1,GRAPH_MAX_X+4,GRAPH_MAX_Y+2,GRAPH_BORDER_COLOR);gfx_Rectangle(GRAPH_MIN_X-2,GRAPH_MIN_Y-2,GRAPH_MAX_X+5,GRAPH_MAX_Y+3,GRAPH_BORDER_COLOR);gfx_RectangleFilled(GRAPH_MIN_X,GRAPH_MIN_Y,GRAPH_MAX_X,GRAPH_MAX_Y,GRAPH_BACKGROUND_COLOR);graphX := GRAPH_MIN_X +1;graphY := GRAPH_MAX_Y -1;gfx_ObjectColour(GRAPH_PLOT_COLOR);sys_SetTimerEvent(TIMER1, getSample);sys_SetTimer(TIMER1,SAMPLE_INTERVAL);endfunc/***********************************initParametersSet up interval and timer eventInitialize variables************************************/func initParameters()dataInIndex := RTRIG_LOOK_AHEAD; // Setup indices for data ring bufferdataOutIndex := 0;paused := 0;mode := 3;timescale := 8;timescaleIndex := timescale * 2;simIndex := 0;r1 := 3;r2 := 0;rTriggerLevel := 9; // If r1 reaches this level, an R wave is indicatedendfunc/*************************************Cycle thru timescales available************************************/func changeTimescale()timescale--;if(timescale < 1)timescale := 8;endifshowTimescale();initGraph();endfuncfunc showTimescale()var gridindex;txt_Set(TEXT_COLOUR, YELLOW);txt_MoveCursor(16,24);print(timescale," ");/* Clear scale area, thenPrint scale below graphShort Tick every 10th second,Long tick every second,gfx_RectangleFilled(GRAPH_MIN_X,GRAPH_MAX_Y+1,GRAPH_MAX_X,GRAPH_MAX_Y+12,GRAPH_BACKGROUND_COLOR);gridindex := 0;repeatgridindex++;if(gridindex%(((1000/SAMPLE_INTERVAL))/(timescale *2)) == 0)gfx_Line(gridindex+GRAPH_MIN_X,GRAPH_MAX_Y+1,gridindex+GRAPH_MIN_X,GRAPH_MAX_Y+12,GRAPH_GRID_COLOR);endifif(gridindex%(((1000/SAMPLE_INTERVAL)/10)/(timescale *2)) == 0)gfx_Line(gridindex+GRAPH_MIN_X,GRAPH_MAX_Y+1,gridindex+GRAPH_MIN_X,GRAPH_MAX_Y+7,GRAPH_GRID_COLOR);endifuntil ((gridindex+GRAPH_MIN_X) > GRAPH_MAX_X);*/endfunc/**********************************Cycle thru the available modes1 = Continous2 = Trigger on R wave3 = Simulate***********************************/func changeMode()gfx_Button(DOWN, MODE_BUTTON_X, MODE_BUTTON_Y, GREEN, WHITE, FONT3, 1, 1, " MODE ");pause(200);gfx_Button(UP, MODE_BUTTON_X, MODE_BUTTON_Y, GREEN, WHITE, FONT3, 1, 1, " MODE ");txt_Set(TEXT_COLOUR, YELLOW);txt_Set(FONT_SIZE, FONT3);txt_Set(TEXT_OPACITY, OPAQUE);if(mode == 1)mode := 2;elseif(mode == 2)mode := 3;elseif(mode == 3)mode := 1;endifendifendifshowMode();initGraph();endfuncfunc showMode()txt_Set(TEXT_COLOUR, YELLOW);txt_MoveCursor(16,10);if(mode == RTRIG_MODE) print(" RTRIG ");if(mode == SIM_MODE) print(" SIM ");if(mode == CONT_MODE) print(" CONT ");endfunc/********************Toggle Pause button********************/func togglePause()if(!paused)paused := 1;elsepaused := 0;endifshowPaused();endfuncfunc showPaused()if(paused)gfx_Button(DOWN, PAUSE_BUTTON_X, PAUSE_BUTTON_Y, GOLD, BLACK, FONT3, 1, 1, " RUN ");elsegfx_Button(UP, PAUSE_BUTTON_X, PAUSE_BUTTON_Y, GOLD, BLACK, FONT3, 1, 1, "PAUSE");endifendfunc/*********************************************************Start screen saver if timer expires*********************************************************/func screenTimerCheck()if(sys_GetTimer(TIMER2) == 0)screenSaver();initScreenTimer();endifendfuncfunc initScreenTimer()sys_SetTimer(TIMER2,SCREENTIMEOUT);endfuncfunc screenSaver()var line, col;txt_Set(TEXT_COLOUR, CYAN);txt_Set(FONT_SIZE, FONT3);gfx_Cls();sys_SetTimer(TIMER1,2000);repeatstate := touch_Get(TOUCH_STATUS);if (state == TOUCH_PRESSED) break;if(sys_GetTimer(TIMER1) == 0)line := (ABS(RAND())/2000);col := (ABS(RAND())/2000) + 10;gfx_Cls();txt_MoveCursor(line,col);print("Touch me");sys_SetTimer(TIMER1,2000);endifforeverwhile (touch_Get(TOUCH_STATUS) != TOUCH_RELEASED);initScreen();endfunc

  • #2
    Hi mechg,
    basically what is happening is you are running out of memory.

    If you take a look in the aux file near the end, you will see:-


    Note that MEMSIZE is in words, so the app requires 8248 bytes for memory,
    and 5437 bytes for codespace so a total of 13685 so far.
    On top of this, the stack default size will add another 400 bytes, so just at this point, the app has already consumed just about everything - in fact, if you put these 2 lines at the start of main it will show you what is happening.

    print("MEM[] used = ", (&amp;sdPresent+2 - &amp;x)*2,"\n"); // show the 'gap' between your apps variables, giving the size in bytes which is MEMSIZE* 2
    print("max heap = ", mem_Heap(),"\n");

    You will see that the poor old heap only has 102 (or so) bytes left.
    the mounting of a file requires another 700 or so to kick off, but once mounted,
    most of this is released and only 38 bytes are actually retained, but the memory must be there for it else mount will fail.
    When you play a sound, the default buffer size is 2k, and another 700bytes or so is required for file buffers.

    Now, first thing to note, you are defining FONT4 at the beginning of your app, this
    does not appear to be used, so removing that line will give you a spare 3083 bytes
    which is probably just enough.

    But the biggest saving of all is by defining the program so it will run directly from FLASH, so add this line somewhere near the start of your app like this:-

    #inherit "4DGL_16bitColours.fnc"
    //#inherit "FONT4.FNT" // NOT USED

    Now download the app again from the Workshop and make sure destination is set to 'flash'

    Now running the app again you will see that there is a healthy 5658 bytes available in the heap.



    • #3

      Thank you so much for the thorough explanation. I guess my app has finally reached the point where I have to pay attention to my use of memory.